CsQuery – JQuery for .NET

I’m currently working on a personal use utility application which requires some web scraping to extract data (from HTML) which can be locally processed by the application. Getting the raw HTML was straightforward enough using the HttpWebRequest and HttpWebResponse classes in the System.Net namespace.

I then reached the point where I had some raw HTML in a string that I needed to parse. After doing a quick search I found CsQuery (available as a NuGet package) which is an open source JQuery port for .NET. I was able to easily extract the data I required from the HTML using the familiar JQuery-like selectors. There is an example code snippet below which shows just how easy it is to use CsQuery.

var html = new StringBuilder();
html.Append(“<html><body>”);
html.Append(“<h1>Hello, world!</h1>”);
html.Append(“<p class=’intro’>This program is using CsQuery.</p>”);
html.Append(“<p id=’author’>CsQuery is a library written by James Treworgy.</p>”);
html.Append(“</body></html>”);var dom = CsQuery.CQ.Create(html.ToString());

// Get the inner text of an element by element name selector
Console.WriteLine(dom[“h1”].Text());

// Get the inner text of an element by class name selector
Console.WriteLine(dom[“.intro”].Text());

// Get the inner text of an element by id selector
Console.WriteLine(dom[“#author”].Text());

// Add a class to an element
dom[“h1”].AddClass(“title”);

// Update the title text using new class in selector
dom[“.title”].Text(“CSQuery – a JQuery port for .NET”);

// Now retrieve the new title by a class selector
Console.WriteLine(dom[“.title”].Text());

// Pause console
Console.ReadLine();

 

CSharp – Zip Compression and Decompression .NET 4 and Earlier

Quick post about a useful third-party zip compression library if you’re working in .NET framework version 4 or earlier.

I had been working on a SQL Server Integration Services (SSIS) package. One of the steps in the package is to decompress a set of zip archives. Unfortunately, .NET script tasks in the SSIS package can only target .NET framework version 4 and earlier. This means that I couldn’t make use of the new zip compression classes introduced in .NET 4.5 (see System.IO.Compression).

Fortunately though, there are a handful of open source .NET zip libraries available. The one I opted for is called DotNetZip. DotNetZip has an intuitive API and is working well with a large number of files (I am decompressing approximately 15,000 archives). The library is available as a NuGet package. The two snippets below show just how easy it is to compress and decompress files using zip.

To compress a file into a zip archive:

using (var zipFile = new ZipFile())
{
// The empty string parameter ensures the file is archived to the 
// root of the archive
zipFile.AddFile(@“C:\Test\Data.txt”string.Empty);
zipFile.Save(@“C:\Test\Data.zip”);
}

To decompress files out of a zip archive:

using (var zipFile = new ZipFile(@“C:\Test\Data.zip”))
{
zipFile.ExtractAll(@“C:\Test\Output”);
}

Csharp How To: Start a Program/Process

To start a program in C#, you can use the Process class. The Process class has a static method called Start which accepts a filename as a parameter. The example below shows how easy it is to start Microsoft Notepad from a C# application. Remember to include the “using System.Diagnostics;” directive at the top.

const string ProgramPath = “Notepad”;

Process.Start(ProgramPath);

Note that if you need to start a program which accepts command line arguments, then you can use an overload of the Start method which accepts a ProcessStartInfo object. The following snippet shows how to open a file within notepad from your C# application.

const string ProgramPath = “Notepad”;

Process.Start(new ProcessStartInfo
{
FileName = ProgramPath,
Arguments = @”C:\WriteTest.txt”
}
);

Csharp CSV Library and HTTP Handlers

A colleague and I was recently looking at some old ASP.NET WebForms code which generated a potentially large CSV string and returned it in a response to a HTTP request. The original code was placed in a standard ASP.NET WebForms page in the OnLoad event handler. As the code was working with the HttpResponse object and writing the CSV directly to the HTTP output stream, we determined that this code was better placed in a HTTP Handler. The primary advantage of using a HTTP handler to generate the file is that we can bypass the unnecessary ASP.NET WebForms page life cycle.

The existing code was using a StringBuilder to generate the CSV string in the page OnLoad event handler. As you may imagine, this looked messy and was a pain to maintain. To abstract the CSV string creation logic, my colleague introduced me to a useful CSV library called LINQ to CSV. The project page link for this library is here and the library is available as a NuGet package.

The LINQ to CSV library enabled us to decorate some properties in a model class with attributes that specify how to output the property in CSV form. The example below (from the library project page) shows how to apply the attributes:

public class Product
{
[CsvColumn(Name = “ProductName”, FieldIndex = 1)]
public string Name { get; set; }
[CsvColumn(FieldIndex = 2, OutputFormat = “dd MMM HH:mm:ss”)]
public DateTime LaunchDate { get; set; }
[CsvColumn(FieldIndex = 3, CanBeNull = false, OutputFormat = “C”)]
public decimal Price { get; set; }
[CsvColumn(FieldIndex = 4)]
public string Country { get; set; }
[CsvColumn(FieldIndex = 5)]
public string Description { get; set; }
}
Once your model class is decorated, you can then use other classes of the library to generate a CSV representation of a collection containing your model instances. This representation can be output to disk as demonstrated in the code example below:

IList products = new List();
products.Add(
new Product
{
Name = “Samung Galaxy S6”,
LaunchDate = DateTime.Today,
Price = 500,
Country = “United Kingdom”,
Description = “This is a Samsung phone product”
}
);

products.Add(
new Product
{
Name = “Apple iPhone 5”,
LaunchDate = DateTime.Today,
Price = 600,
Country = “United States”,
Description = “This is an Apple phone product”
}
);

CsvFileDescription inputFileDescription = new CsvFileDescription();
inputFileDescription.SeparatorChar = ‘,’;
inputFileDescription.FirstLineHasColumnNames = true;

CsvContext csvContext = new CsvContext();
csvContext.Write(products, @”C:\Products.csv”);

Usefully, the CsvContext class of the library also supports an overload to the Write method which accepts a TextWriter stream. Passing a TextWriter stream to this overload results in the library outputing the CSV representation to your stream rather than a file on disk. In our case, we used a StreamWriter that wrote to a MemoryStream. Once the CSV file content was in the MemoryStream instance, we sent the stream contents in the HTTP response from the HTTP handler. The full HTTP handler code is below (using the example product data).

public class ProductsExportHandler : IHttpHandler
{
public bool IsReusable { get { return true; } }

public void ProcessRequest(HttpContext context)
{
context.Response.AddHeader(
“content-disposition”,
“attachment;filename=BulkExport.csv”
);
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.ContentType = “application/vnd.text”;

IList products = new List();
// Add products…

var inputFileDescription = new CsvFileDescription();
inputFileDescription.SeparatorChar = ‘,’;
inputFileDescription.FirstLineHasColumnNames = true;

using (var memoryStream = new MemoryStream())
{
using (var streamWriter = new StreamWriter(memoryStream))
{
var csvContext = new CsvContext();
csvContext.Write(products, streamWriter);

streamWriter.Flush();

context.Response.BinaryWrite(memoryStream.GetBuffer());
}
}
}
}

Azure App Service – Forcefully redirecting from HTTP to HTTPS the easy way!

The easiest, non techie way is to add the ‘Redirect HTTP to HTTPS’ Extension kindly created by Greg Hogan (https://github.com/gregjhogan)

In the Azure Portal, select ‘Extensions’ in the App Service blade

azure-redirect-1

Add a new Extension by clicking on the ‘+Add’ button at the top
Select the ‘Redirect HTTP to HTTPS’ extension from the list given.

azure-redirect-2

Agree to the T&C’s
Wait till it’s installed and then restart the service (which you can find in the ‘Overview’)

After this when you access the website with http or without http/https, it will automatically redirect to https.

Dynamics CRM, set status of activity as Complete/Open using CSharp

In dynamics CRM, Task, phonecalls or any activity can be marked as complete which indicate its status as done.

To programatically, do it from C#, below code is required. Lets first make a generic entity model to be used.

1
2
3
4
5
6
7
8
9
    public class ActivityStatusInputEntity
    {
        public string Email { get; set; }
        public string Password { get; set; }
        public string ActivityId { get; set; }
        public string ActivityType{get;set;} //task, phonecall, meeting ..
        public int StatusCode { get; set; } // 5 if its a tasks, 2 if its a call, 3 if its a meeting
        public int StateCode { get; set; } // 0 to set it as open activity, 1 to make it Completed
    }

StatusCode and StateCode are the major key points here. As we cannot update these fields directly into the entity, we can do this with the SetStateRequest class.

StatusCode: 5 if its a tasks, 2 if its a call, 3 if its a meeting
StateCode: 0 to set it as open activity, 1 to make it Completed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
public Response UpdateTaskStatus(ActivityStatusInputEntity activityStatusEntity)
        {
            try
            {
                var crmService = GetCRMService(activityStatusEntity.Email, activityStatusEntity.Password);
                SetStateRequest setStateRequest = new SetStateRequest();
 
                // In my case i'm updating Task Activity
                setStateRequest.EntityMoniker = new EntityReference(activityStatusEntity.ActivityType, new Guid(activityStatusEntity.ActivityId));
 
                // Set the State and Status OptionSet Values.
                setStateRequest.State = new OptionSetValue(taskStatusEntity.StateCode);
                setStateRequest.Status = new OptionSetValue(taskStatusEntity.StatusCode);
 
                // Execute the Response
                SetStateResponse setStateResponse = (SetStateResponse) crmService.Execute(setStateRequest);
                return new Response() {Message = "success"};
            }
            catch (Exception err)
            {
                return new Response() {Message = "failure"};
            }
 
        }

This way we can set status of activities to either complete, or reopen an activity for editing programatically in C#.