August 2003 - Posts

Encrypted server control licensing? Naahh...

Note: this entry has moved.

I'd think more than twice before implementing the Encrypted Licence Scheme proposed by Nikhil Kotari. He's proposing to embed the bytes of the key in the assembly itself, and use that as the encryption (for the generator) and decryption (at run-time).
Any decent programmer knows that dumping the IL code with ILDASM will easily expose those bytes as follows (even in Release mode compilation):

.data D_00002408 = bytearray (
                 35 46 42 32 38 31 46 36)                         // 5FB281F6

Now you can write a trivial console app to hack the expiration limit proposed in the same document, for example:

[STAThread]
static void Main(string[] args)
{
  byte[] encryptionKeyBytes = ASCIIEncoding.ASCII.GetBytes("5FB281F6");
  string license;

  DESCryptoServiceProvider des = new DESCryptoServiceProvider();
  des.Key = encryptionKeyBytes;
  des.IV = encryptionKeyBytes;

  // Read the encrypted file.
  ICryptoTransform desDecryptor = des.CreateDecryptor();
  using (FileStream fs = new FileStream(@"..\..\LicensedControls.EncryptedLicensedLabel.lic", FileMode.Open))
  {
    using (Stream crypt = new CryptoStream(fs, desDecryptor, CryptoStreamMode.Read))
    {
      byte[] licbytes = new byte[fs.Length];
            crypt.Read(licbytes, 0, licbytes.Length);
      license = UTF8Encoding.UTF8.GetString(licbytes);
    }
  }

  Console.WriteLine("Decrypted licence: {0}", license);
  
  // Spoof the license with a bigger limit.
  license = String.Concat(
    license.Substring(0, license.LastIndexOf(".") + 1), 
    ";", Int32.MaxValue);
  Console.WriteLine("Hacked licence: {0}", license);

  // Persist it encrypted again.
  ICryptoTransform desEncryptor = des.CreateEncryptor();
  using (FileStream fs = new FileStream(@"..\..\LicensedControls.EncryptedLicensedLabel.lic", FileMode.Create))
  {
    using (CryptoStream crypt = new CryptoStream(fs, desEncryptor, CryptoStreamMode.Write))
    {
      byte[] licbytes = UTF8Encoding.UTF8.GetBytes(license);
      crypt.Write(licbytes, 0, licbytes.Length);
      crypt.FlushFinalBlock();
    }
    fs.Flush();
  }

  Console.WriteLine("Finished");
  Console.ReadLine();
}

Voila! Now your licensed control can be used almost forever without expiration (I could have used Int64.MaxValue to get even more, but you get the idea).
I believe we have to come up with a better solution. Maybe signing the license file with the assembly private key (sn.exe-generated), and then checking its integrity with the assembly public key... what about building something like that right inside ASP.NET 2.0? That would really great!

How to serve binary resources from a database (images and others) in ASP.NET?

Note: this entry has moved.

This is such a frequent question, that I thought I’d better spend some time outlining a customizable and versatile solution so that it can be reused in future scenarios.
Often, binary resources such as employee pictures, office documents in a document management system, and others, are stored in a database. Now the issue is how to pull that information out of it and show it using ASP.NET. One way to solve this problem is creating a dummy ASP.NET page that simply uses Response.BinaryWrite() to output the binary field brought by the DB query, as is explained in an ASP Alliance article. However, you don’t get encapsulation and reusability, having to resort to copy/paste as new projects need such a feature.
My advice is to always use a custom IHttpHandler that serves these binary resources. Of course this is not a new idea, I'm just putting it here so I can refer to the countless persons that asked me.
You have to map a path to your handler in the Web.config file, and to avoid having to modify the IIS extensions mapping, you should use one of the built-in extensions that are already mapped to ASP.NET at installation time: .ashx or .axd. It's always better to use an specific "file name" for your handler, to avoid interfering with the ASP.NET built-in handlers. Such a handler should be configured in the Web.config as follows:

<configuration>
  <system.web>
    ...
    <httpHandlers>
      <add verb="GET" path="getresource.axd" type="NMatrix.Web.BinaryResourceHandler, NMatrix.Core" />
    </httpHandlers>

From now on, each request sent to the "file" getresource.axd will be passed to our handler. The ".ashx" extension could have been used too: it's already mapped in IIS to the ASP.NET ISAPI filter, it doesn't affect the normal ASP.NET execution, and it was conceived as the natural extension to use by so-called "web handlers" (see other articles). However, that extension is usually applied to files that look like .aspx with inline server-side code with an @ webhandler directive. That's why I prefer the "axd" extension. We map only the GET verb as it's the only one we will need to retrieve resources. This could easily be extended by allowing the POST verb meaning a new resource should be stored. I'll leave that as homework for the reader. Mostly, uploading resources is a more complex process that involves authorization at least, maybe even a full document management system.

The handler will need two parameters: the resource ID and the connection string to the repository. The first one will be provided by the calling client, as a query string value. The later is stored in the Web.config for simplicity:

<configuration>
  <appSettings>
  <add key="connection" value="Data Source=.\NetSdk;Initial Catalog=Resources;User Id=sa;Pwd=;" />
  </appSettings>

To make the storage flexible, the table storing the resources will also contain a ContentType to allow the storage of arbitrary types. Now the handler code:

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Web;

namespace NMatrix.Web
{
  /// <summary>
  /// Serves binary resources stored in a database.
  /// </summary>
  /// <author>Daniel Cazzulino</author>
  public class BinaryResourceHandler : IHttpHandler
  {
    #region Ctor & Vars

    //Key used in Web.config
    public const string ConnectionStringKey = "connection";
    //Holds the DB connection
    private static string _connectionstring;
    //Size of the chunk to read from the DB
    private const int ChunkSize = 1024;

    static BinaryResourceHandler()
    {
      _connectionstring = ConfigurationSettings.AppSettings[ConnectionStringKey];
      if (_connectionstring == null || _connectionstring.Length == 0)
        throw new ArgumentException("A 'connection' attribute must be provided to the handler.");
    }

    #endregion Ctor & Vars

    #region IHttpHandler Members

    public void ProcessRequest(HttpContext context)
    {
      string id = context.Request.QueryString["id"];
      if (id == null || id.Length == 0)
        throw new ArgumentException("An 'id' query string value must be specified.");

      using (SqlConnection cn = new SqlConnection(_connectionstring))
      {
        SqlCommand cmd = new SqlCommand("SELECT ContentType, BinaryData FROM Resources WHERE ResourceId=@id", cn);
        cmd.Parameters.Add("@id", SqlDbType.VarChar, 50);
        cmd.Parameters["@type"].Value = id
        cn.Open();
        //CommandBehavior.SequentialAccess avoids loading the entire BLOB in-memory.
        SqlDataReader r = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
        if (r.Read())
        {
          context.Response.ContentType = r.GetString(0);
          byte[] buffer = new byte[ChunkSize];
          long idx = 0;
          long size = 0;
          //Write the BLOB chunk by chunk.
          while ((size = r.GetBytes(1, idx, buffer, 0, ChunkSize)) == ChunkSize)
          {
            context.Response.BinaryWrite(buffer);
            idx += ChunkSize;
          }
           //Write the last bytes.
           byte[] remaining = new byte[size];
           Array.Copy(buffer, 0, remaining, 0, size);
           context.Response.BinaryWrite(remaining);
        }

      }
    }

    /// <summary>
    /// This instance is freely reusable.
    /// </summary>
    public bool IsReusable
    {
      get { return true; }
    }

    #endregion IHttpHandler Members
  }
}

The code is straightforward. The only tip is that by using CommandBehavior.SequentialAccess, the SqlDataReader can read the binary data in chunks, avoiding to load it completely in-memory (thanks Pablo Castro!).
A client application performing uploads could simply have a file upload HTML control (with runat="server" to allow our code to access the Request.Files collection) and with the following code could simply save arbitrary files to the database:

private void btnUpload_ServerClick(object sender, System.EventArgs e)
{
  using (SqlConnection cn = new SqlConnection(ConfigurationSettings.AppSettings[
         NMatrix.Web.BinaryResourceHandler.ConnectionStringKey]))
  {
    SqlCommand cmd = new SqlCommand("INSERT INTO Resources (ContentType, BinaryData) VALUES (@type, @data)", cn);
    cmd.Parameters.Add("@type", SqlDbType.VarChar, 50);
    cmd.Parameters.Add("@data", SqlDbType.Image);
    cmd.Parameters["@type"].Value = txtContent.Text;
    byte[] data = new byte[Request.Files[0].InputStream.Length];
    //Trunc the stream length. Nobody will be able to send Int.MaxValue bytes (around 2Gb!)
    Request.Files[0].InputStream.Read(data, 0, (int) Request.Files[0].InputStream.Length);
    cmd.Parameters["@data"].Value = data;
    cn.Open();
    cmd.ExecuteNonQuery();
  }         
}

The ContentType field has a purpose: if someone specifies application/msword or application/msexcel (or any other content type understood and handled specially by the browser), IE will automatically instantiate the appropriate Office application inside the browser window to open the incoming "file" (stream, more properly).
To refer to a resource of type image/jpg from an <img> HTML tag, we could use:

<img alt="Dynamically served image" src="getresource.axd?id=3">

To directly open a Word document from the server, we could simply point IE to the same handler passing its id.

Visitor Design Pattern: revisited for .NET

Note: this entry has moved.

The somewhat forgot Visitor Design Pattern exposed by Gamma et all (the legendary GoF book), is explored under the light of .NET and C#, and a new way of implementing it in an extensible yet easy way is discussed in my article.
XSD.EXE is still useful (or how to get properties instead of fields)

Note: this entry has moved.

Getting code form XSD files is a great help when you have to create many entities reflecting your business logic. It also allows for easy extensibility because you only have to change the schema and generate the entities again. Using xsd.exe /c, you can get the XmlSerializer-friendly classes in a snap. What's more, a very usefull tool by Chris Sells even makes the process automatic inside the IDE, with a custom tool.
However, the problem with XSD is that it generates classes with public fields instead of property get/sets, which is far from ideal.

As you probably know, there's no way of customizing XSD.EXE, so how can we get the properties and still use it? A little work with regular expressions and the Find/Replace dialog does the trick. Use the following values in the dialog:

Find what:    public {[^ ]+} {[^ ]+};
Replace with: public \1 \2 \n\t\t{\n\t\t\tget { return _\2; }\n\t\t\tset { _\2 = value; }\n\t\t} private \1 _\2;

Remember to check Use Regular Expressions. Now you will get the following code:

/// 
public int CustomerID;

replaced with:

/// 
public int CustomerID 
{
 get { return _CustomerID; }
 set { _CustomerID = value; }
} private int _CustomerID;

Lastly, having public properties lets you bind these custom classes directly to a WinForms datagrid and get the properties as columns automatically (yeah... I know nobody will EVER use that...). But you can always take the blue pill after doing so ;)

Binary serialization, the smarter way: reloaded

Note: this entry has moved.

VGA posted about a way to improve the binary serialization, by using a compact format. We work together, and I was surprised he didn't post some code for all the code-hungry guys, so here it is:

public sealed class BinaryHelper
{
	private enum TypeID : byte
	{
		Boolean = 0x03, 
		Byte = 0x06, 
		...
	}

	private static Type[] _types;

	static IOHelper()
	{
		_types = new Type[19];
		_types[0] = typeof(string);
		_types[1] = typeof(int);
		_types[2] = typeof(bool);
		...
	}

	private BinaryHelper(){}

	public static object ReadBinary(BinaryReader reader)
	{
		TypeID code = (TypeID) reader.ReadByte();

		switch (code)
		{
			case TypeID.Boolean:
				return reader.ReadBoolean();
			case TypeID.Byte:
				return reader.ReadByte();
			...
			case TypeID.Object:
				BinaryFormatter fmt = new BinaryFormatter();
				MemoryStream stm = new MemoryStream(reader.ReadBytes(reader.ReadInt32()));
				return fmt.Deserialize(stm);
			...
		}
	}

	public static void WriteBinary(BinaryWriter writer, object value)
	{
		if (value == null)
		{
			writer.Write((byte)TypeID.Null);
			return;
		}

		Type t = value.GetType();
		//Write according to type.

		if (t == _types[0])
		{
			writer.Write((byte)TypeID.String);
			writer.Write((String)value);
			return;
		}
		if (t == _types[1])
		{
			writer.Write((byte)TypeID.Int32);
			writer.Write((int)value);
			return;
		}
		...
		//Other types serialized to binary directly.
		try
		{
			writer.Write((byte)TypeID.Object);
			BinaryFormatter fmt = new BinaryFormatter();
			MemoryStream stm = new MemoryStream();
			fmt.Serialize(stm, value);
			writer.Write(stm.Length);
			writer.Write(stm.ToArray());
		}
		catch (Exception ex)
		{
			throw new InvalidOperationException("Couldn't serialize object.", ex);
		}
	}
}

Note that for arbitrary object serialization, the class relies in built-in BinaryFormatter, which makes it an improvement of if but not a replacement. The types specified in the TypeID enumeration will be highly optimized, and could even expand on the future if you find better ways of serializing other types.
You can figure out the missing parts. It's pretty clear in the IL code (maybe Reflector can help more). What's important is that whether or not you saw System.Web AltSerialization class, this approach is so logic and common that I doubt many more developers haven't arrived to very similar code before (at least I did, even before .NET existed).

Incredibly real, exciting and possible story!

Note: this entry has moved.

I can't stress enough how great Neuromancer is. I read it twice in a month... it is THAT good.
The author, William Gibson, wrote this book back in 1985, when there was no Internet, no virtual reality, no Matrix movie!! Yet, he is the father of the "cyberspace" word, you can recognize a yet-to-be-created virtual reality device that "transmits" not only images but the full 5 senses to the user (the simestim), and he even mentions (and gives birth to) the Matrix! Yes... exactly with that name...
A must-read for Matrix lovers, technology fans and those who wonder what the near future may look like....
Using WSE (1.x) on a per-WebMethod basis

Note: this entry has moved.

WSE is great for several things, but as stated in Programming with WSE 1.0, you have to add the extension in the Web.config. However, this causes ALL exposed WebMethods to require WSE processing, thus, you can't secure some of them and leave others as "plain" ASP.NET WebServices.

The solution is to use the other type of web service extension available on ASP.NET, an SoapExtensionAttribute-inherited class that can be applied to each desired attribute. The code for such an attribute class, allowing you to use WSE only on specific methods, follows:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class WseExtensionAttribute : SoapExtensionAttribute
{
	public override Type ExtensionType
	{
		get { return typeof(WebServicesExtension); }
	}

	public override int Priority
	{
		get { return _priority; }
		set { _priority = value;    }
	} int _priority = 0;
}

Now you can use the attribute only on the methods that require WSE processing:

[WebMethod]
[WseExtension]
public void WseSecuredMethod()
{
}

[WebMethod]
public void NonWseMethod()
{
}

By looking at the WSE 2.0 Technical Preview "code", I can say this still holds true, so you will need this code anyway (except if they happen to add it!).

Introduction

Note: this entry has moved.

I think it's time to start for me too :). I'm Daniel, a big fan of .NET, C#, XML and design patterns. I wrote 4 books for the extint Wrox Press (about ASP.NET and Server Controls), as well as some articles for C# Today and ASP Today. I was a speaker at the .NET ONE 2002 conference also (slides), where I presented the NMatrix project, a personal endeavour I started back in May 2001, in a joined effort with my german friend Rainer and Paul Speranza to contribute to the OpenSource community.

Almost a year ago, I joined Lagash (spanish), the company started by four brilliant and excelent people DiegoG, DiegoB, Pablo and Julian. They really created a company that is the ideal of every entrepreneur: a frienly ambience, cool and smart people, a strong sense of teamwork and collaboration, and they are really superb in building a strong feeling of belonging and community among us. It's really great and I'm very lucky they found me. Thanks God for that one ;)

Before Lagash, I tried to start my own company, DEVerest, but it got mixed with my efforts with NMatrix, and later Lagash turned out to be everything I ever wanted from my own company, so why start from scratch? I perceive myself an integral part of Lagash, share its goals and put all my energies in it. I only wish I was there when they founded it :(.

Recently, VGA also joined us, another clever guy I met in the Wrox days.
I will be posting some code, and thoughts about programming, movies and books I read.

Let's start the real blogging now...

Cazzu
More Posts