Creating a .cab file with C#

.NET does not have any classes for creating cabinet files out-of-box, so today I had to look what else is available out there. There are a couple of solutions I found for creating a .cab file from the .NET code. The one that actually worked for me was a library developed by Microsoft(!) as part of their Windows Installer XML (WiX) toolset. This toolset is distributed with a bunch of dlls as part of its SDK. The library that allows to create cabinet files is called Microsoft.Deployment.Compression.Cab and located under <WIX_Installation_Folder>\SDK.

In your project you need to add a reference to the Microsoft.Deployment.Compression.Cab.dll and to Microsoft.Deployment.Compression.dll (located under the same folder and has some base classes for types defined in the Microsoft.Deployment.Compression.Cab).

After doing this you can add files to a cabinet file from .NET with just a couple of line of code:

using Microsoft.Deployment.Compression.Cab;
//create a instance of Microsoft.Deployment.Compression.Cab.CabInfo
//which provides file-based operations on the cabinet file
CabInfo cab = new CabInfo(@"C:\Cabinet1.cab");

//create a list with files and add them to a cab file
List<string> filesToArchive = new List<string>() { @"C:\file1", @"C:\file2" };
cab.PackFiles(null, filesToArchive, null);
            

//add a folder (including subdirectories) to another cab file with a maximum compression level
cab = new CabInfo(@"C:\Cabinet2.cab");
cab.Pack(@"C:\folder", true, Microsoft.Deployment.Compression.CompressionLevel.Max, null);

//unpack a cab file into C:\Unpacked folder
cab.Unpack(@"C:\Unpacked");

The library has an MSDN style help file located under <WIX_Installation_Folder>\doc\DTFAPI.chm.

Another dll that also comes with WiX toolset SDK is Microsoft.Deployment.Compression.Zip.dll that provides similar functionality for packing and unpacking zip files.

Catching local SOAP traffic with Fiddler

Fiddler is a great tool for testing and debugging web services. It logs and analyze all HTTP traffic between your machine and the Internet. I think it could be extremely beneficial to see how data is actually being serialized and what exactly is being sent to/from a web-service or application.

When it comes to catching a local traffic you have to do some tweaks, since .NET tries to avoid any proxies when it sends local requests. I had no problem catching local REST traffic by simply changing web-service address from http://localhost:[port]/… to http://ipv4.fiddler:[port]/… However when I tried to see a local SOAP traffic this simple address change did not bring any result and the SOAP messages were still not logged.

I had to spend some time and try multiple ways to fix this issue, starting from modifying a web.config to explicitly specify a proxy and ending with modifying a localhost value in /etc/hosts. Here are the steps that actually worked for me:

1. Modified client’s web-service address from “localhost” to “localhost. (I think it is better then changing it to the actual machine name (makes client configuration machine-dependent) and definitely better than ipv4.fiddler (cannot work without fiddler proxy turned on)).

2. Turned off listening on to the IPv6 adapter: Tools => Fiddler Options… => General tab => Enable IPv6 (if available) [uncheck]:image

These two steps allowed me to successfully see HTTP traffic to/from a web service hosted on a local ASP.NET development server (Cassini).

Dynamically changing HTML form action using jQuery

In order to test a RESTful service I’m currently working on I’ve created a simple HTML page with a bunch of forms. These forms generate various POST/GET requests to my REST service API methods, so I can manually test the service during a development process. One issue I faced was that the action attribute of HTML form element is static while I need to modify it dynamically based on user’s input (i.e. so I can send a GET requests to a URL like http://www.myrestfulservice.com/item/{itemID} where itemID is entered to the form by a user). JavaScript comes to mind.

So here is how this could easily be done with jQuery:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript" src='http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js'></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#getForm :submit").click(function() {
                var item = $(":input#itemId").val();
                $("#getForm").attr("action", "http://www.myrestfulservice.com/" + item);
            });
        });
    </script>
</head>
<body>
    <p>
        Enter item ID get:
        <input type="text" size="50" id="itemId" />
    </p>
    <form id="getForm" method="get" action="">
        <input type="submit" value="Get Item" />
    </form>
</body>
</html>

Getting Database column length with LINQ to Entities

During the work with ADO.Net Entity Framework sometimes you need to know a metadata for a database you’re working with such as a nchar/nvarchar column max length. Trying to update a DB column using LINQ to Entities with a string greater than the column max length leads to an SqlException (e.g. System.Data.SqlClient.SqlException: String or binary data would be truncated); therefore you need to check that your data does not exceed DB column boundaries manually. LINQ won't do this for you on a run-time.

If you don't want to have all your Entity Model metadata hardcoded, you need to get it on a run-time. Here is described how you can do this with LINQ to SQL.

Unfortunately this approach seems not to work for Entities Model. In order to do this for Entities you would need to query MetadataWorkSpace class and get a conceptual (CSpace) metadata for your Entity:

public static int GetMaxLength(Type entityType, string columnName)
{
    int result = 0;

    using (myEntities context = new myEntities())
    {
        var queryResult = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)    //getting conceptual entity metadata
                          where meta.BuiltInTypeKind == BuiltInTypeKind.EntityType
                                && (meta as EntityType).Name == entityType.Name    //selecting desired entity by name
                          from property in (meta as EntityType).Properties
                          where property.Name == columnName    //selecting an entity property that matches the column name
                                && (property.TypeUsage.EdmType.Name == "String")            
                          select property.TypeUsage.Facets["MaxLength"].Value;              

        if (queryResult.Count() > 0)
        {
            result = Convert.ToInt32(queryResult.First());
        }
    }
    return result;
}

When you call this method, just pass a type of your entity e.g.

GetMaxLength(typeof(myEntity), "myColumnName");