Wednesday, September 18, 2013

Wcf, wif and azure acs

After struggling with federated identity with wcf services for a couple of days I finally got it to work. The documentation for wif 4.5 was, to say the least, really thin. Got some tips from tinktecture and other blogs and are ready to do the next post in the Wcf series. Hope you find it useful

Wednesday, September 11, 2013

How to programmatically configure WCF services and clients at runtime pt. 2.


In this post we will add support for a more advanced configuration management and really take control of WCF. We will also add support for REST service endpoints.

Centralized configuration – the simple version

For our “late configuration” of WCF, we want to add a shared configuration store that all components in our system utilizes. In this example, we will use XML and xpath to create a versioned configuration store with inheritance. With inheritance, we mean that data is inherited from the parent data set unless it is overridden in the children. A configuration set represents a runtime environment like dev, test or prod.

The basic structure
The xml file consists of one or more ConfigurationSet, which may contain as many services as needed. A service consist of one or more endpoints with the appropriate binding configuration settings.



When we are reading from the file we use the value from the first set that has a value in the requested node.

public string GetValue(string expression)
        {
            return GetValueFromVersion(expression, Version);
        }
 
private string GetValueFromVersion(string expression, string version)
        {
            if (string.IsNullOrEmpty(version)) return null;
            var expr = CreatExpression(expression, version);
            var iterator = Navigator.Select(expr);
            if (iterator.MoveNext())
                return iterator.Current.Value;
            if (expression == "ParentSet") return null;
            return GetValueFromVersion(expression, GetParent(version));
        }
 
public IEnumerable GetValues(string expression)
        {
            var expr = CreatExpression(expression, Version);
            var iterator=Navigator.Select(expr);
            var list=new List();
            while (iterator.MoveNext())
            {
                list.Add(iterator.Current.Value);
            }
            return list;
        }
 
private XPathExpression CreatExpression(string expression, string version)
        {
            var expr = Navigator.Compile(FormatExpression(expression, version));
            return expr;
        }
 
//Creates an xpath expression by combining an incoming expression part with the set selector query
private static string FormatExpression(string expression, string version)
        {
            var expr = string.Format("ConfigurationSets/ConfigurationSet[SetName='{0}']/{1}", version, expression);
            return expr;
        }
 

To make it easy to create the needed expressions we create our own little expression builder.

public static class ExpressionBuilder
    {
        public static string GetEndpointNames(string serviceName)
        {
            return string.Format("Services/EndpointConfig[ServiceName='{0}']//Endpoint/EndpointName", serviceName);
        }
 
        public static string GetEndpointConfigValue(string serviceName, string bindingName, string attributeName)
        {
            return string.Format("Services/EndpointConfig[ServiceName='{0}']//Endpoint[EndpointName='{1}']/{2}", serviceName, bindingName, attributeName);
        }
 
        public static string GetClientEndpoint(string serviceName)
        {
            return string.Format("Services/EndpointConfig[ServiceName='{0}']/ActiveEndpoint", serviceName);
        }
    }

With this, we have the necessary code to read config settings and use it in our configuration code.
 First we create a helper class that loads and initializes our configuration store. Note that this helper should include some kind of caching mechanism that allows the application to get new settings without restart.

internal static class ConfigurationReader
    {
        internal static VersionedDocumentReader Reader;
 
        static ConfigurationReader()
        {
            Reader = new VersionedDocumentReader();
            Reader.Load(ConfigurationManager.AppSettings["ConfigPath"]);
            Reader.SetVersion(ConfigurationManager.AppSettings["ConfigSet"]);
        }
    }

To make it easier to configure and name the services we add a new attribute that sets the service name on the interface. We access this attribute instance at runtime using reflection and read the service name. If the service interface doesn’t have this attribute set we use the interface name as the service name.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
    public sealed class ServiceNameAttribute : Attribute
    {
        public string ServiceName { get; private set; }
 
        public ServiceNameAttribute(string serviceName)
        {
            ServiceName = serviceName;
        }
    }

Changes to the code.

We need to pass the service name to the binding creators so they can find the correct settings to use during configuration of the binding.

public interface IBindingBuilder
    {
        Binding CreateBinding(string serviceName);
    }

Then we add a helper method to the binding builders to read data from the configuration store and inject the binding name.

private static string GetValue(string serviceName,string valueName)
        {
            return ConfigurationReader.Reader.GetValue(ExpressionBuilder.GetEndpointConfigValue(serviceName, "basic", valueName));
        }


public Binding CreateBinding(string serviceName)
        {
            return new BasicHttpBinding
            {
                Name = "basic",
                AllowCookies = false,
                HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                MaxBufferPoolSize = int.Parse(GetValue(serviceName,"MaxBufferPoolSize")),
                MaxReceivedMessageSize = int.Parse(GetValue(serviceName, "MaxReceivedSize")),
                MessageEncoding = (WSMessageEncoding)Enum.Parse(typeof(WSMessageEncoding), GetValue(serviceName,"MessageFormat")),
                TextEncoding = Encoding.GetEncoding(GetValue(serviceName, "TextEncoding")),
                ReaderQuotas = XmlDictionaryReaderQuotas.Max,
                BypassProxyOnLocal = true,
                UseDefaultWebProxy = false
            };
        }

And we add a new class for creating a REST binding

internal class RestBindingBuilder:IBindingBuilder
    {
        public Binding CreateBinding(string serviceName)
        {
            var binding = new WebHttpBinding(WebHttpSecurityMode.None)
                              {
                                  AllowCookies = false,
                                  HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                                  MaxBufferPoolSize = int.Parse(GetValue(serviceName, "MaxBufferPoolSize")),
                                  MaxReceivedMessageSize = int.Parse(GetValue(serviceName, "MaxReceivedSize"))
                              };
            return binding;
        }
 
        private static string GetValue(string serviceName, string valueName)
        {
            return ConfigurationReader.Reader.GetValue(ExpressionBuilder.GetEndpointConfigValue(serviceName, "rest", valueName));
        }
    }

For the WebHttpBinding to work we need to do some additional changes to the code, I will comment this when we get to these parts later.
We also need to read the address from the configuration store by changing the AddressHelper class to take the service name and use this to look for the value in the xml file.

internal static string GetFormattedAddress(string bindingType,string serviceName)
        {
            return String.Format(ConfigurationReader.Reader.GetValue(ExpressionBuilder.GetEndpointConfigValue(serviceName, bindingType, "Address"))) + "/" + bindingType;
        }

Update ServiceConfigurationImp to get the service name and pass it to the binding builders.
Add a method called GetServiceName. You need to get the service interface from the service type. I have done this the quick and dirty way her and assuming that the serviceType only implements one service interface. It the interface is decorated with the ServiceName attribute we use the value from it, else we use the name of the serviceType.

private string GetServiceName(Type serviceType)
        {
            var attrib = serviceType.GetInterfaces()[0].GetAttribute();
            if (attrib == null) return serviceType.Name;
            return attrib.ServiceName;
        }

 

Update the GetBindingTypes to read from the configuration store and not the config file as in the previous post.

private static IEnumerable GetBindingTypes(string serviceName)
        {
            var bindingTypes = ConfigurationReader.Reader.GetValues(ExpressionBuilder.GetEndpointNames(serviceName));
            return bindingTypes;
        }

Update CreateEndpoint to support WebHttpBinding, where we set the default response format to json.

private static ServiceEndpoint CreateEndpoint(Binding binding, EndpointAddress address, ContractDescription cd)
        {
            if (binding is WebHttpBinding)
                return new WebHttpEndpoint(cd, address)
                           {
                               HelpEnabled = true,
                               DefaultOutgoingResponseFormat = WebMessageFormat.Json,
                               Binding = binding
                           };
            return new ServiceEndpoint(cd, binding, address);
        }

This is basically the changes needed for the service side of WCF.
On the client side we only need to do one small change in ServiceClientContainer. It also needs to get the service name from the attribute and we need to get the active client binding from the configuration store.

private string GetServiceName()
        {
            var serviceType = typeof(T);
            var attrib = serviceType.GetAttribute();
            if (attrib == null) return serviceType.Name;
            return attrib.ServiceName;
        }

 
internal ServiceClientContainer()
        {
            ServiceName = GetServiceName();
            BindingType = GetBindingType();
            Url = AddressHelper.GetFormattedAddress(BindingType,ServiceName);
        }

 To enable support for rest we change the Initialize method

public ServiceClientContainer Initialize()
        {
            ClientFactory = CreateChannelFactory(ServiceName, Url);
            if (ClientFactory.Endpoint.Binding is WebHttpBinding)
                ClientFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());
            return this;
        }

Updating the config files
There are just a few things we need to change in the config files for the client and service. We need to add references to the location of the xml configuration file and which set to use.

    <add key="ConfigPath" value="C:\Settings\sentralConfiguration.xml"/>
    <add key="ConfigSet" value="Demo"/>

Download the code here: http://jmp.sh/b/k0b3LRA0jxOz83L4baQ8

Tuesday, September 3, 2013

How to programmatically configure WCF services and clients at runtime pt. 1.


Windows Communication Foundation (WCF) is a framework from Microsoft that helps developers build (web) services. WCF serves as an abstraction layer and allows the developer to focus on _what_ to build, not on all the how’s, if’s and but’s. Choosing transport, protocol and security is done later [config time].
In this post, we will look into how to configure WCF programmatically and postpone the choices to run-time. Note that the service needs to recycle in order to obtain new config settings.
One challenge we meet in software development is configurations sets that change from development, test and production environments. Getting all the endpoints and settings correct in each environment is time consuming and error prone.

One solution is to centralize the configuration and introduce environmental variables to the server images. Let us say that we create a windows server image and inject an appSettings value for environment e.g. development. And we also might want to add a value that can resolve the correct url’s for the services and endpoints needed in a given environment. Add these settings to the machine.config file of your server image, this will make the settings available to all services and applications running on the server.

<add key="Environment" value="Dev" >
<add key="UrlPrefix" value="Dev." >
var endpointUrl=String.Format(“http://{0}MyService.MyCompany.com/Service.svc”,ConfigurationManager.AppSettings[“UrlPrefix”]);

 
This neat little trick makes deployment easy and no configuration transformation is needed. However, you are still stuck with the wcf configuration from your development environment, unless you use config transformations. Config transformations are still a static approach, changing the settings means that you need to change the transformation and update the config file in your service and the service clients.
This is where we will start to play with WCF and configuring this runtime.

The service:

In this post we’ll only cover .svc hosted services. First you need to create a service host factory, which is responsible for creating the service host. During creation of the service host you can configure the service and the available endpoints.

Please note that the sample code uses the really poor man’s IoC (switch - new), in real life scenarios change this to your preferred IoC container. In my production version of this, I use a custom lightweight IoC container.

Service Host Factory

To be able  to configure the service at runtime you need to create a new service host factory. Do this by overriding ServiceHostFactory’s CreateServiceHost method. In this method you can control all aspects of the service you are hosting.
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var serviceHost = new ServiceHost(serviceType, baseAddresses);
            var configurator = CreateConfigurator();
            configurator.ConfigureServiceHost(serviceHost, serviceType);
            SetBehavior(serviceHost);
            return serviceHost;
        }

First you create the service host, just ‘new up’ the WCF default implementation. We will add the endpoints to this later.

To prepare for more advanced scenarios in later posts we will create an interface to handle the configuration of the endpoints. Create an interface, IServiceConfiguration, with a method called ConfigureServiceHost.

After the endpoints have been added to the service host, we want to set some behavior for the service, like open and close timeout values.

Building the endpoints

Each endpoint has its own binding, all bindings share the same base type, Binding. This allows us to create an abstraction over this using an interface, IBindingBuilder.

var bindingTypes = ConfigurationManager.AppSettings["bindingTypes"].Split(';');
            var contractDescription = ContractDescription.GetContract(serviceType.GetInterfaces()[0]);
            contractDescription.Namespace = "http://demo.wcf.org/" + serviceType.Name;
            foreach (var bindingType in bindingTypes)
            {
                var bindingBuilder = GetBindingBuilder(bindingType);
                var binding = bindingBuilder.CreateBinding();
                var endpoint = CreateEndpoint(binding, new EndpointAddress(GetFormattedAddress(bindingType)), contractDescription);
                serviceHost.AddServiceEndpoint(endpoint);
            }
 
private static ServiceEndpoint CreateEndpoint(Binding binding, EndpointAddress address, ContractDescription cd)
        {
            return new ServiceEndpoint(cd, binding, address);
        }

 Create one binding builder for each endpoint type you need your service to support. In this sample, I have created the BasicHttpBinding and WSHttpBinding as MSMQ and NET.TCP is not supported in IIS Express or the Web Dev Server.

class BasicBindingBuilder : IBindingBuilder
    {
        public Binding CreateBinding()
        {
            return new BasicHttpBinding
            {
                Name = "basic",
                AllowCookies = false,
                HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                MaxBufferPoolSize = int.MaxValue,
                MaxReceivedMessageSize = int.MaxValue,
                MessageEncoding = WSMessageEncoding.Mtom,
                TextEncoding = Encoding.UTF8,
                ReaderQuotas = XmlDictionaryReaderQuotas.Max,
                BypassProxyOnLocal = true,
                UseDefaultWebProxy = false
            };
        }
    }

 

public Binding CreateBinding()
        {
            return new WSHttpBinding(SecurityMode.None)
                       {
                           Name = "ws",
                           AllowCookies = false,
                           TransactionFlow = false,
                           HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                           MaxBufferPoolSize = int.MaxValue,
                           MaxReceivedMessageSize = int.MaxValue,
                           MessageEncoding = WSMessageEncoding.Text,
                           TextEncoding = Encoding.UTF8,
                           ReaderQuotas = XmlDictionaryReaderQuotas.Max,
                           BypassProxyOnLocal = true,
                           UseDefaultWebProxy = false
                       };
        }

 

The values to configure the bindings with can be read from a configuration store. I’ll post a simple version of a centralized configuration store later.

Bringing it all together

To enable the service to be configured by our new factory we need to add one simple statement to the svc markup (marked in red).

<%@ ServiceHost Language="C#" Debug="true" Service="Syrstad.Blog.WcfDemo.Service.DemoService" CodeBehind="DemoService.svc.cs" Factory="Syrstad.Blog.WcfDemo.WcfConfigurationModule.HostFactory" %>

When the development team is building both the service and the client(s) it is a good thing to extract the interface and the data classes in a separate assembly for easy distribution, through the build system, to the projects that depend on it.

Configuring the client

The client also needs to be configured in the same way. We want to ensure that resources used by WCF are properly cleaned, so we will create a container for the proxy that we make disposable.

For ease of use we will create a factory for client proxy containers, called ClientProxyFactory. This has one static method that returns an initialized instance of the container. We implement the container as a generic and uses the type parameter is the interface used in the service itself.

public static class ClientProxyFactory
    {
        public static ServiceClientContainer CreateProxy()
        {
            //Replace with your IoC of choice
            return new ServiceClientContainer().Initialize();
        }
    }

The service container creates a new channel factory with the appropriate settings collected from the interface and the config store. This factory is used to create the actual proxy. The factory is kept as a instance field so it will be a part of the dispose.

For binding creation, we reuse the BindingFactory used by the service so that there is no possibility for configuration mismatch.

internal ServiceClientContainer()
        {
            ServiceName = typeof(T).Name;
            BindingType = ConfigurationManager.AppSettings["useClientBinding"];
            Url = AddressHelper.GetFormattedAddress(BindingType);
        }
 
        public ServiceClientContainer Initialize()
        {
            ClientFactory = CreateChannelFactory(ServiceName, Url);
            return this;
        }
 
        internal ChannelFactory CreateChannelFactory(string servicename, string uri)
        {
            var builder = GetProxyBuilder();
            var channelFactory = new ChannelFactory(builder.GetServiceBinding(servicename, uri, BindingType));
            foreach (OperationDescription op in channelFactory.Endpoint.Contract.Operations)
            {
                var dataContractBehavior = op.Behaviors[typeof(DataContractSerializerOperationBehavior)] as DataContractSerializerOperationBehavior;
                if (dataContractBehavior != null)
                {
                    dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
                }
            }
            return channelFactory;
        }
 
        private static IProxyBindingBuilder GetProxyBuilder()
        {
            return new ProxyBindingBuilder();
        }

Next we need a GetClient method that creates the proxy and returns it to the client code.

public T GetClient()
        {
            if (Client == null) Client = ClientFactory.CreateChannel(new EndpointAddress(Url));
            return Client;
        }

This approach makes it easy and clean to create and use runtime generated WCF proxies and ensure proper disposal of the underlying resources.

Download the demo solution and play with WCF. I apologize for the use of regions in some of the source files; they are added as an effort to make this post and the code easier to follow.

Please note that I have done some code cleaning (separated some code into new methods) after I wrote this post.


 The demo solution

Project
Description
Syrstad.Blog.WcfDemo
Contains WCF Service interface and data transfer objects for the demo
Syrstad.Blog.WcfDemo.Client
The demo client
Syrstad.Blog.WcfDemo.Service
The demo service
Syrstad.Blog.WcfDemo.WcfConfigurationModule
The WCF configuration code. This will be updated in future posts to include centralized config store and more binding builders