Monday, March 21, 2011

ASP.NET MVC 3 Dependency Injection using Windsor Castle, Singleton Lifestyle and object not set to an instance

Dependency Injection and Inversion of Control is an increasingly common and popular design principle in ASP.NET MVC.

However for the uninitiated (and even for those how have worked with it for some time) you can run into unexpected errors, especially when mixing Lifestyles for different Components on larger projects where you have multiple container installers/initializers.

I will here present a very obvious case that nevertheless had me and another developer spending a few hours trying to figure out what was wrong. This bug presented here are especially difficult to track down when you are doing frequent builds on a development machine and that build process causes the IIS application pool(s) to recycle, effectively resetting the IoC container.

I will be using Castle Windsor as the IoC (Inversion of Control) container in this posting.

The zipped solution can be downloaded here IocLifestyles.zip

First of all we will need to start with a new standard empty ASP.MVC NET 3.0 site/project and add a reference to Castle.Windsor. This reference can be added using NuGet or by downloading the source or binary libraries at the 
Castle Windsor website.

Secondly we need to tell ASP.NET MVC that we do not want to use the DefaultControllerFactory to create controller instances but that we want to use our own which in turn uses Windsor to provide the dependencies the various controllers need.

I do this in the Global.asax file by adding the following lines in the Application_Start method.


// Using WindsorControllerFactory rather then DependencyResolver
// http://bradwilson.typepad.com/blog/2010/07/service-location-pt1-introduction.html (read comments)
// http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html (read comments)
// http://bradwilson.typepad.com/blog/2010/10/service-location-pt10-controller-activator.html (read comments)
// http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html
// http://kozmic.pl/2010/08/19/must-windsor-track-my-components/
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(applicationWideWindsorContainer));

// Initialize / install components in container
applicationWideWindsorContainer.Install(new WindsorInstaller());
As well as the the field

WindsorContainer applicationWideWindsorContainer = new WindsorContainer();
This leads to our Global.asax files looking like this

using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;

namespace IocLifestyles
{
 // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
 // visit http://go.microsoft.com/?LinkId=9394801

 public class MvcApplication : System.Web.HttpApplication
 {
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
   filters.Add(new HandleErrorAttribute());
  }

  public static void RegisterRoutes(RouteCollection routes)
  {
   routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

   routes.MapRoute(
     "Default", // Route name
     "{controller}/{action}/{id}", // URL with parameters
     new { controller = "Default", action = "Index", id = UrlParameter.Optional } // Parameter defaults
   );

  }

  WindsorContainer applicationWideWindsorContainer = new WindsorContainer();

  protected void Application_Start()
  {
   AreaRegistration.RegisterAllAreas();

   RegisterGlobalFilters(GlobalFilters.Filters);
   RegisterRoutes(RouteTable.Routes);

   // Using WindsorControllerFactory rather then DependencyResolver
   // http://bradwilson.typepad.com/blog/2010/07/service-location-pt1-introduction.html (read comments)
   // http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html (read comments)
   // http://bradwilson.typepad.com/blog/2010/10/service-location-pt10-controller-activator.html (read comments)
   // http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html
   // http://kozmic.pl/2010/08/19/must-windsor-track-my-components/
   ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(applicationWideWindsorContainer));

   // Initialize / install components in container
   applicationWideWindsorContainer.Install(new WindsorInstaller());
  }
 }
}

We now need to look closer at 2 classes, namely the WindsorControllerFactory and the WindsorInstaller.

The responsibility of the WindsorControllerFactory is to provide all the objects to the controller which it depends on to perform it's logic. This is passed in to the controllers constructor. This is done using Constructor Injection (you can see a lot of good tips, thoughts and recommendations at Mark Seeman's blog).

using System;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;

namespace IocLifestyles
{
 public class WindsorControllerFactory : DefaultControllerFactory
 {
  private readonly IWindsorContainer windsorContainer;

  public WindsorControllerFactory(IWindsorContainer windsorContainer)
  {
   this.windsorContainer = windsorContainer;
  }

  protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  {
   return windsorContainer.Resolve(controllerType) as IController;
  }

  public override void ReleaseController(IController controller)
  {
   var disposableController = controller as IDisposable;
   if (disposableController != null)
   {
    disposableController.Dispose();
   }

   windsorContainer.Release(controller);
  }
 }
}
Now we need to register the classes which we are going to use through out our application with the IoC container and we do this by implementing the IWindsorInstaller interface.

Please note the Lifestyles for the different components, since this is the key to the bug I am going to illustrate.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>());
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

Looking closer at the 2 classes that we have registered in the WindsorInstaller: SomeRepository and SessionValidator.

namespace IocLifestyles
{
 public interface ISomeRepository
 {
  SessionToken GetSessionToken();
 }

 public class SomeRepository : ISomeRepository
 {
  private readonly ISessionValidator sessionValidator;

  public SomeRepository(ISessionValidator sessionValidator)
  {
   this.sessionValidator = sessionValidator;
  }

  public SessionToken GetSessionToken()
  {
   return sessionValidator.ValidateSession();
  }
 }
}
using System.Net;
using System.Web;

namespace IocLifestyles
{
 public interface ISessionValidator
 {
  SessionToken ValidateSession();
 }
 public class SessionValidator : ISessionValidator
 {
  private readonly HttpContextBase httpContextBase;

  public SessionValidator(HttpContextBase httpContextBase)
  {
   this.httpContextBase = httpContextBase;
  }

  public SessionToken ValidateSession()
  {
   // Do some validation here
   var sessionToken = new SessionToken
             {
              IpAddress = IPAddress.Parse(httpContextBase.Request.UserHostAddress),
              IsValid = true
             };

   return sessionToken;
  }
 }
}
The final 2 pieces needed to actually see something in the browser is the DefaultController
using System.Web.Mvc;

namespace IocLifestyles.Controllers
{
 public class DefaultController : Controller
 {
  private readonly ISomeRepository someRepository;

  // Constructor Injection
  public DefaultController(ISomeRepository someRepository)
  {
   this.someRepository = someRepository;
  }

  public ActionResult Index()
  {
   ViewData.Model = someRepository.GetSessionToken();
   return View();
  }
 }
}

and the Views/Default/Index.cshtml view.

@model IocLifestyles.SessionToken
@{
 ViewBag.Title = "Index";
}
<h2>
 SessionToken IpAddress: @Model.IpAddress.ToString()</h2>

This is a rather contrived example, but please bear with me for the sake of demonstration purposes.

What is interesting however is what happens when we run the application the first time and contrast this to what happens when we run it a second time without rebuilding the code.

First time:


Second and subsequent times:



Playing around with this you will notice that you can display the page one time after a build, this is giving us an indication of what is wrong.


Below you can see the full stack trace with all details
Server Error in '/' Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 20:   {
Line 21:    // Do some validation here
Line 22:    var sessionToken = new SessionToken
Line 23:              {
Line 24:               IpAddress = IPAddress.Parse(httpContextBase.Request.UserHostAddress),


Source File: D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SessionValidator.cs    Line: 22

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
   Microsoft.VisualStudio.WebHost.Connection.get_RemoteIP() +0
   Microsoft.VisualStudio.WebHost.Request.GetRemoteAddress() +65
   System.Web.HttpRequestWrapper.get_UserHostAddress() +22
   IocLifestyles.SessionValidator.ValidateSession() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SessionValidator.cs:22
   IocLifestyles.SomeRepository.GetSessionToken() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\SomeRepository.cs:19
   IocLifestyles.Controllers.DefaultController.Index() in D:\Users\kst\Visual Studio 2010\projects\IocLifestyles\IocLifestyles\Controllers\DefaultController.cs:17
   lambda_method(Closure , ControllerBase , Object[] ) +96
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +55
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +263
   System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +191
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
   System.Web.Mvc.Controller.ExecuteCore() +116
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8862285
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.208

The reason this is failing is the mixing of Lifestyles in the WindsorInstaller. Lets bring up that particular code again.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>());
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

The default lifestyle is Singleton. Omitting the lifestyle on ISomeRepository will register it as a Lifestyle.Singleton. SomeRepository will be instantiated one time by Windsor and then cached internally for future use. This means that even though all the other registered Components are Lifestyle.PerWebRequest, ISomeRepository will not be able to benefit from this.

There are no warnings that helps you if you mix Lifestyles in your installers, and especially in larger projects, this can be a challenge when you start tweaking for memory/performance reasons.
You need to know how all the dependencies work, and how they are used, to be able tweak Lifestyles for components. If you do not have this knowledge the risk is very high that you will introduce bugs. My suggestion especially if you are new to ASP.NET MVC leave Lifestyles to Lifestyle.PerWebRequest for all components, unless it is very obvious that this is a real singleton component. Only start tweaking Lifestyles if performance or memory consumption becomes a problem.

Changing the installer to the following solves the problem.

using System.Web.Mvc;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using System.Web;

namespace IocLifestyles
{
 public class WindsorInstaller : IWindsorInstaller
 {
  public void Install(IWindsorContainer container, IConfigurationStore store)
  {
   // Register all controllers from this assembly
   container.Register(
    AllTypes.FromThisAssembly()
    .BasedOn<Controller>()
    .Configure(c => c.LifeStyle.PerWebRequest)
   );

   // Register HttpContext(Base) and HttpRequest(Base) so it automagically can be injected using IoC
   container.AddFacility<FactorySupportFacility>();
   container.Register(Component.For<HttpRequestBase>().LifeStyle.PerWebRequest
      .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request)));
   container.Register(Component.For<HttpContextBase>().LifeStyle.PerWebRequest
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current)));

   // Respository and Service registrations
   container.Register(Component.For<ISomeRepository>().ImplementedBy<SomeRepository>().LifeStyle.PerWebRequest);
   container.Register(Component.For<ISessionValidator>().ImplementedBy<SessionValidator>().LifeStyle.PerWebRequest);
  }
 }
}

Monday, March 14, 2011

Is throw null and throw new NullReferenceException() the same?

A few times I have seen the use of 
throw null;
where a more verbosely inclined programmer would have written 
throw new NullReferenceException();
So I set out to find out if these 2 uses indeed are equivalent.
Starting out with the code for our class, the matching generated MSIL and finally the stack trace.
using System;
namespace NullRefernceException
{
 public class Class1
 {
  public void DoSomething()
  {
   throw null;
  }
 }
}
.method public hidebysig instance void  DoSomething() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  ldnull
  IL_0001:  throw
} // end of method Class1::DoSomething
System.NullReferenceException: Object reference not set to an instance of an object.
   at NullRefernceException.Class1.DoSomething() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1.cs:line 8
   at NullRefernceException.Class1Tests.DoSomething_TestDriveNullReferenceException_ExceptionThrown() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1Tests.cs:line 15

And now for the version of the code that is using throw new NullReferenceException

using System;
namespace NullRefernceException
{
 public class Class1
 {
  public void DoSomething()
  {
   throw new NullReferenceException();
  }
 }
}
.method public hidebysig instance void  DoSomething() cil managed
{
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  newobj     instance void [mscorlib]System.NullReferenceException::.ctor()
  IL_0005:  throw
} // end of method Class1::DoSomething
System.NullReferenceException: Object reference not set to an instance of an object.
   at NullRefernceException.Class1.DoSomething() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1.cs:line 8
   at NullRefernceException.Class1Tests.DoSomething_TestDriveNullReferenceException_ExceptionThrown() in D:\Users\kst\Visual Studio 2010\projects\NullRefernceException\NullRefernceException\Class1Tests.cs:line 15


And the test used to drive

using System;
using NUnit.Framework;

namespace NullRefernceException
{
 [TestFixture]
 public class Class1Tests
 {
  [Test]
  public void DoSomething_TestDriveNullReferenceException_ExceptionThrown()
  {
   var class1 = new Class1();
   try
   {
    class1.DoSomething();
   }
   catch (Exception exception)
   {
    Console.WriteLine(exception);
   }
  }
 }
}

So from a stacktrace point of view it does not look like there is a difference but in IL there is a difference.

After going through this exercise in code I flexed my Google Fu powers :) and found more information at this link on Stackoverflow - Why does C# allow you to 'throw null'?

Saturday, March 12, 2011

IIS administration using C# - multiple websites text search and replace in physicalpath

I recently found myself in a situation where I had several different web applications that where branches/tagged/deployed as a unit. When working with several different feature branches this leads to either having quite a few individual sites in IIS or updating the configurations of the existing IIS sites when switching to another branch. Since the setup and configuration of these sites was non-trivial, I ended up wondering if I could have one setup in IIS and then just bulk update the web applications physical path using a search and replace functionality.


Initially I tried vbs, but then I found this nice dll Microsoft.Web.Administration, which allows you to perform IIS administration from C#/.NET.


We have the following file system layout



Looking at the IIS administration tool we are currently pointing to branch1.





Running the program and bulk updating one or more site's physical paths.



Looking in the IIS administration again we see that the physical path of the site has been updated.



The source code below is pretty self explanatory. (Please note that I have kept the sources to the bare minimum to illustrate working with the Web.Administration API, rather than doing null checks, array length checks, try catches ...)


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Web.Administration;

namespace UpdateIisApplicationPaths
{
 public partial class Form1 : Form
 {
  private readonly ServerManager serverManager = new ServerManager();
  public Form1()
  {
   InitializeComponent();
  }

  private void Form1_Load(object sender, EventArgs e)
  {
   foreach (var site in serverManager.Sites)
   {
    websitesListBox.Items.Add(site.Name);
   }  
  }

  private void commitChangesButton_Click(object sender, EventArgs e)
  {
   Cursor.Current = Cursors.WaitCursor;
   foreach (var sitename in websitesListBox.SelectedItems)
   {
    var physicalPath = serverManager.Sites[(string) sitename].Applications[0].VirtualDirectories[0].PhysicalPath;
    physicalPath = physicalPath.Replace(oldPhysicalSitePathTextBox.Text, newPhysicalSitePathTextBox.Text);
    serverManager.Sites[(string) sitename].Applications[0].VirtualDirectories[0].PhysicalPath = physicalPath;
   }
   serverManager.CommitChanges();
   Cursor.Current = Cursors.Default;
  }

  private void websitesListBox_SelectedIndexChanged(object sender, EventArgs e)
  {
   if (websitesListBox.SelectedItems.Count > 0)
   {
    oldPhysicalSitePathTextBox.Text =
     serverManager.Sites[(string) websitesListBox.SelectedItems[0]].Applications[0].VirtualDirectories[0].PhysicalPath;
   }
  }
 }
}

Sunday, February 27, 2011

WCF REST Exception handling deserializing with XmlSerializer

As an alternative to using the DataContractSerializer you can use the XmlSerializer in your WCF services. Assuming that you have a special need that cannot be covered by the DataContractSerializer here is a sample of how to catch and handle WCF REST faults on the client side. This provides an alternative to using the DataContractSerializer which is used in this post WCF REST Exception handlingThe WCF REST Exception handling post sets the scene for this post.

Dan Rigsbyb have a great blog posting where he compares the DataContractSerializer with the XmlSerializer, it is located here XmlSerializer vs DataContractSerializer: Serialization in Wcf.
The advantage of this version of the WcfRestExceptionHelper class is that it allows for somewhat simpler client code (compared to the version in  WCF REST Exception handling). 
To mix things up a little bit I have chosen to use the XmlSerializer instead of the DataContractSerializerWithout further ado.

WCF REST client code:

var factory = new ChannelFactory<IService1Wrapper>("Service1WrapperREST");var proxy = factory.CreateChannel();

try
{
 var serviceResult = proxy.GetProductById("1");

 // Do something with result
}
catch (Exception exceptionThrownByRestWcfCall)
{
 var serviceResult = WcfRestExceptionHelper<SampleItem[], SampleError>.HandleRestServiceError(exceptionThrownByRestWcfCall);

 // Do something with result, let higher levels in the callstack handle possible real exceptions
}
finally
{
 ((IDisposable)proxy).Dispose();
}

The WcfRestExceptionHelper class

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.ServiceModel;
using System.Text;
using System.Xml.Serialization;

namespace WcfRestClient.WcfErrors
{
 public static class WcfRestExceptionHelper<TServiceResult, TServiceFault> where TServiceFault : class
 {
  private static IDictionary<Type, XmlSerializer> cachedSerializers = new Dictionary<Type, XmlSerializer>();

  public static TServiceResult HandleRestServiceError(Exception exception)
  {
   if (exception == null) throw new ArgumentNullException("exception");

   // REST uses the HTTP procol status codes to communicate errors that happens on the service side.
   // This means if we have a teller service and you need to supply username and password to login
   // and you do not supply the password, a possible scenario is that you get a 400 - Bad request.
   // However it is still possible that the expected type is returned so it would have been possible 
   // to process the response - instead it will manifest as a ProtocolException on the client side.
   var protocolException = exception as ProtocolException;
   if (protocolException != null)
   {
    var webException = protocolException.InnerException as WebException;
    if (webException != null)
    {
     var responseStream = webException.Response.GetResponseStream();
     if (responseStream != null)
     {
      try
      {
       // Debugging code to be able to see the reponse in clear text
       //SeeResponseAsClearText(responseStream);

       // Try to deserialize the returned XML to the expected result type (TServiceResult)
       return (TServiceResult) GetSerializer(typeof(TServiceResult)).Deserialize(responseStream);
      }
      catch (InvalidOperationException serializationException)
      {
       // This happens if we try to deserialize the responseStream to type TServiceResult
       // when an error occured on the service side. An service side error serialized object 
       // is not deserializable into a TServiceResult

       // Reset responseStream to beginning and deserialize to a TServiceError instead
       responseStream.Seek(0, SeekOrigin.Begin);

       var serviceFault = (TServiceFault)GetSerializer(typeof(TServiceFault)).Deserialize(responseStream);
       throw new WcfRestServiceException<TServiceFault>() { ServiceFault = serviceFault };
      }
     }
    }
   }

   // Don't know how to handle this exception
   throw exception;
  }
  
  /// <summary>
  /// Based on the knowledge of how the XmlSerializer work, I found it safest to explicitly implement my own caching mechanism.
  /// 
  /// From MSDN:
  /// To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and 
  /// deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when 
  /// using the following constructors:
  /// 
  /// XmlSerializer.XmlSerializer(Type)
  /// XmlSerializer.XmlSerializer(Type, String)
  /// 
  /// If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, 
  /// which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned 
  /// two constructors. Otherwise, you must cache the assemblies.
  /// 
  /// </summary>
  /// <param name="classSpecificSerializer"></param>
  /// <returns></returns>
  private static XmlSerializer GetSerializer(Type classSpecificSerializer)
  {
   if (!cachedSerializers.ContainsKey(classSpecificSerializer))
   {
    cachedSerializers.Add(classSpecificSerializer, new XmlSerializer(classSpecificSerializer));
   }
   return cachedSerializers[classSpecificSerializer];
  }

  /// <summary>
  /// Debugging helper method in case there are problems with the deserialization
  /// </summary>
  /// <param name="responseStream"></param>
  private static void SeeResponseAsClearText(Stream responseStream)
  {
   var responseStreamLength = responseStream.Length;
   var buffer = new byte[responseStreamLength];
   var x = responseStream.Read(buffer, 0, Convert.ToInt32(responseStreamLength));
   var enc = new UTF8Encoding();
   var response = enc.GetString(buffer);
   Debug.WriteLine(response);
   responseStream.Seek(0, SeekOrigin.Begin);
  }
 }
}
The generic exception that we can throw

using System;
namespace WcfRestClient.WcfErrors
{
 public class WcfRestServiceException<TServiceError> : Exception where TServiceError : class
 {
  public WcfRestServiceException() : base("An service error occured. Please inspect the ServiceError property for details.")
  {
  }
  
  public TServiceError ServiceFault { get; set; }
 }
}

Visual Studio 2010 + ASP.NET MVC 3.0 + Entity Framework + Sql Server Compact 4.0 and Northwind

I wanted to play around with the latest version of SQL Server Compact Edition together with the Entities Framework in a ASP.NET MVC 3.0 site.


So I did the following:

  1. Download and install Microsoft SQL Server Compact 4.0
  2. Create a new ASP.NET MVC 3 project
  3. Copy the database file for Northwind from C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v3.5\Samples to the App_Data folder in the project.
  4. Try to generate the generate an ADO.NET Entity Data Model based on the database.

Here we encounter the first problem. The ADO.NET Entity Data Model generator in Visual Studio 2010 does not seem to support ADO.NET connection strings to the SQL Server 4.0 Compact Edition. Even adding the DbProviderFactory for SQLServer 4.0 Compact in the machine.config does not seem to work. 

To the rescue comes the command line ADO.NET Entity Data Model generator 2 source code which can be downloaded here EdmGen2.exe.
EdmGen2 is a command-line tool for the Microsoft ADO.NET Entity Framework. The tool can be used as a replacement for the EdmGen.exe tool that ships with the .Net framework 3.5 SP1. EdmGen.exe can only read and write the CSDL, SSDL & MSL file formats. However, EdmGen2.exe can read and write the EDMX file format used by the Visual Studio design tools. Additionally, EdmGen2.exe can translate between EDMX and CSDL, SSDL & MSL formats, and the source code can act as examples on using the tooling APIs defined in the System.Data.Entity.Design assembly.
The first thing I found trying to run this tool with the following command line

/ModelGen "Data Source=D:\Users\kst\Visual Studio 2010\projects\MasterDetailCrud\MasterDetailCrud\App_Data\Northwind.sdf" System.Data.SqlServerCe.4.0 Northwind

was that the database I wanted to use was a SqlServer CE 3.5 database.

This was not obvious since the EdmGen2 tool just silently failed with no output. However running it through the debugger with the above command line parameters, yielded the following error.

"error 6003: The underlying provider failed on Open.
The database file has been created by an earlier version of SQL Server Compact. Please upgrade using SqlCeEngine.Upgrade() method."

At this point in time, I am slowly beginning to wonder if going down this path using Sql Server CE is worth it (since I most likely will never use it professionally), or if I am missing something obvious (which is not entirely unlikely). But alas being stubborn I quickly created a small windows app with the following code 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlServerCe;
using System.IO;

namespace NorthwindDBUpdater
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void openDatabaseToolStripMenuItem_Click(object sender, EventArgs e)
  {
   openFileDialog1.ShowDialog(this);
  }

  private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
  {
   selectedDatabaseFileTextBox.Text = openFileDialog1.FileName;
  }

  private void updateDatabaseButton_Click(object sender, EventArgs e)
  {
   var connectionStringTemplate = "Data Source={0}";
   var saveDirectory = string.Format(@"{0}\Upgrade", Path.GetDirectoryName(openFileDialog1.FileName));

   var sourceConnectionString = string.Format(connectionStringTemplate, openFileDialog1.FileName);
   var destinationConnectionString = string.Format(connectionStringTemplate, string.Format(@"{0}\{1}",saveDirectory, Path.GetFileName(openFileDialog1.FileName)));
   if (!Directory.Exists(saveDirectory))
   {
    Directory.CreateDirectory(saveDirectory);
   }

   SqlCeEngine sqlEngine = new SqlCeEngine(sourceConnectionString);
   sqlEngine.Upgrade(destinationConnectionString);
  }

 }
}
This allowed me to update the database file to a Sql Server 4.0 compatible database.
After copying the database to App_Data and invoking the EdmGen2 tool it now worked great and I could start mapping the ADO.NET Entity models to my domain models.


I will not provide the updated Northwind database here but you can download the NorthwindDBUpdater project and update the database yourself (I guess you should be able to use it to update any CE database, not just Northwind.)


The project can be downloaded here 2011-02-27-NorthwindDBUpdater.zip

Friday, February 18, 2011

WCF REST Internal Microsoft HttpWebResponse validation rules

The posting WCF REST Exception handling deals with handling ProtocolExceptions thrown by Microsoft's WCF REST implementation. This specific ProtocolException/Exception is thrown based on rules located in various methods in the following classes/methods in the .NET framework.

private bool CompleteGetResponse(IAsyncResult result);
 
Declaring Type: System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest 
Assembly: System.ServiceModel, Version=4.0.0.0 

 
public Message WaitForReply(TimeSpan timeout);
 
Declaring Type: System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest 
Assembly: System.ServiceModel, Version=4.0.0.0 
Then you can trace the code into the various static utility methods such as

Declaring Type: System.ServiceModel.Channels.HttpChannelUtilities 
Assembly: System.ServiceModel, Version=4.0.0.0 


public static HttpWebResponse ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason);
 
public static HttpInput ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException, ChannelBinding channelBinding);

public static Exception CreateNullReferenceResponseException(NullReferenceException nullReferenceException);

Friday, February 11, 2011

HtmlHelper extension method output unencoded strings in ASP.NET MVC 3.0 Razor views

In ASP.NET MVC 1.0 when using the <%= tag you had to handle any string html encoding you wanted specifically.

This was changed in ASP.NET 2.0 when generated views introduced the <%: tag which by default would html encode your string. In ASP.NET MVC 2.0 you could use the MvcHtmlString class which allowed you to avoid html encoding a string.

With .NET 4.0 you now have another option for not html encoding strings (for instance from an HtmlHelper extension method used in a ASP.NET MVC 3.0 Razor view). The interface IHtmlString and the implementing class HtmlString allows you to indicate that a string is not to be html encoded.

public static class HtmlHelperExtensions
{
    // .NET 4.0
    public static IHtmlString EmitObjectTagUnencoded(this HtmlHelper htmlHelper, string someValue)
    {
        return new HtmlString(string.Format("<object>{0}</object>", someValue));
    }

    // ASP.NET MVC 2 
    public static MvcHtmlString EmitObjectTagUnencoded2(this HtmlHelper htmlHelper, string someValue)
    {
        return MvcHtmlString.Create(string.Format("<object>{0}</object>", someValue));
    }

    public static string EmitObjectTagEncoded(this HtmlHelper htmlHelper, string someValue)
    {
        return string.Format("<object>{0}</object>", someValue);
    }
}
Using this in a view like the following
<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
       @Html.EmitObjectTagUnencoded("EmitObjectTagUnencoded")
    </div>
    <div>
       @Html.EmitObjectTagUnencoded2("EmitObjectTagUnencoded2")
    </div>
    <div>
       @Html.EmitObjectTagEncoded("EmitObjectTagEncoded")
    </div>
</body>
</html>
Will yield the following html output
<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
       <object>EmitObjectTagUnencoded</object>
    </div>

    <div>
       <object>EmitObjectTagUnencoded2</object>
    </div>
    <div>
       &lt;object&gt;EmitObjectTagEncoded&lt;/object&gt;
    </div>
</body>

</html>

Monday, February 07, 2011

WCF REST Exception handling

WCF normally offers all the extensibility you need, but recently when implementing a WCF REST client in .NET 4.0, I found that it seems like there is at least a little inconsistency in how WCF REST handles service faults compared to other WCF implementations.


Ground rules:
In WCF it is not recommended to throw .NET exceptions since they most likely are not known and recognized in non .NET clients. so instead we are using FaultException<TDetail> and WebFaultException. The below quote is taken from the MSDN WebFaultException documentation.
When using a WCF REST endpoint (WebHttpBinding and WebHttpBehavior or WebScriptEnablingBehavior) the HTTP status code on the response is set accordingly. However, WebFaultException can be used with non-REST endpoints and behaves like a regular FaultException.

When using a WCF REST endpoint, the response format of the serialized fault is determined in the same way as a non-fault response. For more information about WCF REST formatting, see WCF REST Formatting.
Thoughts and implementation 
My intial take on how to handle service side generated faults/errors was to use the IClientMessageInspector & Message Inspectors for fault handling. However nothing seemed to work. I got a ProtocolException that was thrown from deep in the WCF REST implementation. The exception was thrown by the underlying WCF REST implementation before the IClientMessageInspector.AfterReceiveReply method was invoked. After spending some time in Reflector with a fellow developer it indeed seemed like there are no extensibility points you can hook into. As soon as a WCF REST service throws a WebFaultException with a fault indicating http response code it will trigger a ProtocolException on the WCF REST client side.


So it seems like you have to solve this with wrapping the proxy calls in a try catch block and then extract the InnerException from the ProtocolException and convert this from a Stream ... etc, etc, etc (i.e. repetitive plumbing code) . Since this plumbing code will be the same for most if not all clients, I created a helper class that should work for any service.


The code that is used here is building on code that has been explained in the following blog postings:
  1. WCF REST service with custom http header check in .NET 4
  2. WCF REST client using custom http headers
The full solution can be downloaded here WcfRestClientExceptionHandling.7z.

Try running the client form with the default app.config and then try changing
<customHttpHeaders>
 <headers>
  <add key="MyCustomHttpHeader" value="some_value"></add>
  <add key="MyCustomHttpHeader2" value="yet_another_value"></add>
 </headers>
</customHttpHeaders>
to the following
<customHttpHeaders>
 <headers>
 </headers>
</customHttpHeaders>
First let us define our service.
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Common;

namespace WcfRestService1
{
 // Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
 // NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
 // a single instance of the service to process all calls. 
 [ServiceContract]
 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
 public class Service1
 {
  [WebGet(UriTemplate = "{id}")]
  public SampleItem[] GetByProductId(string id)
  {
   if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
     throw new WebFaultException<SampleError>(new SampleError(){ErrorCode = "1223456789", Message = "The custom httpheader 'MyCustomHttpHeader' has not been set."}, HttpStatusCode.BadRequest);
   
   return new[] { new SampleItem() { Id = 1, StringValue = "Product1" } };
  }
 }
}
Looking through the code we see that there are 2 possible objects returned (ignoring all the potential unhandled exceptions). The 2 possible objects are SampleItem, SampleError.

using System.Runtime.Serialization;

namespace Common
{
 [DataContract]
 public class SampleError
 {
  [DataMember]
  public string Message { get; set; }
  [DataMember]
  public string ErrorCode { get; set; }
 }
}

using System.Runtime.Serialization;

namespace Common
{
 [DataContract]
 public class SampleItem
 {
  [DataMember]
  public int Id { get; set; }
  [DataMember]
  public string StringValue { get; set; }
 }
}
I will not get into the additional classes used to add custom http headers for the requests as they are explained in the previous indicated postings. Suffice to say that you can add and modify the headers included in the call to the WCF service by editing the customHeaders/headers element in the app.config file.

<behaviors>
 <endpointBehaviors>
  <behavior name="CustomHeaderBehavior">
   <customHttpHeaders>
    <headers>
     <add key="MyCustomHttpHeader" value="some_value"></add>
     <add key="MyCustomHttpHeader2" value="yet_another_value"></add>
    </headers>
   </customHttpHeaders>
   <webHttp/>
  </behavior>
 </endpointBehaviors>
</behaviors>
Very briefly looking at the interface used to describe the service on the client side

using System.ServiceModel;
using System.ServiceModel.Web;
using Common;

namespace WcfRestClient
{
 [ServiceContract]
 public interface IService1Wrapper
 {
  [OperationContract]
  [WebGet(
   BodyStyle = WebMessageBodyStyle.Bare,
   ResponseFormat = WebMessageFormat.Xml,
   UriTemplate = "/Service1/GetByProductId?id={id}")]
  SampleItem[] GetProductById(string id);
 }
}
Now we will look at the client code. There are a few different outcomes of a service call.


Handled by proposed helper class:
  1. Everything is OK and the call returns the expected type deserialized on our/client end
  2. Everything is not OK and the service throws a FaultException and the http status code is one of the fault status codes. This will result in the current WCF REST implementation to raise a ProtocolException. The proposed code will try to handle that.
  3. Any other Exceptions thrown when trying to handle the result or fault from the service can be caught and handled or rethrown.

Not Handled by proposed helper class:
  1. Inconsistent use of http status codes and raising FaultExceptions. (Everything is not OK and the service throws a FaultException which needs to be handled on our client end. If this is combined with a http status code of 200/OK then we expect a TServiceResult but we are getting a TServiceFault. This will throw a SerializationException in the HandleRestServiceError() mehotd. The solution proposed here will not be able to handle that case. However one could argue that that is a problem at the service level.)
using System;
using System.ServiceModel;
using System.Windows.Forms;
using Common;
using WcfRestClient.WcfErrors;

namespace WcfRestClient
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
   var factory = new ChannelFactory<IService1Wrapper>("Service1WrapperREST");
   var proxy = factory.CreateChannel();

   try
   {
    // This call can return one of the following object as a serialized response
    // If successful -> SampleItem[]
    // If error      -> SampleError
    // We can only handle SampleItem[]. If a combination of
    // a FaultException thrown + http status code OK then this code will 
    // throw a SerializationException
    var serviceResult = proxy.GetProductById("1");

    // In this case the serviceResult is returning the expected type
    HandleServiceResult(serviceResult);
   }
   catch (Exception exceptionThrownByRestWcfCall)
   {
    // There are a few different ways you can write the code below
    // Lambda expression with anonymous method
    // serviceResult =>
    //  {
    //    MessageBox.Show("ServiceResult:" + serviceResult[0].StringValue);
    //  },
    //
    // Lambda expression with named method
    // serviceResult => HandleServiceResult(serviceResult)
    //
    // .NET 4.0 MethodGroup shorthand
    // HandleServiceResult
    //
    // MethodGroup shorthand is the shortest / clearest I think but I am 
    // opting for the Lambda expression to keep the coding style the same.
    WcfRestExceptionHelper<SampleItem[], SampleError>.HandleRestServiceError(
     exceptionThrownByRestWcfCall,
     serviceResult =>
      {
       HandleServiceResult(serviceResult);
      },
     serviceFault =>
      {
       MessageBox.Show(serviceFault.Message, "ServiceFaultHandler");
      },
     exception =>
      {
       MessageBox.Show(exception.ToString(), "ExceptionHandler");
      }
     );
   }
   finally
   {
    ((IDisposable)proxy).Dispose();
   }
  }

  private static void HandleServiceResult(SampleItem[] serviceResult)
  {
   MessageBox.Show(serviceResult[0].StringValue, "ServiceResult:");
  }
 }
}
The interesting part is the following code

try
{
 var serviceResult = proxy.GetProductById("1");
 HandleServiceResult(serviceResult);
}
catch (Exception exceptionThrownByRestWcfCall)
{
 WcfRestExceptionHelper<SampleItem[], SampleError>.HandleRestServiceError(
  exceptionThrownByRestWcfCall,
  serviceResult =>
   {
    HandleServiceResult(serviceResult);
   },
  serviceFault =>
   {
    MessageBox.Show(serviceFault.Message, "ServiceFaultHandler");
   },
  exception =>
   {
    MessageBox.Show(exception.ToString(), "ExceptionHandler");
   }
  );
}
That is a lot of code for a handling the responses from a simple service call, rewriting the code a bit (removing bracketed approach in the lambdas, omitting the optional exceptionHandler Action delegate in the call, as well as using a method group shorthand we can squeeze the code down to a fairly long (unreadable) one-liner.

try
{
 var serviceResult = proxy.GetProductById("1");
 HandleServiceResult(serviceResult);
}
catch (Exception exceptionThrownByRestWcfCall)
{
 WcfRestExceptionHelper<SampleItem[], SampleError>.HandleRestServiceError(exceptionThrownByRestWcfCall, HandleServiceResult, serviceFault => MessageBox.Show(serviceFault.Message, "ServiceFaultHandler"));
}
This allows us to put the actual handling code here where the service is called, without most of the plumbing code. The implementation of HandleRestServiceError() can be seen below.
public static void HandleRestServiceError(Exception exception, Action<TServiceResult> serviceResultHandler, Action<TServiceFault> serviceFaultHandler = null, Action<Exception> exceptionHandler = null)
{
 var serviceResultOrServiceFaultHandled = false;

 if (exception == null) throw new ArgumentNullException("exception");
 if (serviceResultHandler == null) throw new ArgumentNullException("serviceResultHandler");

 // REST uses the HTTP procol status codes to communicate errors that happens on the service side.
 // This means if we have a teller service and you need to supply username and password to login
 // and you do not supply the password, a possible scenario is that you get a 400 - Bad request.
 // However it is still possible that the expected type is returned so it would have been possible 
 // to process the response - instead it will manifest as a ProtocolException on the client side.
 var protocolException = exception as ProtocolException;
 if (protocolException != null)
 {
  var webException = protocolException.InnerException as WebException;
  if (webException != null)
  {
   var responseStream = webException.Response.GetResponseStream();
   if (responseStream != null)
   {
    try
    {
     // Debugging code to be able to see the reponse in clear text
     //SeeResponseAsClearText(responseStream);

     // Try to deserialize the returned XML to the expected result type (TServiceResult)
     var response = (TServiceResult) GetSerializer(typeof(TServiceResult)).ReadObject(responseStream);
     serviceResultHandler(response);
     serviceResultOrServiceFaultHandled = true;
    }
    catch (SerializationException serializationException)
    {
     // This happens if we try to deserialize the responseStream to type TServiceResult
     // when an error occured on the service side. An service side error serialized object 
     // is not deserializable into a TServiceResult

     // Reset responseStream to beginning and deserialize to a TServiceError instead
     responseStream.Seek(0, SeekOrigin.Begin);

     var serviceFault = (TServiceFault) GetSerializer(typeof(TServiceFault)).ReadObject(responseStream);

     if (serviceFaultHandler != null && serviceFault != null)
     {
      serviceFaultHandler(serviceFault);
      serviceResultOrServiceFaultHandled = true;
     }
     else if (serviceFaultHandler == null && serviceFault != null)
     {
      throw new WcfServiceException<TServiceFault>() { ServiceFault = serviceFault };
     }
    }
   }
  }
 }

 // If we have not handled the serviceResult or the serviceFault then we have to pass it on to the exceptionHandler delegate
 if (!serviceResultOrServiceFaultHandled && exceptionHandler != null)
 {
  exceptionHandler(exception);
 }
 else if (!serviceResultOrServiceFaultHandled && exceptionHandler == null)
 {
  // Unable to handle and no exceptionHandler passed in throw exception to be handled at a higher level
  throw exception;
 }
}
After spending some time on this posting and coding it I found this forum post How to return a FaultException from a WCF client that calls a REST API. It does seem to come to a similar conclusion.

Tuesday, February 01, 2011

WCF REST client using custom http headers

This deals with using WCF as a framework to consume REST based services (where the services not necessarily are written in .NET). This is a follow up post of WCF REST service with custom http header check in .NET 4.


REST based services are to a higher degree than SOAP or other services based on the basic HTTP protocol mechanisms. This will also often mean that you are using http headers to relay information, as well as possibly cookies and also utilizing the different available request methods as per RFC for Hypertext Transfer Protocol -- HTTP/1.1 (Method Definitions).


Let us assume that we have the following REST based service.

using System.Net;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Common;

namespace WcfRestService1
{
 // Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
 // NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
 // a single instance of the service to process all calls. 
 [ServiceContract]
 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
 public class Service1
 {
  [WebGet(UriTemplate = "{id}")]
  public SampleItem[] GetProductById(string id)
  {
   if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
     throw new WebFaultException<string>("The custom httpheader 'MyCustomHttpHeader' has not been set.", HttpStatusCode.BadRequest);
   
   return new[] { new SampleItem() { Id = 1, StringValue = "Product1" } };
  }
 }
}


This service requires a http header named "MyCustomHttpHeader" is part of the request. The service does currently no care what values are sent with this header, but it needs to be part of the request.

We have defined the DataContract for SampleItem in a Common project.


using System.Runtime.Serialization;

namespace Common
{
 [DataContract]
 public class SampleItem
 {
  [DataMember]
  public int Id { get; set; }
  [DataMember]
  public string StringValue { get; set; }
 }
}


On the client side we have defined an interface that describes our service, so its methods can be accessed by client code.


using System.ServiceModel;
using System.ServiceModel.Web;
using Common;

namespace CRTest
{
 [ServiceContract]
 public interface IService1Wrapper
 {
  [OperationContract]
  [WebGet(
   BodyStyle = WebMessageBodyStyle.Bare,
   ResponseFormat = WebMessageFormat.Xml,
   UriTemplate = "/Service1/GetByProductId?id={id}")]
  SampleItem[] GetProductById(string id);
 }
}



Finally we have some client code that is trying to use our service.


using System;
using System.ServiceModel;
using System.Windows.Forms;

namespace CRTest
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
   var factory = new ChannelFactory<IService1Wrapper>("Service1WrapperREST");
   var proxy = factory.CreateChannel();
   var response = proxy.GetProductById("1");
   ((IDisposable)proxy).Dispose();
  }
 }
}


There is nothing in this code that indicates that custom headers are added, and indeed there are 3 more classes that needs to be presented and we also need to see the app.config file to get the full picture.

First let us have a look at the app.config file.



<?xml version="1.0"?>
<configuration>
 <startup>
  <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
 </startup>
 <system.serviceModel>
  <client>
   <endpoint address="http://localhost:62510"
        binding="webHttpBinding"
        contract="CRTest.IService1Wrapper"
        name="Service1WrapperREST"
        behaviorConfiguration="CustomHeaderBehavior" />
  </client>
  <behaviors>
   <endpointBehaviors>
    <behavior name="CustomHeaderBehavior">
     <customHttpHeaders>
      <headers>
       <add key="MyCustomHttpHeader" value="some_value"></add>
       <add key="MyCustomHttpHeader2" value="yet_another_value"></add>
      </headers>
     </customHttpHeaders>
     <webHttp/>
    </behavior>
   </endpointBehaviors>
  </behaviors>
  <extensions>
   <behaviorExtensions>
    <add name="customHttpHeaders" type="CRTest.CustomHeaderBehaviorExtensionElement, CRTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
   </behaviorExtensions>
  </extensions>
 </system.serviceModel>
</configuration>


Looking at the system.servicemodel/client/endpoint we see nothing unusual in the first 4 lines, but then I have added a behaviorConfiguration named CustomHeaderBehavior.

When we continue down through the config file and at system.servicemodel/behaviors/endpointBehaviors/behavior name="CustomHeaderBehavior" we have an element named customHttpHeaders which basically define all the custom headers that we want to include in our REST request.

Finally in the config file we see that a behaviorExtensions has been added to add support for these new customHttpHeaders xml elements in our configuration file.

Let us start with the CRTest.CustomHeaderBehaviorExtensionElement class.


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.ServiceModel.Configuration;

namespace CRTest
{
 public class CustomHeaderBehaviorExtensionElement : BehaviorExtensionElement 
 {
  protected override object CreateBehavior()
  {
   Dictionary<string, string> customHeaders = null;
   if (CustomHeaders != null)
   {
    customHeaders = CustomHeaders.AllKeys.ToDictionary(key => key, key => CustomHeaders[key].Value);
   }
   return new CustomHeaderBehavior(customHeaders);
  }

  public override Type BehaviorType
  {
   get { return typeof (CustomHeaderBehavior); }
  }

  [ConfigurationProperty("headers", IsRequired = true)]
  [ConfigurationCollection(typeof(KeyValueConfigurationCollection))]
  public KeyValueConfigurationCollection CustomHeaders
  {
   get
   {
    return (KeyValueConfigurationCollection) base["headers"];
   }
  }
 }
}


Starting from the bottom of the class and moving up we see the CustomHeaders property which is tied to the headers XML element in the config file. Since we have used the XML attribues key/value we are returning a KeyValueConfigurationCollection. This collection is rather specific to configuration and config files and I do not want that being passed around in the application.

That is why I in the CreateBehavior() converts it into a Dictionary<string, string> customHeaders.

Then I return a new instance of the CustomHeaderBehavior which as an argument in the constructor takes the custom headers as a Dictionary<string, string>.


using System.Collections.Generic;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace CRTest
{
 public class CustomHeaderBehavior : IEndpointBehavior
 {
  private readonly IDictionary<string, string> customHttpHeaders;

  public CustomHeaderBehavior(IDictionary<string, string> customHttpHeaders)
  {
   this.customHttpHeaders = customHttpHeaders;
  }

  public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
  {
   var customHeaderMessageInspector = new CustomHeaderMessageInspector(customHttpHeaders);
   clientRuntime.MessageInspectors.Add(customHeaderMessageInspector);
  }

  public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
  {
  }

  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
  {
  }

  public void Validate(ServiceEndpoint endpoint)
  {
  }
 }
}


In ApplyClientBehavior() we add a MessageInspector of type CustomHeaderMessageInspector and this is the class that is actually adding those custom headers to the request.


using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace CRTest
{
 public class CustomHeaderMessageInspector : IClientMessageInspector
 {
  private readonly IDictionary<string, string> customHttpHeaders;

  public CustomHeaderMessageInspector(IDictionary<string,string> customHttpHeaders)
  {
   if (customHttpHeaders == null) throw new ArgumentNullException("customHttpHeaders");
   this.customHttpHeaders = customHttpHeaders;
  }

  public object BeforeSendRequest(ref Message request, IClientChannel channel)
  {
   // Making sure we have a HttpRequestMessageProperty
   HttpRequestMessageProperty httpRequestMessageProperty;
   if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
   {
    httpRequestMessageProperty = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
    if (httpRequestMessageProperty == null)
    {
     httpRequestMessageProperty = new HttpRequestMessageProperty();
     request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessageProperty);
    }
   }
   else
   {
    httpRequestMessageProperty = new HttpRequestMessageProperty();
    request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessageProperty);
   }

   // Add custom headers to the WCF request
   foreach (var header in customHttpHeaders)
   {
    httpRequestMessageProperty.Headers.Add(header.Key, header.Value);
   }
   
   return null;
  }

  public void AfterReceiveReply(ref Message reply, object correlationState)
  {
  }
 }
}


I case you are interested in the solution file it can be downloaded here WCFCustomHeaderClient.zip.

Debugging XML deserialization issues using XmlSerializer when using REST through WCF

This url Troubleshooting Common Problems with the XmlSerializer holds some really useful information when you encounter deserialization issues when working with REST, WCF and .NET 4.0 (and XmlSerialization in general).


Saturday, January 29, 2011

WCF REST service with custom http header check in .NET 4

This is the posting I initially intended to write when I started writing WCF REST and .NET 4.0.

This posting outlines how to make a simple http header check in the WCF REST based service and depending on the the outcome of the header evaluation either return the result or throw an WebFaultException.

This WCF service is built using .NET 4.0 only without using the WCF REST starter kit (see more information here REST in Windows Communication Foundation (WCF) and here WCF REST Starter Kit Preview 2.


Start out by making a new project in Visual Studio, choose "Online Template" and select the "WCF" sub category. Select "WCF REST Service Template 40".




Change the code of the Service1.cs file to look like the following.


using System.Net;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace WcfRestService1
{
 // Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
 // NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
 // a single instance of the service to process all calls. 
 [ServiceContract]
 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
 public class Service1
 {
  [WebGet(UriTemplate = "{id}")]
  public List<SampleItem> GetProductById(string id)
  {
   if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
    throw new WebFaultException<string>("The custom httpheader 'MyCustomHttpHeader' has not been set.", HttpStatusCode.BadRequest);
   
   return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Product1" } };
  }
 }
}

Build the solution and try to access the url http://localhost:some_random_dev_web_server_port/Service1/GetProductById?id=1





This was kind of expected, but notice how neat this is tying in with the http request return codes.

If we look at this in Fiddler we will see the following.



As expected according to our code in the service 


if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
                throw new WebFaultException<string>("The custom httpheader 'MyCustomHttpHeader' has not been set.", HttpStatusCode.BadRequest);


If we now use the Request Builder in Fiddler and add the custom http header "MyCustomHttpHeader" we will see the following result in Fiddler.




If you want to let headers flow back and forth between clients and the services your best option is to add some new classes implementing the interfaces IClientMessageInspector, IEndpointBehavior and if you want this to be configurable from the .config file you need to extend the base class BehaviorExtensionElement.

You can see a sample implementation here WCF REST client using custom http headers

WCF REST and .NET 4.0

REST  and SOAP have long been available as specifications how to access and interact with services published on the internet (or intra- /extra- net). Yahoo, Google and Amazon Web Services have long been using REST as the primary way to expose different APIs. In the .NET world we initially had SOAP based web service support built into Visual Studio (.NET / 2003 / 2005), meaning that we could point Visual Studio to a WSDL file and generate the needed code to interact with this service. You could use a REST based web service using the .NET framework by manually using a combination of HttpWebRequest, HttpWebResponse and generating supporting classes for the returned XML using xsd.exe, but there was no built in support for REST based services in the IDE.

With the revealing of the new API codenamed "Indigo" the implementation of the WS* standards into an easy and coherent programming model, as well as incorporating consuming any service no matter where it was located (In process, webservice ... ) using the same programming model, WCF was born and released with .NET 3.0.

In the WCF programming model it does not matter where the service is located. The same unchanged client code can communicate with a service located in the same app domain, across app domains but in the same process, or inter process on the same machine. The same client code can also consume and use a services on different machine either on a LAN or across the inter-, intra-, extra- net.

Juval Löwy has a great note about this in his book Programming WCF Services.

Conceptually, even in C# or VB, there are endpoints: the address is the memory address of the type’s virtual table, the binding is CLR, and the contract is the interface itself. Because in classic .NET programming you never deal with addresses or bindings, you take them for granted, and you’ve probably gotten used to equating in your mind’s eye the interface (which is merely a programming construct) with all that it takes to interface with an object. The WCF endpoint is a true interface because it contains all the information required to interface with the object. In WCF, the address and the binding are not preordained and you must specify them.
Obviously due to the physical differences in how the messages are transported from client to service there are circumstances that need to taken into account. A slow WCF service located across the world, should limit the round trips as much as possible and make sure that the OperationContract is not a "chatty one". Funny enough this applies equally well for the service located in the same app domain in the same process but for a different reason. In the remote scenario it is due to performance, in the same app domain the reason is to achieve an location agnostic service, which can be moved to a remote location only by changing the endpoint  in the configuration file. This is not enforced by the framework but is good programming practices.

Now with .NET 4.0 we have built in support for calling and consuming REST based web service. However especially if you rely on http headers to transfer custom meta information to the service you will have to dive into the extensibility points of WCF. Initially this posting was supposed to be concerning that subject specifically but seeing how it ended up being more of a history lesson of WCF, I have posted that as a separate post which is located here WCF REST service with custom http header check in .NET 4