Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

April 2013 - Posts

Querying Entity Framework Code First Inheritance

This is a short post to complement my previous one on Entity Framework Code First Inheritance: how to query for a specific class. The options are:

  1. From the DbContext collection:
       1: IEnumerable<DerivedA> derived = ctx.Bases.OfType<DerivedA>().ToList();
  2. From the inner ObjectContext, using Entity SQL and the OFTYPE operator:
       1: IEnumerable<DerivedA> derived = (ctx as IObjectContextAdapter).ObjectContext.CreateQuery<DerivedA>("SELECT VAlUE b FROM OFTYPE(Bases, MyNamespace.DerivedA) AS b").OfType<DerivedA>().ToList();
  3. Also in Entity SQL, using TREAT and IS OF:
       1: IEnumerable<DerivedA> derived = (ctx as IObjectContextAdapter).ObjectContext.CreateQuery<DerivedA>("SELECT VAlUE TREAT(b AS MyNamespace.DerivedA) FROM Bases AS b WHERE b IS OF (ConsoleApplication1.DerivedA)").OfType<DerivedA>().ToList();
  4. Using LINQ to Entities:
       1: IEnumerable<DerivedA> derived = (from d in ctx.Bases where d is DerivedA select d as DerivedA).ToList();
  5. Using pure SQL:
       1: IEnumerable<DerivedA> derived = ctx.Database.SqlQuery<DerivedA>("SELECT * FROM Bases AS b WHERE b.Discriminator = 'DerivedA'").ToList();
Visual Studio 2012 and .NET 4.5 Expert Development Cookbook Review
Visual Studio 2012 and .NET 4.5 Expert Development Cookbook

Visual Studio 2012 and .NET 4.5 Expert Development Cookbook

I recently started reading Packt Publishing’s Visual Studio 2012 and .NET 4.5 Expert Development Cookbook. It is a book focused primarily on the new features of .NET 4.5 and Visual Studio 2012. Although some concepts already existed in previous versions (some Visual Studio IDE elements, for example), others are quit new (take Windows 8 programming APIs and the new asynchronous syntax). It follows the now classic recipes or cookbook approach, where for each category, a number of recipes are presented with a brief description of their purpose and some code to illustrate the solution. It is a very focused book, it doesn’t cover anything that shouldn’t be there.

The first chapter is about the IDE, how to use it effectively and how to extend it without using code. It walks us through creating templates and code snippets and in the process we get to know smart tags, refactoring options, UML diagrams and other nice functionality.

On second chapter, the focus is .NET application and memory management. We learn about the internal structure of a .NET assembly (actually, its various types), garbage collection and memory management and even how to disassemble it with ILMerge or Reflector. Talking about disassembling, some tips for protecting an assembly against it are also presented by means of Dotfuscator. Also includes an interesting tip on detecting memory leaks. This is the one chapter that mostly deals with pre-.NET 4.5 concepts.

Next comes asynchronous programming, something that most people (including myself) are looking with increased interest since the arrival of .NET 4.5. The chapter presents all programming models currently available for .NET developers and talks about some not well known thread synchronization objects and techniques of the .NET world, including guidelines on choosing the appropriate mechanisms. Finally it covers the new async and await pattern.

Following is a chapter on the new enhancements to ASP.NET, which go from HTML5 editor and syntax support to working with strongly-typed models in data-bound controls. In the middle, it also covers using asynchronous programming techniques in pages, modules and handlers and effectively using jQuery. There’s also a recipe on actually using some of HTML5’s new features, which is not strictly on ASP.NET, but is useful nevertheless.

WPF is next. The very popular MVVM patter is presented together with the new improvements like Ribbon support, a feature which seems to be becoming ubiquitous in Microsoft products.

The final chapters are all about Windows 8 applications. The first focuses on building touch-sensitive applications. It was a fun read, because I knew absolutely nothing on the subject. It actually covers more than just touch-sensitive applications, and covers WinRT, JavaScript and XAML.

The last chapter talks about the various options for communicating and sharing contained within Windows 8. Also a very interesting one, of which I knew nothing about. It covers the ways by which we can share data between Windows 8 applications, writing notification services in WCF and displaying notifications in tiles or toasts.

It was a very pleasant read, I am sure to return to it very often, for some of the topics are very wide.

Entity Framework Code First Inheritance

Introduction

Another post for self reference, this time, how to map inheritance strategies with Entity Framework Code First.

Single Table Inheritance / Table Per Class Hierarchy

First, the default strategy: one table for all classes in the hierarchy. Will store all columns on the same table, so all properties on derived classes must be nullable, and there will be lots of nulls. An additional column will be created, which will contain a discriminator value for deciding which type corresponds to each row.

   1: [Table("Base")]
   2: public abstract class Base
   3: {
   4:     public Int32 BaseId { get; set; }
   5:  
   6:     public String InheritedColumn { get; set; }
   7: }

 

   1: public class DerivedA : Base
   2: {
   3:     public String A { get; set; }
   4: }

 

   1: public class DerivedB : Base
   2: {
   3:     public String B { get; set; }
   4: }

 

image

 

Class Table Inheritance / Table Per Type

This will map all properties of the base class into a table of its own and each derived class in its own table, connected to the base table by a foreign key. No duplication will occur and properties on derived classes can be mapped as not nullable.

   1: [Table("Base")]
   2: public abstract class Base
   3: {
   4:     public Int32 BaseId { get; set; }
   5:  
   6:     public String InheritedColumn { get; set; }
   7: }

 

   1: [Table("DerivedA")]
   2: public class DerivedA : Base
   3: {
   4:     public String ColumnA { get; set; }
   5: }

 

   1: [Table("DerivedB")]
   2: public class DerivedB : Base
   3: {
   4:     public String ColumnB { get; set; }
   5: }

 

image

 

Concrete Table Inheritance / Table Per Concrete Type

No table for the base class, each concrete class will have its own table, which will contain columns for all of the class’ properties, including inherited ones. One record will only exist in one of the tables, so usage of IDENTITY columns as primary keys is not possible, because there will be records with the same ID on all of the tables, unless different seeds and/or increments are used.

   1: public abstract class Base
   2: {
   3:     public Int32 BaseId { get; set; }
   4:  
   5:     public String InheritedColumn { get; set; }
   6: }

 

   1: [Table("DerivedA")]
   2: public class DerivedA : Base
   3: {
   4:     public String ColumnA { get; set; }
   5: }

 

   1: [Table("DerivedB")]
   2: public class DerivedB : Base
   3: {
   4:     public String ColumnB { get; set; }
   5: }

This will require additional configuration at the context level, this strategy is not possible just with attributes:

   1: public class Context : DbContext
   2: {
   3:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
   4:     {
   5:         modelBuilder.Entity<DerivedA>().Map(m =>
   6:         {
   7:             m.MapInheritedProperties();
   8:         });
   9:         modelBuilder.Entity<DerivedB>().Map(m =>
  10:         {
  11:             m.MapInheritedProperties();
  12:         });
  13:     }
  14:  
  15:     public DbSet<Base> Bases { get; set; }
  16: }

 

image

Entity Framework Code First Relations

Introduction

This post is more for self-reference than anything else. Basically, I tend to forget some options for mapping relations with Entity Framework Code First, so I wrote this. If in doing so it helps someone, even better! Winking smile

One-to-Many

First, the most basic: one-to-many/many-to-one: an instance of the Master class has lots of Details.

   1: public class Master
   2: {
   3:     public Int32 MasterId { get; set; }
   4:  
   5:     public virtual ICollection<Detail> Details { get; protected set; }
   6: }

 

   1: public class Detail
   2: {
   3:     public Int32 DetailId { get; set; }
   4:  
   5:     public virtual Master Master { get; set; }
   6: }

image

One-to-One

The stepchild of database relations. Sometimes it is useful, though: a single Master has an optional Detail, which always refers to an existing Master.

   1: public class Master
   2: {
   3:     public Int32 MasterId { get; set; }
   4:  
   5:     public virtual Detail Detail { get; set; }
   6: }

 

   1: public class Detail
   2: {
   3:     [Key]
   4:     [ForeignKey("Master")]
   5:     public Int32 MasterId { get; set; }
   6:  
   7:     [Required]
   8:     public virtual Master Master { get; set; }
   9: }

image

Many-to-Many

A single Master can have many Details; each Detail can itself be connected to multiple Masters.

   1: public class Master
   2: {
   3:     public Master()
   4:     {
   5:         this.Details = new List<Detail>();
   6:     }
   7:  
   8:     public Int32 MasterId { get; set; }
   9:  
  10:     public virtual ICollection<Detail> Details { get; protected set; }
  11: }

 

   1: public class Detail
   2: {
   3:     public Detail()
   4:     {
   5:         this.Masters = new List<Master>();
   6:     }
   7:  
   8:     public Int32 DetailId { get; set; }
   9:  
  10:     public virtual ICollection<Master> Masters { get; protected set; }
  11: }

image

One-to-Many With Composite Key

In this case we have a composite primary key constituted by a foreign key and a scalar column: a Master instance is related with many Details and each Detail is identified by both a single Master and a timestamp.

   1: public class Master
   2: {
   3:     public Master()
   4:     {
   5:         this.Details = new List<Detail>();
   6:     }
   7:  
   8:     public Int32 MasterId { get; set; }
   9:  
  10:     public virtual ICollection<Detail> Details { get; protected set; }
  11: }

 

   1: public class Detail
   2: {
   3:     [Key]
   4:     [ForeignKey("Master")]
   5:     [Column(Order = 0)]
   6:     public Int32 MasterId { get; set; }
   7:  
   8:     [Required]
   9:     public virtual Master Master { get; set; }
  10:  
  11:     [Key]
  12:     [Column(Order = 1)]
  13:     public DateTime Timestamp { get; set; }
  14: }

image

Have I forgotten something? Let me know!

Unity – Part 3: Aspect Oriented Programming

AOP

This is my third post on Unity. See the first here for an introduction and the second here for how to apply dependency injection.

Aspect Oriented Programming (AOP) is a technique for applying cross-cutting concerns to existing implementations, without modifying them. Some examples of it are:

  • Wrapping method calls that go to the database in transactions automatically;
  • Logging all calls to some method, including the input parameters and return value;
  • Catching exceptions thrown in a method automatically and doing something with them.

AOP is supported in the Enterprise Library (of which Unity is part) by the Policy Injection application block, and it can be integrated with Unity. You must install this application block, perhaps by using NuGet:

image

We need to add the interception behavior – which is the one that actually applies aspects – to Unity, either by code:

   1: unity.AddNewExtension<Interception>();

Or by XML configuration:

   1: <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
   2:     <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
   3: </unity>

Having said that, the first concept we need to know is that of an interceptor. An interceptor in the Policy Injection block is an implementation of Microsoft.Practices.Unity.InterceptionExtension.IInterceptor interface, and there are three implementations:

It is required that, when you are going to apply an aspect to a registration, you choose an interceptor suitable for that registration, based on what type we are registering.

An aspect itself is an implementation of Microsoft.Practices.Unity.InterceptionExtension.ICallHandler, Unity includes five out of the box such handlers:

The ICallHandler interface only defines a single method, Invoke, which wraps a method’s arguments and allows having code run before, after or even instead of the target method, and an Order property, for specifying the order by which the aspect should be applied, in case there are many.

A simple call handler, for outputting some string before or after a method call, might be:

   1: public class OutputCallHandler : ICallHandler
   2: {
   3:     public Boolean Before
   4:     {
   5:         get;
   6:         set;
   7:     }
   8:  
   9:     public Boolean After
  10:     {
  11:         get;
  12:         set;
  13:     }
  14:  
  15:     public String Message
  16:     {
  17:         get;
  18:         set;
  19:     }
  20:  
  21:     Int32 ICallHandler.Order
  22:     {
  23:         get;
  24:         set;
  25:     }
  26:  
  27:     IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
  28:     {
  29:         if (this.Before == true)
  30:         {
  31:             Console.WriteLine(this.Message);
  32:         }
  33:  
  34:         IMethodReturn result = getNext()(input, getNext);
  35:  
  36:         if (result.Exception != null)
  37:         {
  38:             Console.Error.WriteLine(result.Exception.Message);
  39:         }
  40:         else
  41:         {
  42:             if (this.After == true)
  43:             {
  44:                 Console.WriteLine(this.Message);
  45:             }
  46:         }
  47:  
  48:         return (result);
  49:     }
  50: }

Another option is to have interception for all methods of the target registration, which can be achieved by implementing Microsoft.Practices.Unity.InterceptionExtension.IInterceptionBehavior in a concrete class, such as this:

   1: public class MyInterceptionBehavior : IInterceptionBehavior
   2: {
   3:     IEnumerable<Type> IInterceptionBehavior.GetRequiredInterfaces()
   4:     {
   5:         return (Type.EmptyTypes);
   6:     }
   7:  
   8:     IMethodReturn IInterceptionBehavior.Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
   9:     {
  10:         //before target method call
  11:  
  12:         if (input.MethodBase == typeof(MyService).GetMethod("DoSomething"))
  13:         {
  14:             //do something
  15:         }
  16:  
  17:         IMethodReturn methodReturn = getNext().Invoke(input, getNext);
  18:  
  19:         //after target method call
  20:  
  21:         return (methodReturn);
  22:     }
  23:  
  24:     Boolean IInterceptionBehavior.WillExecute
  25:     {
  26:         get
  27:         {
  28:             return (true);
  29:         }
  30:     }
  31: }

If we want to cancel the default method call, if it is non void, we must return an appropriate value:

   1: IMethodReturn methodReturn = input.CreateMethodReturn(someValue, input.Arguments);

Or if we want to return an exception:

   1: IMethodReturn methodReturn = input.CreateExceptionMethodReturn(new SomeException());

There are three ways by which we can apply an aspect to a registration:

  • By applying an attribute to a method on the declaring or target type;
  • By code configuration;
  • By XML configuration.

Interception By Attributes

We need to create an attribute that derives from Microsoft.Practices.Unity.InterceptionExtension.HandlerAttribute and which instantiates our call handler:

   1: [Serializable]
   2: [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
   3: public sealed class OutputCallHandlerAttribute : HandlerAttribute
   4: {
   5:     public Boolean Before
   6:     {
   7:         get;
   8:         set;
   9:     }
  10:  
  11:     public Boolean After
  12:     {
  13:         get;
  14:         set;
  15:     }
  16:  
  17:     public String Message
  18:     {
  19:         get;
  20:         private set;
  21:     }
  22:  
  23:     public OutputCallHandlerAttribute(String message)
  24:     {
  25:         this.Message = message;
  26:     }
  27:  
  28:     public override ICallHandler CreateHandler(IUnityContainer container)
  29:     {
  30:         return (new OutputCallHandler() { After = this.After, Before = this.Before, Message = this.Message });
  31:     }        
  32: }

And we apply it to any method declaration:

   1: public interface IMyService
   2: {
   3:     [OutputCallHandler("Before", Before = true)]
   4:     [OutputCallHandler("After", After = true)]
   5:     void DoSomething();
   6: }

But before this works, we need to tell Unity to use interface interception for our type:

   1: unity.Configure<Interception>().SetDefaultInterceptorFor<IMyService>(new InterfaceInterceptor());

Interception By Code

For intercepting by code, whenever we register something with Unity, we also tell it to use interface interception and to include a behavior instance – it is not possible to specify a call handler for a specific method:

   1: unity.RegisterType<IMyService, MyService>(new ContainerControlledLifetimeManager(), new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<OutputInterceptionBehavior>());

Interception By Configuration

When applying interception by configuration we also cannot target a specific method, but instead specify an interception behavior, which will apply to all method – of course, inside of it we can do our own filtering, by looking at the IMethodInvocation.MethodBase property:

   1: <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
   2:     <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
   3:     <container>
   4:         <extension type="Microsoft.Practices.Unity.InterceptionExtension.Interception, Microsoft.Practices.Unity.Interception"/>
   5:         <interceptors>
   6:             <interceptor type="InterfaceInterceptor">
   7:                 <default type="MyNamespace.IMyService, MyAssembly"/>
   8:             </interceptor>
   9:         </interceptors>
  10:         <register type="MyNamespace.IMyService, MyAssembly" mapTo="MyNamespace.MyService, MyAssembly">
  11:             <lifetime type="singleton"/>
  12:             <interceptionBehavior type="MyNamespace.OutputInterceptionBehavior, MyAssembly"/>
  13:         </register>
  14:         </register>
  15:     </container>
  16: </unity>

Executing

You must Unity to retrieve an instance, which will be properly wrapped in a proxy, and from there all of your configured interceptors will be called:

   1: IMyService svc = ServiceLocator.Current.GetInstance<IMyService>();
   2: svc.DoSomething();

Next in line: extending Unity.

Unity – Part 2: Dependency Injection

Dependency Injection

Second part of my series on Unity. For an introduction, read the first post.

OK, now we know how to get Inversion of Control (IoC): instead of referencing a particular concrete implementation, we instead reference an interface or an abstract base class, which creates a level of abstraction and allows us to change things at a later time.

Now let’s see what Unity has to offer in terms of Dependency Injection (DI). DI is the process by which objects are populated (injected) with values, called dependencies, usually coming from the IoC container itself. Basically, we have three options for that:

  • Constructor injection;
  • Property injection;
  • Method injection.

What this means is, when asked for a particular instance, Unity will call a constructor, set a property’s value or invoke a method with a parameter coming from its registration. Say you have a class like this:

   1: public class MyService : IMyService
   2: {
   3:     public ILogger Logger
   4:     {
   5:         get;
   6:         private set;
   7:     }
   8:  
   9:     public MyService(ILogger logger)
  10:     {
  11:         this.Logger = logger;
  12:     }
  13:  
  14:     public void SetLogger(ILogger logger)
  15:     {
  16:         this.Logger = logger;
  17:     }
  18: }

Unity can inject the Logger instance by either passing a parameter on the constructor when building an instance of the MyService class, directly setting the Logger property (even with a private setter) or by invoking the SetLogger method.

Injection By Configuration

As we have seen, most things in Unity can be configured by XML configuration:

   1: <register type="MyNamespace.IMyService, MyAssembly" mapTo="MyNamespace.MyService, MyAssembly">
   2:     <constructor>
   3:         <param name="logger" dependencyType="MyNamespace.ILogger, MyAssembly" dependencyName="File"/>
   4:     </constructor>
   5:     <property name="Logger" dependencyType="MyNamespace.ILogger, MyAssembly" dependencyName="File"/>
   6:     <method name="SetLogger">
   7:         <param name="logger" dependencyType="MyNamespace.ILogger, MyAssembly" dependencyName="File"/>
   8:     </method>
   9: </register>

Did you notice the dependencyName attribute? That is the name under which the dependencyType was registered, if not set, it defaults to the empty string.

I have included both constructor, property and method injection, you usually will only need one of them.

Injection By Code

Another option is by code. When registering a type, you must add some additional code:

   1: unity.RegisterType<IMyService, MyService>(new InjectionConstructor(unity.Resolve<ILogger>("File")), new InjectionMethod("SetLogger", unity.Resolve<ILogger>("File")), new InjectionProperty("Logger", unity.Resolve<ILogger>("File")));

If you don’t want to resolve an instance yourself in InjectionMethod, InjectionConstructor or InjectionProperty, you can pass a Type and Unity will look up the actual instance for you.

Injection By Attributes

Another option is by applying attributes:

   1: public class MyService : IMyService
   2: {
   3:     [Dependency("File")]
   4:     public ILogger Logger
   5:     {
   6:         get;
   7:         private set;
   8:     }
   9:  
  10:     [InjectionConstructor]
  11:     public MyService([Dependency("File")] ILogger logger)
  12:     {
  13:         this.Logger = logger;
  14:     }
  15:  
  16:     [InjectionMethod]
  17:     public void SetLogger([Dependency("File")] ILogger logger)
  18:     {
  19:         this.Logger = logger;
  20:     }
  21: }

The File string is the name of the registered type.

Like previously mentioned, although I depicted all three, you will pick only one injection method. When you call Resolve or GetInstance, the instance you get will have its dependencies assigned.

Injecting Dependencies On Existing Entities

If you have some object instance that was obtained elsewhere, you can still ask Unity to inject whatever dependencies this object has. This is achieved by the BuildUp family of methods:

   1: IMyService svc = new MyService();
   2:  
   3: unity.BuildUp(svc);    //Logger property is set and SetLogger method is called

Next in line: applying aspects. Stay tuned!

Unity - Part 1: Introduction

Updated: ContainerControlled instead of ExternallyControlled in the bullet list of lifetime managers. Thanks, Ross Smith!

Introduction

Unity is Microsoft’s Inversion of Control (IoC) and Dependency Injection (DI) container. It is part of the Enterprise Library family of Application Blocks.

I have been using it for years. Yes, I am aware that there are lots of other tools for the same purpose and with more or less functionality, but I actually like Unity. It has a good combination of out of the box features, performance and extensibility options. Some of its aspects, I believe, are not well know, so I set out to write a couple of posts on it, this being the first. This will not be an introduction to IoC and DI, I am assuming you already know that.

First things first: the best way to install Unity is by using Nuget:

image

It will install both Unity and the Common Service Locator, and all .NET versions from 2.0 are supported.

The Common Service Locator is an attempt to define a common interface for a IoC functionality; different IoC libraries implement adapters for the Common Service Locator, so that they can be used through the common interface, without tying the implementation to a particular one. Most IoC containers already implement one such adapter.

We create a Unity container like this:

   1: private static readonly IUnityContainer unity = new UnityContainer();

And we set up the Common Service Locator from it:

   1: ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unity));

An IoC container is no good without registrations. You can register entries on the configuration file or through code. An IoC container is particularly good for minimizing coupling, by having dependencies on interfaces and abstract base classes instead of actual implementations, so these registrations basically consist of an interface of abstract base class as the key and a concrete type or instance as the value. Let’s consider a simple interface, ILogger, and two concrete implementations, ConsoleLogger and FileLogger:

image

The implementation is not very important, but lets consider the following ILogger interface:

   1: public interface ILogger
   2: {
   3:     void Log(String message);
   4: }

Registration By Configuration File

If you want to register by configuration, place the following content on the Web.config or App.config file:

   1: <configuration>
   2:     <configSections>
   3:         <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
   4:     </configSections>
   5:     <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
   6:         <container>
   7:             <register type="MyNamespace.ILogger, MyAssembly" mapTo="MyNamespace.ConsoleLogger, MyAssembly"/>
   8:             <register type="MyNamespace.ILogger, MyAssembly" mapTo="MyNamespace.FileLogger, MyAssembly" name="File"/>
   9:         </container>
  10:     </unity>
  11: </configuration>

Notice the two registrations, both for the interface ILogger, one mapping to ConsoleLogger, without a name, and another mapping to FileLogger, with a name of File. This is perfectly valid, there can be multiple declarations for the same interface (or abstract base class), provided they have different names. If no name is specified, it will default to the empty string (“”).

We have to tell Unity to load the configuration from the .config file, and we do it like this (do reference the Microsoft.Practices.Unity.Configuration namespace for the LoadConfiguration extension method):

   1: unity.LoadConfiguration();

Registration By Code

Alternatively, if you want to register entries by code, do so as:

   1: unity.RegisterType<ILogger, ConsoleLogger>();
   2: unity.RegisterType<ILogger, FileLogger>("File");

With registration by code, you can do something that is not available with the configuration file approach: registering a concrete instance as the value. Here’s how:

   1: unity.RegisterType<ILogger, ConsoleLogger>();
   2: unity.RegisterInstance<ILogger>("File", new FileLogger());

This has the advantage that you can create an instance anyway you like, with any specific configuration, and make it available to Unity.

Pay attention to this: the Common Service Locator has no methods for adding entries to the registration, just for resolving them.

Getting Instances

After you have some entries registered, you can ask for them, either by calling Unity directly (not recommended) or through the Common Service Locator (better):

   1: ILogger loggerFromUnity = unity.Resolve<ILogger>();
   2: ILogger loggerFromCommonServiceLocator = ServiceLocator.Current.GetInstance<ILogger>();

Or, if you want to obtain a particular named registration:

   1: ILogger fileLoggerFromUnity = unity.Resolve<ILogger>("File");
   2: ILogger fileLoggerFromCommonServiceLocator = ServiceLocator.Current.GetInstance<ILogger>("File");

For dynamic invocation, when you don’t have at compile time the desired Type, and thus no strong typing:

   1: ILogger loggerFromUnity = unity.Resolve(typeof(ILogger)) as ILogger;
   2: ILogger loggerFromCommonServiceLocator = ServiceLocator.Current.GetInstance(typeof(ILogger)) as ILogger;

It is possible to get all registered values for a given type:

   1: IEnumerable<ILogger> loggersFromUnity = unity.ResolveAll<ILogger>();
   2: IEnumerable<ILogger> loggersFromCommonServiceLocator = ServiceLocator.Current.GetAllInstances<ILogger>();
   3:  

And, if there is the need, you can also resolve instances for a Type, that is, not using generics:

   1: IEnumerable<ILogger> loggersFromUnity = unity.ResolveAll(typeof(ILogger)).OfType<ILogger>();
   2: IEnumerable<ILogger> loggersFromCommonServiceLocator = ServiceLocator.Current.GetAllInstances(typeof(ILogger)).OfType<ILogger>();

For the single instance methods, if no such registration exists (for the type or the name), an exception will be thrown. For the enumeration ones, an empty list will be returned.

Lifetime Managers

By now, you might ask yourself: OK, but what if we ask Unity for some registered interface two or more times, will it give me the same instance or different instances? If we have registered an instance, by calling RegisterInstance instead of RegisterType, Unity will indeed return the same instance all the time. Otherwise, Unity will do what the Lifetime Manager tells it to do. For a good discussion, see Understanding Lifetime Managers.

A Lifetime Manager is an instance of a class that inherits from LifetimeManager and is responsible for creating or retrieving stored instances of mapped classes. Unity comes with the following out of the box implementations, but you are free to implement others:

  • ContainerControlledLifetimeManager (aka, singleton): Unity will only create an instance of the concrete type, and will return it every time, effectively treating it as a singleton;
  • PerThreadLifetimeManager (perthread): a different instance will be created once for each thread that the method it is called on, and the same instance will be returned on all subsequent calls for the same thread;
  • TransientLifetimeManager (transient): a new instance will be created and returned every time.
  • HierarchicalLifetimeManager (hierarchical): a new instance will be created and the same one will be returned for each Unity container, and another one for each child container (more on this later).
  • PerResolveLifetimeManager (perresolve): a new instance will be created every time, but it will be reused in the same build process if it is needed as a dependency somewhere in the list of dependencies of the current resolve process.
  • ExternallyControlledLifetimeManager (external): the actual instance was created and is managed elsewhere, like when you supply your own instance.

If we don’t specify a particular Lifetime Manager instance, or if we use null, the default is TransientLifetimeManager. The RegisterType method has overloads that take a LifetimeManager instance:

   1: unity.RegisterType<ILogger, FileLogger>("File", new ContainerControlledLifetimeManager());

If you want to do it by configuration:

   1: <register type="MyNamespace.ILogger, MyAssembly" mapTo="MyNamespace.FileLogger, MyAssembly" name="File">
   2:     <lifetime type="singleton"/>
   3: </register>

Conclusion

That’s it for now. In the next post: dependency injection.

NHibernate Pitfalls: Collections of Elements and Inverse

This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

When mapping a collection of elements, this collection should not be marked as inverse. This is a different behavior from many to many or one to many, and it is because on the other endpoint of the relation, there is no entity to have the ownership of the relation, which is what the inverse attribute is for.

A simple example, in HBM.XML, just to remember:

   1: <class name="Post" lazy="true" table="`POST`">
   2:     <!-- ... -->
   3:     <set cascade="all" lazy="false" name="Tags" table="`TAG`" order-by="`TAG`">
   4:         <key column="`POST_ID`" />
   5:         <element column="`TAG`" type="String" length="20" not-null="true" unique="true" />
   6:     </set>
   7:     </class>
   8: </hibernate-mapping>
Extended ASP.NET Button Control

I once had the need to have a button control that would change its look depending on a theme, for example, it would render either as regular button, an image or a link. Of course, the only way I had to achieve this was by manually swapping the Button control for a ImageButton or a LinkButton, which wasn’t really a solution, so I started to think of a control that could do the trick… and here it is!

Basically, I wrote a button control that displays in one of 5 ways:

  • A regular button:
image
  • A text hyperlink:

image

  • An image:

image

  • A button with HTML content (see this):

image

  • A hyperlink with HTML content:

image

In ASP.NET terms, I have a server-side control with a ButtonType property. The markup that produces each effect is as follows:

   1: <web:ExtendedButton runat="server" ButtonType="Button" ID="button" Text="Button"/>
   2:  
   3: <web:ExtendedButton runat="server" ButtonType="Link" ID="link" Text="Link"/>
   4:  
   5: <web:ExtendedButton runat="server" ButtonType="Image" ID="image" ImageUrl="~/Images/button.png"/>
   6:  
   7: <web:ExtendedButton runat="server" ButtonType="Button" ID="buttonWithTemplate">
   8:     <Template>
   9:             <asp:Image runat="server" ImageUrl="~/Images/button.png" />
  10:             Button With Template
  11:         </Template>
  12: </web:ExtendedButton>
  13:  
  14: <web:ExtendedButton runat="server" ButtonType="Link" ID="linkWithTemplate">
  15:         <Template>
  16:             <asp:Image runat="server" ImageUrl="~/Images/button.png" />
  17:             Link With Template
  18:         </Template>
  19: </web:ExtendedButton>

For the Image value of ButtonType, the only useful properties are ImageUrl, ImageAlign and AlternateText. These will work in the exact same way as the ImageButton control.

For Link and Button, if the Template property is not specified, Text will be used for the textual description of the button or link. If instead a Template is available, it will be used instead of the Text. Keep in mind that you can specify almost any HTML you like for the Template, as long as it can be surrounded by an A (in the case of the Link type) or BUTTON (for Button) tags. If no Template is supplied, it will render and behave just like a LinkButton or a Button.

This control implements IButtonControl, so it shares the usual behavior of regular button controls, like having a text property, a validation group, a postback URL, Click and Command events, event bubbling, etc. It uses the control state to save some properties, so it is safe to turn off view state in it.

I almost forgot: here is the code!

   1: [ParseChildren(true)]
   2: [DefaultEvent("Click")]
   3: [PersistChildren(false)]
   4: [DefaultProperty("Text")]
   5: [SupportsEventValidation]
   6: [ToolboxData("<{0}:ExtendedButton runat=\"server\" Text=\"\" />")]
   7: public class ExtendedButton : WebControl, IButtonControl, IPostBackEventHandler, INamingContainer, ITextControl, IPostBackDataHandler
   8: {
   9:     #region Private static readonly fields
  10:     private static readonly Object EventClick = new Object();
  11:     private static readonly Object EventCommand = new Object();
  12:     #endregion
  13:  
  14:     #region Public constructor
  15:     public ExtendedButton() : base(HtmlTextWriterTag.Input)
  16:     {
  17:         this.ButtonType = ButtonType.Button;
  18:         this.CommandArgument = String.Empty;
  19:         this.CommandName = String.Empty;
  20:         this.OnClientClick = String.Empty;
  21:         this.ImageAlign = ImageAlign.NotSet;
  22:         this.ImageUrl = String.Empty;
  23:         this.PostBackUrl = String.Empty;
  24:         this.CausesValidation = true;
  25:         this.ValidationGroup = String.Empty;
  26:         this.UseSubmitBehavior = true;
  27:         this.Text = String.Empty;
  28:     }
  29:     #endregion
  30:  
  31:     #region Protected override methods
  32:     protected override void AddAttributesToRender(HtmlTextWriter writer)
  33:     {
  34:         base.AddAttributesToRender(writer);
  35:  
  36:         this.Page.VerifyRenderingInServerForm(this);
  37:  
  38:         if (this.ButtonType == ButtonType.Button)
  39:         {
  40:             if (this.Template == null)
  41:             {
  42:                 if (this.UseSubmitBehavior == true)
  43:                 {
  44:                     writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
  45:                 }
  46:                 else
  47:                 {
  48:                     writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
  49:                 }
  50:             }
  51:  
  52:             writer.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
  53:             writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
  54:         }
  55:         else if (this.ButtonType == ButtonType.Image)
  56:         {
  57:             writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
  58:             writer.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
  59:             writer.AddAttribute(HtmlTextWriterAttribute.Alt, this.AlternateText);
  60:             writer.AddAttribute(HtmlTextWriterAttribute.Type, "image");
  61:             writer.AddAttribute(HtmlTextWriterAttribute.Src, HttpUtility.HtmlEncode(this.ResolveClientUrl(this.ImageUrl)));
  62:  
  63:             if (this.ImageAlign != ImageAlign.NotSet)
  64:             {
  65:                 writer.AddAttribute(HtmlTextWriterAttribute.Align, this.ImageAlign.ToString().ToLower());
  66:             }
  67:         }
  68:  
  69:         String firstScript = this.OnClientClick;
  70:         PostBackOptions postBackOptions = this.GetPostBackOptions();
  71:                     
  72:         if (this.IsEnabled == true)
  73:         {
  74:             if (this.HasAttributes == true)
  75:             {
  76:                 String script = this.Attributes[HtmlTextWriterAttribute.Onclick.ToString()];
  77:  
  78:                 if (String.IsNullOrWhitespace(script) == false)
  79:                 {
  80:                     firstScript = String.Join(";", new String[] { firstScript, script });
  81:                     this.Attributes.Remove(HtmlTextWriterAttribute.Onclick.ToString());
  82:                 }
  83:             }
  84:  
  85:             String postBackEventReference = this.Page.ClientScript.GetPostBackEventReference(postBackOptions, true);
  86:  
  87:             if (String.IsNullOrWhiteSpace(postBackEventReference) == false)
  88:             {
  89:                 firstScript = firstScript + postBackEventReference;
  90:  
  91:                 if ((this.ButtonType == ButtonType.Link) || ((this.ButtonType == ButtonType.Button) && (this.Template != null)))
  92:                 {
  93:                     writer.AddAttribute(HtmlTextWriterAttribute.Href, postBackEventReference);
  94:                 }
  95:             }
  96:             else
  97:             {
  98:                 if (this.ButtonType == ButtonType.Link)
  99:                 {
 100:                     writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:void(0)");
 101:                 }
 102:             }
 103:         }
 104:  
 105:         if (firstScript.Length > 0)
 106:         {
 107:             if (this.ButtonType == ButtonType.Button)
 108:             {
 109:                 if (this.UseSubmitBehavior == false)
 110:                 {
 111:                     writer.AddAttribute(HtmlTextWriterAttribute.Onclick, firstScript);
 112:                 }
 113:             }
 114:             else
 115:             {
 116:                 if (String.IsNullOrWhiteSpace(this.OnClientClick) == false)
 117:                 {
 118:                     writer.AddAttribute(HtmlTextWriterAttribute.Onclick, this.OnClientClick);
 119:                 }
 120:             }
 121:         }
 122:  
 123:         if ((this.Enabled == true) && (this.IsEnabled == false))
 124:         {
 125:             writer.AddAttribute(HtmlTextWriterAttribute.Disabled, HtmlTextWriterAttribute.Disabled.ToString().ToLower());
 126:         }
 127:     }
 128:  
 129:     protected override void OnInit(EventArgs e)
 130:     {
 131:         this.Page.RegisterRequiresControlState(this);
 132:  
 133:         if (this.ButtonType == ButtonType.Image)
 134:         {
 135:             this.Page.RegisterRequiresPostBack(this);
 136:         }
 137:  
 138:         base.OnInit(e);
 139:     }
 140:  
 141:     protected override void RenderContents(HtmlTextWriter writer)
 142:     {
 143:         if ((this.ButtonType == ButtonType.Link) || (this.ButtonType == ButtonType.Button))
 144:         {
 145:             if (this.Template != null)
 146:             {
 147:                 PlaceHolder placeHolder = new PlaceHolder();
 148:                 this.Template.InstantiateIn(placeHolder);
 149:                 this.Controls.Add(placeHolder);
 150:                 base.RenderContents(writer);
 151:             }
 152:             else
 153:             {
 154:                 if (this.ButtonType == ButtonType.Link)
 155:                 {
 156:                     writer.WriteEncodedText(this.Text);
 157:                 }
 158:             }
 159:         }
 160:     }
 161:  
 162:     protected override void LoadControlState(Object savedState)
 163:     {
 164:         Object [] state = savedState as Object [];
 165:  
 166:         this.OnClientClick = (String) state [ 1 ];
 167:         this.CausesValidation = (Boolean) state [ 2 ];
 168:         this.ValidationGroup = (String) state [ 3 ];
 169:         this.ButtonType = (ButtonType) state [ 4 ];
 170:         this.PostBackUrl = (String) state [ 5 ];
 171:         this.UseSubmitBehavior = (Boolean) state [ 6 ];
 172:         this.CommandArgument = (String) state [ 7 ];
 173:         this.CommandName = (String) state [ 8 ];
 174:         this.Text = (String) state [ 9 ];
 175:         this.ImageUrl = (String) state [ 10 ];
 176:         this.ImageAlign = (ImageAlign) state [ 11 ];
 177:  
 178:         base.LoadControlState(state [ 0 ]);
 179:     }
 180:  
 181:     protected override Object SaveControlState()
 182:     {
 183:         Object [] state = new Object [] { base.SaveControlState(), this.OnClientClick, this.CausesValidation, this.ValidationGroup, this.ButtonType, this.PostBackUrl, this.UseSubmitBehavior, this.CommandArgument, this.CommandName, this.Text, this.ImageUrl, this.ImageAlign };
 184:         return (state);
 185:     }
 186:     #endregion
 187:  
 188:     #region Public override methods
 189:     public override void RenderBeginTag(HtmlTextWriter writer)
 190:     {
 191:         this.AddAttributesToRender(writer);
 192:  
 193:         switch (this.ButtonType)
 194:         {
 195:             case ButtonType.Button:
 196:                 if (this.Template != null)
 197:                 {
 198:                     writer.RenderBeginTag(HtmlTextWriterTag.Button);
 199:                 }
 200:                 else
 201:                 {
 202:                     writer.RenderBeginTag(HtmlTextWriterTag.Input);
 203:                 }
 204:                 break;
 205:  
 206:             case ButtonType.Image:
 207:                 writer.RenderBeginTag(HtmlTextWriterTag.Input);
 208:                 break;
 209:  
 210:             case ButtonType.Link:
 211:                 writer.RenderBeginTag(HtmlTextWriterTag.A);
 212:                 break;
 213:         }
 214:     }
 215:     #endregion
 216:  
 217:     #region Protected virtual methods
 218:     protected virtual PostBackOptions GetPostBackOptions()
 219:     {
 220:         PostBackOptions options = new PostBackOptions(this, String.Empty);
 221:         options.ClientSubmit = false;
 222:  
 223:         if ((this.CausesValidation == true) && (this.Page.GetValidators(this.ValidationGroup).Count > 0))
 224:         {
 225:             options.PerformValidation = true;
 226:             options.ValidationGroup = this.ValidationGroup;
 227:         }
 228:  
 229:         if (String.IsNullOrWhiteSpace(this.PostBackUrl) == false)
 230:         {
 231:             options.ActionUrl = HttpUtility.UrlPathEncode(this.ResolveClientUrl(this.PostBackUrl));
 232:         }
 233:  
 234:         if ((this.ButtonType == ButtonType.Link) || ((this.ButtonType == ButtonType.Button) && (this.Template != null)))
 235:         {
 236:             options.ClientSubmit = true;
 237:             options.RequiresJavaScriptProtocol = true;
 238:         }
 239:  
 240:         return (options);
 241:     }
 242:  
 243:     protected virtual void OnClick(EventArgs e)
 244:     {
 245:         EventHandler handler = (EventHandler) this.Events [ EventClick ];
 246:  
 247:         if (handler != null)
 248:         {
 249:             handler(this, e);
 250:         }
 251:     }
 252:  
 253:     protected virtual void OnCommand(CommandEventArgs e)
 254:     {
 255:         CommandEventHandler handler = (CommandEventHandler) this.Events [ EventCommand ];
 256:  
 257:         if (handler != null)
 258:         {
 259:             handler(this, e);
 260:         }
 261:     }
 262:     #endregion
 263:  
 264:     #region IButtonControl Members
 265:     public event EventHandler Click
 266:     {
 267:         add
 268:         {
 269:             this.Events.AddHandler(EventClick, value);
 270:         }
 271:         remove
 272:         {
 273:             this.Events.RemoveHandler(EventClick, value);
 274:         }
 275:     }
 276:  
 277:     public event CommandEventHandler Command
 278:     {
 279:         add
 280:         {
 281:             this.Events.AddHandler(EventCommand, value);
 282:         }
 283:         remove
 284:         {
 285:             this.Events.RemoveHandler(EventCommand, value);
 286:         }
 287:     }
 288:  
 289:     [DefaultValue(true)]
 290:     [Themeable(false)]
 291:     public Boolean CausesValidation
 292:     {
 293:         get;
 294:         set;
 295:     }
 296:  
 297:     [Bindable(true)]
 298:     [DefaultValue("")]
 299:     [Themeable(false)]
 300:     public String CommandArgument
 301:     {
 302:         get;
 303:         set;
 304:     }
 305:  
 306:     [Themeable(false)]
 307:     [DefaultValue("")]
 308:     public String CommandName
 309:     {
 310:         get;
 311:         set;
 312:     }
 313:  
 314:     [DefaultValue("")]
 315:     [Themeable(false)]
 316:     [UrlProperty("*.aspx")]
 317:     public String PostBackUrl
 318:     {
 319:         get;
 320:         set;
 321:     }
 322:  
 323:     [DefaultValue("")]
 324:     [Themeable(false)]
 325:     public String ValidationGroup
 326:     {
 327:         get;
 328:         set;
 329:     }
 330:  
 331:     [DefaultValue("")]
 332:     [Localizable(true)]
 333:     [Bindable(true)]
 334:     public String Text
 335:     {
 336:         get;
 337:         set;
 338:     }
 339:     #endregion
 340:  
 341:     #region Public properties
 342:     [Browsable(false)]
 343:     [TemplateContainer(typeof(ExtendedButton))]
 344:     [TemplateInstance(TemplateInstance.Single)]
 345:     [PersistenceMode(PersistenceMode.InnerProperty)]
 346:     public ITemplate Template
 347:     {
 348:         get;
 349:         set;
 350:     }
 351:  
 352:     [DefaultValue(ButtonType.Button)]
 353:     public ButtonType ButtonType
 354:     {
 355:         get;
 356:         set;
 357:     }
 358:  
 359:     [Themeable(false)]
 360:     [DefaultValue("")]
 361:     public String OnClientClick
 362:     {
 363:         get;
 364:         set;
 365:     }
 366:  
 367:     [DefaultValue("")]
 368:     [Themeable(false)]
 369:     [UrlProperty("*.jpg;*.gif;*.png")]
 370:     public String ImageUrl
 371:     {
 372:         get;
 373:         set;
 374:     }
 375:  
 376:     [DefaultValue(ImageAlign.NotSet)]
 377:     public ImageAlign ImageAlign
 378:     {
 379:         get;
 380:         set;
 381:     }
 382:  
 383:     [DefaultValue("")]
 384:     [Themeable(false)]
 385:     public String AlternateText
 386:     {
 387:         get;
 388:         set;
 389:     }
 390:  
 391:     [DefaultValue(true)]
 392:     [Themeable(false)]
 393:     public Boolean UseSubmitBehavior
 394:     {
 395:         get;
 396:         set;
 397:     }
 398:     #endregion
 399:  
 400:     #region IPostBackEventHandler Members
 401:     void IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
 402:     {
 403:         this.Page.ClientScript.ValidateEvent(this.UniqueID, eventArgument);
 404:  
 405:         if (this.CausesValidation == true)
 406:         {
 407:             this.Page.Validate(this.ValidationGroup);
 408:         }
 409:  
 410:         this.OnClick(EventArgs.Empty);
 411:         this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
 412:  
 413:         this.RaiseBubbleEvent(this, EventArgs.Empty);
 414:     }
 415:     #endregion
 416:  
 417:     #region IPostBackDataHandler Members
 418:  
 419:     Boolean IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection postCollection)
 420:     {
 421:         if (postDataKey == this.UniqueID)
 422:         {
 423:             if (this.ButtonType == ButtonType.Image)
 424:             {
 425:                 if ((String.IsNullOrWhiteSpace(postCollection[postDataKey + ".x"]) == false) && (String.IsNullOrWhiteSpace(postCollection[postDataKey + ".y"]) == false))
 426:                 {
 427:                     (this as IPostBackEventHandler).RaisePostBackEvent(String.Empty);                    
 428:                 }
 429:             }
 430:             else
 431:             {
 432:                 (this as IPostBackEventHandler).RaisePostBackEvent(String.Empty);
 433:             }
 434:         }
 435:  
 436:         return(false);
 437:     }
 438:  
 439:     void IPostBackDataHandler.RaisePostDataChangedEvent()
 440:     {
 441:     }
 442:  
 443:     #endregion
 444: }

As usual, I hope you find it useful!

ASP.NET Web Forms Extensibility: Handlers

In the .NET world, all HTTP requests, whether they be for web services (XML, WCF, Web API), pages (Web Forms and MVC), etc, are processed by a handler. Basically, a handler is a particular implementation of the IHttpHandler interface, and requests are routed to a particular handler class by one of four ways:

  • An entry on the Web.config file, on the httpHandlers section;
  • An instance returned from a Handler Factory;
  • A route handler, like in MVC or Dynamic Data;
  • Explicitly requested by the URL, in the case of ASHX generic handlers.

The httpHandlers section can specify both a handler or a handler factory for a specific URL pattern (say, for example, /images/*.png), which may be slightly confusing. I have already discussed handler factories in another post, have a look at it if you haven’t already. A simple registration would be:

   1: <httpHandlers>
   2:     <add verb="*" path="Image.axd" type="MyNamespace.MyHandler, MyAssembly"/>
   3: </httpHandlers>

Another option is through a route. The IRouteHandler interface defines a method GetHttpHandler which returns the route handler that will handle the request. You can register a IRouteHandler instance for a specific route by setting the RouteHandler property inside the Route class.

Finally, there’s another kind of handler that doesn’t need registering and that is called explicitly: generic handlers. These are .ASHX markup files without any user interface elements that merely reference a code-behind class, which must implement IHttpHandler (you can also place code in the .ASHX file, inside a <script runat=”server”> declaration). Here’s an example:

   1: <%@ WebHandler Language="C#" Class="Handler" %>
   2: <script runat="server" language="C#">
   1:  
   2: public class Handler : System.Web.IHttpHandler
   3: {
   4:     //...
   5: }
   6:  
</script>

Having said that, what is a handler good for? The IHttpHandler interface only defines one method, ProcessRequest, and a property, IsReusable. As you can tell, this is considerably more simple than, for example, the Page class, with its myriad of virtual methods and events, which, of course, is also an implementation of IHttpHandler. Because of that, it is much more useful for handling requests that do not need a complex lifecycle. Some scenarios:

  • Downloading a file;
  • Uploading a file;
  • Streaming;
  • Redirecting;
  • Returning values for consumption by JavaScript, in AJAX style;
  • Tracing and monitoring, like ELMAH or the Trace handler;
  • Generating content dynamically, such as images.

The IsReusable indicates to the ASP.NET infrastructure if the hander’s instance can be reused for different identical requests or if a new instance needs to be created. If you don’t store state on the handler’s class, it is safe to return true.

As for the ProcessRequest method, a simple implementation might be:

   1: public class ImageHandler : IHttpHandler
   2: {
   3:     public void ProcessRequest(HttpContext context)
   4:     {
   5:         Bitmap bmp = new Bitmap(400, 300);
   6:  
   7:         Graphics g = Graphics.FromImage(bmp);
   8:         g.DrawRectangle(new Pen(new SolidBrush(Color.Green)), 10, 10, 300, 200);
   9:         g.DrawString(context.Request.Url.Query, new Font("Arial", 30), new SolidBrush(Color.Yellow), new PointF(10f, 10f));
  10:  
  11:         context.Response.ContentType = "image/gif";
  12:  
  13:         bmp.Save(context.Response.OutputStream, ImageFormat.Gif);
  14:     }
  15:  
  16:     public Boolean IsReusable
  17:     {
  18:         get
  19:         {
  20:             return (true);
  21:         }
  22:     }
  23: }

This will create an image with a text string that is obtained from the query string, that is, anything in the URL after the ? symbol.

Don’t forget to always return the appropriate content type, because the browser won’t know how to handle the content you send without it.

One final note: from an handler you normally don't have access to the session - the Session property is null. If you need to use it, you must declare that your handler implements IRequiresSessionState or IReadOnlySessionState, the later for read-only access. That's basically what ASP.NET does when, on your page's markup, you place a EnableSessionState attribute.

More Posts Next page »