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

 

Friday, February 4, 2011

ADFS, SAML and RelayState

I have been working with ADFS for a customer for som time now, and as a part of their pilot we are going to enable trust with a SaaS application that suports SAML WebSSO Post profile. The customer requires deep linking to conten from their intranet. The SaaS solution handles this by reading the RelayState parameter in the SAML POST.
Microsoft did not implement support for this part of the POST profile....
In this forum thread Collins gives an outline of the solution, but no actual code examples. As we needed this feature I had to write this piece of code (not the prettiest code ever writen, but it works in my case).
So, to the solution:
(As I said, it is not going to be pretty)
code is shown in italic

Code to add a cookie:
in "IdpInitiatedSignOn.aspx.cs" add the following line in the using section:

using System.Web;

And at the beginning of the method "Page_Init" add the following lines at the beginngin of the method:

string value = Context.Request.QueryString["RelayState"];
if(String.IsNullOrEmpty(value))
value=" ";
HttpCookie = cookie= new HttpCookie("RelayState", value);
Context.Response.Cookies.Add(cookie);

(It might be a good idea to enable error messages in web.config (a small typo might cause crashes)

Create a class library project in Visual Studio 2008, with a strong name.

add a class called: "RelayStateModule"

public class RelayStateModule:System.Web.IHttpModule
{
#region IHttpModule Members

public void Dispose()
{
_Context = null;
}
private System.Web.HttpApplication _Context;
private RelayStateFilter MyFilter;
public void Init(System.Web.HttpApplication context)
{
_Context = context;
_Context.AuthorizeRequest += new EventHandler(_Context_AuthorizeRequest);

}



void _Context_AuthorizeRequest(object sender, EventArgs e)
{
if (_Context.Request.Cookies.AllKeys.Contains("RelayState"))
{
var value = _Context.Request.Cookies["RelayState"].Value;
MyFilter = new RelayStateFilter(_Context.Response.Filter, value);
_Context.Response.Filter = MyFilter;
}
}

#endregion
}

Add a class called: "RelayStateFilter"

public class RelayStateFilter : Stream
{

private Stream ParentFilter;
private StreamWriter streamWriter;
private string _RelayState;
public RelayStateFilter(Stream filter,string relayState)
{
_RelayState = relayState;
ParentFilter = filter;
streamWriter = new StreamWriter(ParentFilter);
}
public override void Write(byte[] buffer, int offset, int count)
{

MemoryStream ms = new MemoryStream(buffer, offset, count, false);
StreamReader sr = new StreamReader(ms, System.Text.Encoding.UTF8);

string s;
bool isSAMLResponse = false;
StringBuilder sb = new StringBuilder();
int i = 0;
int lineNumberToInsertRS = -1;
while ((s = sr.ReadLine()) != null)
{
i++;
if (s.Contains("SAMLResponse"))
{
isSAMLResponse = true;
}
if (isSAMLResponse && s.Contains("submit"))
{
lineNumberToInsertRS = i;
var rsIncluded = InsertRSIntoResponseString(s, _RelayState);

sb.AppendLine(rsIncluded);
streamWriter.WriteLine(rsIncluded);
}
else
{
sb.AppendLine(s);
streamWriter.WriteLine(s);
}
}
sb.AppendLine("number of lines="+i.ToString());
//For debugging purposes, remove from production code.
if (isSAMLResponse)
{
using (var fs = File.Open(@"c:\temp\lastToken.txt", FileMode.Create))
{
//fs.w
var sr2 = new StreamWriter(fs);

sr2.Write(sb.ToString());
sr2.Close();
}
}
streamWriter.Flush();

}

private string InsertRSIntoResponseString(string s, string _RelayState)
{
//Finding location of Submit action
var loc = s.IndexOf("<noscript>");
return s.Insert(loc,String.Format("<input type=\"hidden\" name=\"RelayState\" value=\>"{0}\" /", _RelayState)); //
}
#region Rest of Stream's function - our stream is write-only

public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}

public override bool CanRead
{ get { return false; } }

public override bool CanSeek
{ get { return false; } }

public override bool CanWrite
{ get { return true; } }

public override long Length
{ get { throw new NotSupportedException(); } }

public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}

public override void Flush()
{
ParentFilter.Flush();
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}

public override void SetLength(long value)
{
throw new NotSupportedException();
}

#endregion
}

Compile and get the full name of your new assembly.

Create a new folder in the adfs\ls directory called "bin" and place your assembly there.
Then you need to register your assembly in web.config:

And at last you register the module in IIS Manager under the ls web site.
There you create a managed module called RelayStateFilter
And under type you have to refer your RelayStateModule
{your namespace}.RelayStateModule

hopefully you will have your RelayState in the SAML message to your RP.





Saturday, November 8, 2008

The garbage collector and memory usage in .NET

During the last weeks I have been diving into the darkest corners of .NET. Normally you don't pay that much attention to the garbage collector in .NET. When it works and you haven't done anything that messes this up it is just sweet. You do not have to release used objects the GC does this for you. But there are times when this is not the case. There are some obvious traps you can fall into and some a bit more obscure. I'll devide this into two parts, the obvious and the sneaky.

I'll start with a breef introduction to the Garbage Collector (GC).
The GC manages the allocation and release of memory for your application. It waches over your memory usage and when you are using too much memory it will release 'dead' objects from the managed heap. Objects are structured in 3 generations + the large objects heap.

Generations explained:

The collector only runs when a certain amount of memory has been used or there is enough pressure for memory on the system.
.Net uses generations to optimize the garbage collector. There are 3 primary generations, 0 through 2.
All new objects are stored in gen 0. if an object survives a collection of gen 0 objects it is moved to the next generation, which is gen 1 in this case. by moving older objects to the next generation, since these objects are likely to be long living objects, this reduces the number of objects the GC needs to check in each collection.
During collection the GC removes and compacts the memory heap for the given generation. This is done by using memcpy to copy them over to the free space to make them contiguous again.

The fact that .NET is a garbage collected runtime you cannot jus look at the memory usage in task manager to determine the actual memory usage.

You can force a collection programmatically, this is however not recommended since the GC is optimized. Calling this yourself might cause your application to spend more time in garbage collection than necessary. There are cases that this might be a good idea. But the general recommendation is 'don't'.


The obvious:

If a class implements the IDisposable you should call it. If you do not have control over your objects life cycle implement a destructor to release native resources. with native resoures we normally think of com objects and pInvoke. But there are classes in .NET that uses native resources, and you MUST release these.
An example of classes that uses native resources is the System.IO namespace. Most streams has native resources bound to it. This is why it is is important to call .Close() and .Dispose() on such objects. Batabase connections is also something you must close as fast as possible.

Methods that uses such resources should always have the finally operator at the end.

internal long GetDASyncStatusCode(long daId)
{
System.Data.OracleClient.OracleCommand cmd = new OracleCommand(string.Format("SELECT SYNCSTATUS FROM DA WHERE DAID={0}", daId.ToString()), this._mainConnection);
cmd.Connection.Open();
long code = 1;
System.Data.OracleClient.OracleDataReader dr = null;
try
{
dr= cmd.ExecuteReader();

if (dr.Read())
{
object o = dr.GetValue(0);
if ((o != null) && (o != DBNull.Value))
code = Convert.ToInt64(o);
else
code = 1;
}
//dr.Close();
}
catch (Exception ex)
{
Barwill.DAWeb.Utilities.ExceptionLogGateway.SaveException(ex);
}
finally
{
if (_mainConnection.State == System.Data.ConnectionState.Open)
{
if (dr != null)
if (!dr.IsClosed)
dr.Close();
_mainConnection.Close();
}
}
return code;
}

The sneaky

In order to keep performance up we often store data in Session or cache storage. if this is an inproc session state you are able to store the entire object also non serializable objects. If you hook up an event handler to a cached object in you ASP.NET pages or controls you might run into a potential memory leak. Event handlers store a reference to the subscribing object. This causes the GC to thing that your ASP.NET page is pinned and will not collect it. if your cached object lives for many hours and you have many users you will run into a OOM (Out Of Memory) exception this might be a bit anoying for the user as well as you, the developer. Below I have added a example og how to unhook your event handlers, a nice place to do this is in the OnUnload event of the page or control.

protected override void OnUnload(EventArgs e)
{
((JobDetail)Page).OnParentUpdated -= JobModuleControl_OnParentUpdated;
_CBSControl.OnControlUpdated -= ctrl_OnControlUpdated;
_CBSControl.OnStatusChanged -= ctrl_OnStatusChanged;



base.OnUnload(e);
}