Friday, 18 September 2009

Injecting service certificates into a WCF end point using Windsor’s WcfIntegration

I recently hit an issue whilst using Windsor’s WCF Integration Facility (see previous post on configuring the the facility) to create a WCF end point. Previously the WCF integration was working fine but I had to change the binding to a wsHttpBinding and use a mutual certificate to secure the message. Normally you would setup the endpoint binding to load the required certificate out of the machines certificate store, my problem was that the certificate was not  in the machines local store and needed to be loaded of disk.

The first thing to do is configure what you can in the configuration file, in my case it was setting up the wsHttpBinding.
<ws2007HttpBinding>
    <binding name="MyCustomServiceBinding">
        <security mode="Message">
            <message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false" />
        </security>
    </binding>
</ws2007HttpBinding>
This configures the service to use a certificate client credential type but if we were to run the service now we would get an Exception saying that no Service certificate has been specified. This is where we need to write some code and have Windsor inject it into the service host factory. To do this we need to create an end point behaviour using the IEndpointBehavior interface defined in the System.ServiceModel assembly. The method we are interested in is the AddBindingParameters method which allows us to add custom data which is added to the binding at runtime. One point to note that you should not manipulate the endpoint directly, if you do the execution behaviour is undefined.
public class MyCustomEndPointBehavior : IEndpointBehavior
{
    public void Validate(ServiceEndpoint endpoint) {}
 
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        var serviceCredentials = bindingParameters.Remove<ServiceCredentials>();
        serviceCredentials = serviceCredentials == null ? new ServiceCredentials() : serviceCredentials.Clone();
        serviceCredentials.ServiceCertificate.Certificate = new X509Certificate2(@"C:\FilePath\Cert.pfx","CertPassword",X509KeyStorageFlags.MachineKeySet);
        bindingParameters.Add(serviceCredentials);
    }
 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {}
 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {}
}
What we do is look to see if there is a ServiceCredentials object in the binding parameter collection creating one if there is not and add our certificate as the ServiceCertificate. It is worth noting that this code will be run for all end points so if you have more than one you will need to use something to identify the end points you are interested such as the end points contract type.

Finally we need to wire the end point behaviour into Windsor, this is as simple as registering the type.
var myCustomEndpointBehavior = new MyCustomEndPointBehavior();
 
container.AddFacility<WcfFacility>().Register(
    Component.For<IEndpointBehavior>().Instance(myCustomEndpointBehavior),
    Component.For<IMyCustomService>().ImplementedBy<MyCustomService>());
 
DefaultServiceHostFactory.RegisterContainer(container.Kernel);
You are not limited to using the IEndpointBehavior, WCF also provides the IServiceBehavior interface which interacts at the service level (what’s in a name?). This works on the same principle but gives you access to the service host base class object but the same principles apply and again modifying the host directly will have an undefined execution behaviour.

Thursday, 17 September 2009

Using Windsor to inject dependencies into your WCF services with WCF Integration Facility

IoC is pretty cool but sometimes you can’t use it straight out of the box with say something like WCF. Well now you can thanks to Ayende Rahien. Windsor contains a WCF Integration Facility that provides a WCF ServiceHostFactory which is used to create a service host for your service and injects any dependencies registered in Windsor. This is frighteningly simple to configure as you will see.

First define your interface and implement it in your service and expose your dependencies in your class constructor as you would normally.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    void SomeAction();
}
 
public class MyService : IMyService
{
    private readonly IDependancy dependancy;
 
    public PrintJobNotificationService(IDependancy dependancy)
    {
        this.dependancy = dependancy;
    }
 
    public void SomeAction()
    {
        //Do something intelligent
    }
}

If you are exposing the service as a web service using an svc file you will need to configure it to use the Windsor ServiceHostFactory. It is important to note that the name you use for the service should be the full type name less the assembly otherwise Windsor will not be able to find it. You can use a friendly string name but you will have to name your type when you register it with Windsor.

<%@
    ServiceHost Service="MyService"
    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
%>

Otherwise you will need to instantiate it in code.

using(var serviceHost = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory().CreateServiceHost(typeof(WCFServices.IMyWCFService).AssemblyQualifiedName, new Uri[0]))
{
    serviceHost .Open();
}

Now you need to wire up Windsor with your service type and any dependencies as well as adding the WCF facility. You must also register your container with the Windsor’s service host factory which you can do via the static RegisterContainer on the DefaultServiceHostFactory.

container.AddFacility<WcfFacility>()
         .AddComponent<IDependancy, DependancyImplementation>()
         .Register(Component.For<IPrintJobNotificationService>().ImplementedBy<PrintJobNotificationService>());
 
DefaultServiceHostFactory.RegisterContainer(container.Kernel);

Finally you will need to configure your WCF components in the app/web.config. You can configure your endpoints and behaviours via Windsor but that is a topic for another post.

Wednesday, 9 September 2009

Generic configuration element collection

Tiered of endlessly writing your custom ConfigurationElementCollection classes and duplicating your code. Well so was I which is why I ended up abstracting out the core functionality into an abstract base class. This is a similar approach to the one Richard Adleta  used in his post on A generic ConfigurationElementCollection implementation but with some differences.

public abstract class BaseConfigurationElementCollection<TConfigurationElementType> : ConfigurationElementCollection, IList<TConfigurationElementType> where TConfigurationElementType : ConfigurationElement, IConfigurationElementCollectionElement, new()
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new TConfigurationElementType();
    }
 
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((TConfigurationElementType)element).ElementKey;
    }
 
    #region Implementation of IEnumerable<TConfigurationElementType>
 
    IEnumerator<TConfigurationElement> IEnumerable<TConfigurationElement>.GetEnumerator()
    {
        foreach (TConfigurationElement type in this)
        {
            yield return type;
        }
    }
 
    #endregion
 
    #region Implementation of ICollection<TConfigurationElementType>
 
    public void Add(TConfigurationElementType configurationElement)
    {
        BaseAdd(configurationElement, true);
    }
 
    public void Clear()
    {
        BaseClear();
    }
 
    public bool Contains(TConfigurationElementType configurationElement)
    {
        return !(IndexOf(configurationElement) < 0);
    }
 
    public void CopyTo(TConfigurationElementType[] array, int arrayIndex)
    {
        base.CopyTo(array, arrayIndex);
    }
 
    public bool Remove(TConfigurationElementType configurationElement)
    {
        BaseRemove(GetElementKey(configurationElement));
 
        return true;
    }
 
    bool ICollection<TConfigurationElementType>.IsReadOnly
    {
        get { return IsReadOnly(); }
    }
 
    #endregion
 
    #region Implementation of IList<TConfigurationElementType>
 
    public int IndexOf(TConfigurationElementType configurationElement)
    {
        return BaseIndexOf(configurationElement);
    }
 
    public void Insert(int index, TConfigurationElementType configurationElement)
    {
        BaseAdd(index, configurationElement);
    }
 
    public void RemoveAt(int index)
    {
        BaseRemoveAt(index);
    }
 
    public TConfigurationElementType this[int index]
    {
        get
        {
            return (TConfigurationElementType)BaseGet(index);
        }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }
 
    #endregion
}

The difference between mine and Richard’s post is that my class inherits from IList<T>  and I don’t override the CollectionType property on the base class. I felt this should be done at the implementation as you also need to define the collection type in the ConfigurationCollection attribute.

The one thing that I hadn’t thought of and I borrowed from Richard was to make the generic type be an implementation of an interface for getting the elements key, in my example this is the IConfigurationElementCollectionElement interface.

Now when you want to create a configuration collection you are just left with defining the ConfigurationCollection attribute and the CollectionType and ElementName methods.

[ConfigurationCollection(typeof(CustomConfigurationElement), AddItemName = CONST_ELEMENT_NAME, CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class CustomConfigurationCollection : BaseConfigurationElementCollection<CustomConfigurationElement>
{
    #region Constants
    private const string CONST_ELEMENT_NAME = "Custom";
    #endregion
 
    public override ConfigurationElementCollectionType CollectionType
    {
        get
        {
            return ConfigurationElementCollectionType.BasicMap;
        }
    }
 
    protected override string ElementName
    {
        get { return CONST_ELEMENT_NAME; }
    }
}

Happy configuring.

Edit:
Thanks to BozoJoe and britman for pointing out that my initial implementation of the IEnumerable<>GetEnumerator() was broken and they were getting a StackOverflow which was because it was recursively calling itself . I have now updated the post to fix this.

Friday, 12 June 2009

Project assembly reference fun and games

We just had an issue with the build of one of our applications on our CI server. The build in question no longer contained an assembly in the bin folder where previously it had.

Pinpointing the issue

At first I couldn’t understand why the assembly was not in the bin folder as the assembly was clearly marked in Visual Studio as “Copy Local = true”. I then looked through the build history to see when the assembly was last published but instead of finding a point in time that it stopped working I found that the issue only occurred on one of our build agents. Two of the three build agents correctly publish the assembly but the other one did not.

The next step was to compare the configuration of the three build agents. The difference was that the two build agents that worked did not have the specific assembly in the GAC where the failing one did. But hang on a minute “Copy Local = true” should still copy the assembly into the bin folder whether referencing a assembly on the file system or in the GAC (try setting the System assembly to “Copy Local = true”).

Investigating the Issue

My first thought was to remove the assemblies from the GAC on the failing build agent but the voice in my head kept saying “This should work dam it” so instead I cracked open the project file. The first thing I noticed was that on some of the assembly references there was an inner element called private which was set to true where as others, including the affected assembly, had no element:

<Reference Include="Ass1">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>c:\Path\Ass1.ddl</HintPath>
</Reference>
<Reference Include="Ass2">
    <SpecificVersion>False</SpecificVersion>
    <HintPath>c:\Path\Ass2.dll</HintPath>
    <Private>True</Private>
</Reference>

BUT they both show up Visual Studio as “Copy Local = true”. So to test how the project file works I set the System assembly to be local as well and sure enough the inner element “Private” with a value of true appears in the project file where before there was none. As expected when built the System.dll was output to the bin folder. However the curious thing was after reverting the System assembly back to “Copy Local = false” the element was not removed instead the value was changed to false.
So my final step was to add the “Private” element to the affected assembly reference and set its value to true, commit the changes to code repository and force a build on the build agent in question and low and behold it worked.

To see how the project file got into this state I tried adding assembly references to a dummy project where some assemblies were in the GAC and some were not. My results show that if you add an assembly reference from the file system then the Copy Local value is implied as no Private element is added to the assembly reference. The Visual Studio UI will show a value of false if the assembly is in the GAC and true if it is not. What this means is that the build output will be different for different environments.

The work around

The only way round this is either to edit the project file manually or to set the Copy Local value to false and then back to true again when adding a reference to the project which you do want included in the build output.

Wednesday, 10 June 2009

ClickOnce updates via authentication proxy

(Disclaimer: This is my first blog post)

You may be aware that ClickOnce installation and updating is not supported via proxy servers that require authentication credentials other than the users default credentials.

http://social.msdn.microsoft.com/Forums/en-US/winformssetup/thread/82be8797-f14f-4db1-acb8-3206881cc567.

The thread suggests that there is hot fix but as far as I am aware this does not fix the issue which is also highlighted at the end of the thread.

I came across this very issue working on a project for a client who required the application we were writing for them to run inside various different environments using varying proxy servers and configurations. In order to accommodate this we allowed the user to either use the proxy settings provided in IE or to be able to override this with custom proxy settings. This worked fine for WCF, HTTP calls and even for creating BITS jobs but we were unable to get ClickOnce updates working.

And it was all because of this little gem in the System.Deployment.SystemNetDownloader:

protected void DownloadSingleFile(FileDownloader.DownloadQueueItem next)
{
    ...
 
    IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy;
 
    if (defaultWebProxy != null)
    {
        defaultWebProxy.Credentials = CredentialCache.DefaultCredentials;
    }
 
    ...
}

This means that every time .Net tries to download a file via the SystemNetDownloader it is overwriting the credentials on the default web proxy with the users default credentials.

In order to work around this short sighted implementation I created a wrapper around the WebProxy object which implemented the IWebProxy interface, the important part here was to specifically do nothing with the Set on the Credentials property and provide a alternative way of setting the proxy credentials:

public class CustomWebProxy : IWebProxy
{
    private WebProxy webProxy;
 
    public CustomWebProxy(string serverName, int port)
    {
        webProxy = new WebProxy(serverName, port);
        webProxy.UseDefaultCredentials = false;
    }
 
    public ICredentials Credentials
    {
        get { return webProxy.Credentials; }
        set { } //The important part
    }
 
    public void SetCredentials(ICredentials credentials){ … }
    public bool BypassProxyOnLocal { … }
    public Uri GetProxy(Uri destination) { … }
    public bool IsBypassed(Uri host) { … }
    public bool UseDefaultCredentials { … }
    public Uri Address { … }
}

The final piece of the puzzle is to setup the proxy, the following should be placed at an appropriate place in the application workflow:

var networkCredential = new NetworkCredential("UserId", "Password");
var proxy = new CustomWebProxy("server", 8080);
proxy.BypassProxyOnLocal = false;
proxy.SetCredentials(networkCredential);
WebRequest.DefaultWebProxy = proxy;

It is worth pointing out that this only solves the issue with ClickOnce and proxy authentication once the application is installed you will still need to find away to get the application on to the users computer first, distribute by CD for example.

Bro Num