Implementing an identity provider and relying party with Zermatt and ASP.NET MVC

Zermatt is the framework recently released by Microsoft to develop claim-aware applications. You can find some announcements here and here.

This framework supports the WS-Federation active and passive profiles. This last one was initially designed with an unique purpose in mind, allow the integration of "dumb clients" into the identity metasystem. As "dumb clients", I am talking about clients like web browsers that do not have the ability to handle cryptographic material.

All the magic is done through some consecutive Http redirects, and today we will see how develop an identity provider and a relying party web (with ASP.NET MVC) that are involved in the whole process.

The identity provider is based on the quickstart that is automatically generated in Visual Studio when you create a new MVC web application. This quickstart uses FormsAuthentication to authenticate the application users and also provides an Account controller (that internally uses ASP.NET Membership) to manage all those users. In order to integrate Zermatt in this application, I added a new controller STSController that knows to process messages for getting issue tokens with the user's claims.

For the relying party, Zermatt provides some web controls to authenticate the user against the identity provider using the passive profile. Unfortunately, for the simple fact that ASP.NET MVC does not support controls with view state, we can not use them here. As workaround, I created a couple of extensions methods that generate the Urls for sending the corresponding messages to the identity provider (Login and Logout).

public static class LoginUrlExtensions

{

   public static string LoginUrl(this UrlHelper helper, string actionName, string controllerName, string stsUrl)

   {

       string host = helper.ViewContext.HttpContext.Request.Url.Authority;

       string schema = helper.ViewContext.HttpContext.Request.Url.Scheme;

 

       string realm = string.Format("{0}://{1}", schema, host);

       string reply = helper.Action(actionName, controllerName).Substring(1);

 

       return string.Format("{0}?wa=wsignin1.0&wtrealm={1}&wreply={2}&wctx=rm=0&id=FederatedPassiveSignIn1&wct={3}",

          stsUrl, realm, reply, XmlConvert.ToString(DateTime.Now));

   }

 

   public static string LogoutUrl(this UrlHelper helper, string actionName, string controllerName, string stsUrl)

   {

       string host = helper.ViewContext.HttpContext.Request.Url.Authority;

       string schema = helper.ViewContext.HttpContext.Request.Url.Scheme;

 

       string realm = string.Format("{0}://{1}", schema, host);

       string reply = string.Format("{0}{1}", realm, helper.Action(actionName, controllerName));

 

       return string.Format("{0}?wa=wsignout1.0&wreply={1}", stsUrl, reply);

   }

}

The "actionName" and "controllerName" are just used to generate the reply address where the user must be redirect after being authenticated in the identity provider. These extension methods can be used in the view as follow,

<a href="<%=Url.LoginUrl("Login", "Home", "localhost://STS")%>">Login</a>

We also need a method in the relying party to parse the RRST message and generate a cookie with the user credentials and claims.

 

public interface IFederatedAuthentication

{

   IClaimsPrincipal Authenticate();

}

 

public class FederatedAuthentication : IFederatedAuthentication

{

     private string logoutUrl;

 

     public FederatedAuthentication(string logoutUrl)

     {

         this.logoutUrl = logoutUrl;

     }

 

     public IClaimsPrincipal Authenticate()

     {

         string securityTokenXml = FederatedAuthenticationModule.Current.GetXmlTokenFromPassiveSignInResponse(System.Web.HttpContext.Current.Request, null);

 

         FederatedAuthenticationModule current = FederatedAuthenticationModule.Current;

 

         SecurityToken token = null;

         IClaimsPrincipal authContext = current.AuthenticateUser(securityTokenXml, out token);

 

         TicketGenerationContext context = new TicketGenerationContext(authContext, false, logoutUrl, typeof(SignInControl).Name);

         current.IssueTicket(context);

 

         return authContext;

     }

}

 

As you can see in the code above, the Zermatt module (FederatedAuthenticationModule) that parses the response message is tied to the Request object, something that we do not have direct access from a MVC controller (Well, it is bad practice if we want to test our code). That's the reason I decided to put all that code in a pluggin that can be injected later in the controller.

The complete solution is available to download from this location. Any feedback would be great!!. Enjoy!!.

Dependency injection made easy for the ASP.NET MVC

I decided to write this post to show how cool is Autofac for doing dependency injection in the ASP.NET MVC framework. Autofac, for me the Moq stepbrother  in the dependency injection arena because of its very-easy-to-use fluent interface and nice support of lambda expressions, comes with a built-in ASP.NET module to automatically intercept the creation of the controllers and pass the required dependencies to them, the only thing a programmer has to do is to provide instances of those dependencies or expressions to build them.

Well, it is time to see Autofac in action with a practical example. If you have the chance to use the MVC preview 4, you may notice that it comes with a new controller "Account" to manage the website membership. This controller receives two dependencies in the constructor,

public AccountController(IFormsAuthentication formsAuth, MembershipProvider provider)

{

  FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

  Provider = provider ?? Membership.Provider;

}

 

public IFormsAuthentication FormsAuth

{

  get;

  private set;

}

 

public MembershipProvider Provider

{

  get;

  private set;

}

If those dependencies are not provided, it creates a default implementation of "FormsAuthenticationWrapper" and use the Membership singleton instance. Ok, let's make some minor changes to this controller so we always assume that those instances must be provided by the caller code (It will be actually responsibility of the DI container).

public AccountController(IFormsAuthentication formsAuth, MembershipProvider provider)

{

  FormsAuth = formsAuth;

  Provider = provider;

}

We now have to initialize a container to instruct Autofac about how to initialize or get instances of those classes. This can be done in the global.asax file,

static IContainerProvider containerProvider;

 

protected void Application_Start()

{

   RegisterRoutes(RouteTable.Routes);

 

   var builder = new ContainerBuilder();

 

   // Automatically register all controllers in the current assembly.

   builder.RegisterModule(new AutofacControllerModule(Assembly.GetExecutingAssembly()));

 

   builder.Register<MembershipProvider>(container => Membership.Provider).ExternallyOwned();

   builder.Register<FormsAuthenticationWrapper>().As<IFormsAuthentication>().FactoryScoped();

 

   containerProvider = new ContainerProvider(builder.Build());

 

   // Hook MVC factory.

   ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(containerProvider));

}

There are some lines in the code above that deserve special attention, so let's discuss them in details:

1.

// Automatically register all controllers in the current assembly.

builder.RegisterModule(new AutofacControllerModule(Assembly.GetExecutingAssembly()));

This line basically discovers and registers all the controllers within the current assembly (The website itself) into the DI container.

2.

builder.Register<MembershipProvider>(container => Membership.Provider).ExternallyOwned();

builder.Register<FormsAuthenticationWrapper>().As<IFormsAuthentication>().FactoryScoped();

The dependencies are registered in the container builder (The one that later knows how to create instances of the dependencies). The Register method optionally receives an lambda expression that will be used later to create or get the dependency instance, it could be considered a sort of lazy class construction. The container can also be used in the expressions to resolve other dependencies, for example,

builder.Register<MessagingService>(c => new MessagingService(c.Resolve<IMessageRepository>).As<IMessagingService>();

Another important aspect in the initialization is the scope, which basically controls the dependency lifetime. In the code above I used two scopes, ExternallyOwned (The instance is managed by the application) and FactoryScoped (A new instance is created for every dependency resolution, very useful for instances that must be used and disposed just after, like the DataContext in Linq to SQL). Other possible scopes could be ContainerScoped (An instance per container) or Singleton (An instance shared between all containers).

3.

containerProvider = new ContainerProvider(builder.Build());

 

// Hook MVC factory.

ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(containerProvider));

The container provider is created, and the controller factory implementation provided by Autofac is set for the current application.

As you can see, most of the plumbing code is already provided by Autofac, just a couple of lines were needed to start using DI in the MVC framework.

The code sample is available to download here

Combining JQuery Validation with ASP.NET MVC

One of the most nicest things about JQuery - in addition to the powerful mechanism it provides to manipulate the HTML DOM - is the great number of very useful plugins available out there.

JQuery Validation is one of my favorites, and today we will see how this plugin can be used with the MVC framework to validate all the inputs in a form before it is submitted to the controller.

This plugin supports the concept of "validation rule", a validation that has to be performed to an input field. For instance, "The field is required", "The field should have at least N characters", or "This field has to be a valid email", many of them are the same you can find in the ASP.NET validators. (These validators do not work with the MVC framework because they are tied to the ASP.NET Viewstate). Of course, new rules can also be created for performing custom validations specific to an application, some examples of this are also available in the plugin's website.

A rule can be applied to an input field in two ways:

1. Declarative, the rule is specified in the input field by means of the class attribute:

<input name="email" id="email" maxlength="60" class="required email" type="text"/>

As you can see, two rules were specified in the class attribute, "Required" and "Email", which means that two validations have to be performed for this field. Many rules can be applied to the same field, they only have to be separated by an space.

2. Imperative in code, the rule is specified in an script:

<script type="text/javascript">

$(document).ready(function(){

  $("#form-sign-up").validate( {

    rules: {

      email: {

        required: true,

        email: true

    },

    messages: {

      email: {

        required: "Please provide an email",

        email: "Please provide a valid email"

     } });

});

</script>

The validation was attached to the input field "email" in the form "form-sign-up". The message displayed when a validation fails for an specific field can also be customized using the "messages" section in the script. (This is optional, the plugin already comes with a set of pre-defined error messages)

And finally, one of the most interesting validation rules you can find there is "remote", which performs a remote validation using an Ajax endpoint. At this point we can use an MVC controller method to perform an specific validation, for instance to see if a login name is still available to be used.

<script type="text/javascript">

$(document).ready(function(){

$("#form-sign-up").validate( {

  rules: {

    login: {

      required: true,

      remote: '<%=Url.Action("IsLoginAvailable", "Accounts") %>'

   }

  },

  messages: {

    login: {

     required: "Please provide an alias",

     remote: jQuery.format("{0} is already in use")

   }

  } });

});

</script>

The only requirement for the controller is that it must be return Json with the result of the validation. This can be easily done with MVC,

public JsonResult IsLoginAvailable(string login)

{

    //TODO: Do the validation

    JsonResult result = new JsonResult();

    if (login == "cibrax")

      result.Data = false;

    else

      result.Data = true;

 

    return result;

}

In the example above, if "cibrax" is entered as login name, the validation will fail and the user will see an error message.

The styles for the error messages can also be customized with the following rules,

label.error {

display: block;

color: red;

font-style: italic;

font-weight: normal;

}

input.error {

border: 2px solid red;

}

td.field input.error, td.field select.error, tr.errorRow td.field input,tr.errorRow td.field select {

border: 2px solid red;

background-color: #FFFFD5;

margin: 0px;

color: red;

}

As we have discussed here, JQuery validation is a great tool that we all should consider at the moment to validate data in the ASP.NET MVC framework.

A complete example with different validations can be downloaded from this location.

WCF - Issue with Secure Conversation in Web farms

While I was working for one of my customers, we ran into a very strange problem when they tried to deploy some WCF services in a web farm using cookie sessions (In order to enable secure conversation in this kind of scenario, cookies must be used to track the state of the Secure Conversation Tokens).

At some point, we start receiving a random exception with the following message,

System.ServiceModel.Security.MessageSecurityException: Message security verification failed. ---&gt; System.Xml.XmlException: There was an error deserializing the security token XML. Please see the inner exception for more details. ---&gt; System.ArgumentException: The SecurityContextSecurityToken with context-id=urn:uuid:502e208e-8db2-4814-8623-d3050273e875 (no key generation-id) has expired

Later, we found out that a time skew setting was not supported in WCF for the SCT cookies, and the error was happening because of an slight difference in time between the servers in the farm.

Fortunately, Brent Schmaltz has made public a hot fix for that problem in his blog. You can find the complete solution and a better description of the problem in this post.

Enjoy.

Microsoft Technight - Buenos Aires

Tonight, Daniel and I will be presenting a session about "synchronization on the web" in the Microsoft Technight event (Microsoft offices in Buenos Aires). 

We are going to talk about some of the areas in which data synchronization is very important, and the available technologies that can be used in those scenarios. ("FeedSync", Microsoft Framework, Mesh4x and Live Mesh to name a few).

I hope to see you there.

Streaming large content with WCF and deferred execution

I will use this post to discuss an scenario that you may run into while working with WCF, a service that returns a lot of objects (Or large data) to the client applications. This scenario is not about transferring files, that is a completely different story, and I already discussed it some time ago in another post.

The scalability of the service's host may be affected if the service is not well designed or configured. WCF will use large memory buffers to keep the complete message before it start sending that message through the wire.

Using data contracts or XML serializable classes in this scenario does not scale well because the complete object graph has to be loaded in memory before the corresponding serializer (Data Contract serializer or Xml Serializer) transform it into an stream of bytes.

In addition, if the service throttling settings are not configured carefully for that service, a large number of requests will practically consume all the available resources (If that happens, the server will stop processing additional requests and you may run into a OutOfMemory exception as well). For more information about Service Throttling, I recommend this Kenny Wolf's post.

Before getting into the streaming solution, which looks very complex at first glance, you should consider refactoring your service's API to support data paging. If you use paging, the design of the final service will be simpler and you should not have any of the mentioned problems. What's more, streaming does not work well with message security, the default behavior for WCF is to buffer all messages when message security is set for the channel. In order to combine message security with streaming you should use the Chunking Channel.

Data Paging design sample,

[XmlRoot("Customer")]

public class Customer

{

  public string FirstName { get; set; }

 

  public string LastName { get; set; }

 

  public string Address { get; set; }

}

 

[XmlRoot("Customers")]

public class Customers

{

    public Customer[] Customers { get; set; }

}

 

public interface ISampleService

{

  [OperationContract]

  Customers GetAllCustomers(int page, int count, out int totalCustomers); 

}

The client application will have to call that method as many times as it needs to retrieve all the customers. The service should have a limit in the number of customers it can return per call, otherwise, we will have the same problems if the client application asks for a large number of customers.

Deferred execution is a cool feature introduced in .NET 2.0 for enumerations. Basically the enumeration does not happen until some calling code wants to examine the enumeration.

Let's discuss now how deferred execution can be achieved in WCF with the help of the streaming model.

1. The first extensibility point that we will need for this solution is a custom BodyWriter class. A BodyWriter has the knowledge to serialize an entire object graph as xml into the body of a soap message. The class Message has an static method to create a new message from a  BodyWriter instance.

public abstract class Message : ....

{

    public static Message CreateMessage(MessageVersion version, string action, BodyWriter body)

}

The "BodyWriter" class is an abstract and contains a single method to serialize the complete object graph into the soap body.

public class CustomBodyWriter : BodyWriter

  {

    private IEnumerable<Customer> customers;

 

    public CustomBodyWriter(IEnumerable<Customer> customers)

      : base(false) // False should be passed here to avoid buffering the message

    {

      this.customers = customers;

    }

 

    protected override void OnWriteBodyContents(System.Xml.XmlDictionaryWriter writer)

    {

      XmlSerializer serializer = new XmlSerializer(typeof(Customer));

      writer.WriteStartElement("customers");

      foreach (Customer customer in customers)

      {

        serializer.Serialize(writer, customer);

      }

      writer.WriteEndElement();

    }

  }

As you can see in the code above, our custom implementation of the "OnWriteBodyContents" receives an enumeration of objects that we want to serialize into the message. A "false" value is passed as argument in the constructor to the base class to specify that our custom implementation can not be buffered.

2. We will use deferred execution to retrieve all the customers from the database (The following code actually emulates that),

public IEnumerable<Customer> GetAllCustomersImpl()

{

   for(long i = 0; i < 1000; i++) //All the customers should be read from the database

   {

      yield return new Customer { FirstName = "Foo", LastName = "Bar", Address = "FooBar 123" };

   }

 

   yield break;

}

What's it is important here is that we are not returning all the customer objects at the same time (we are returning one at time, so they are not loaded in memory) using the "yield" operator.

3. The service implementation returns a new message created from the custom "CustomBodyWriter" class.

public class SampleService : ISampleService

  {

    #region ISampleService Members

 

    public Message GetAllCustomers()

    {

      Message message = Message.CreateMessage(MessageVersion.Soap11, "GetAllCustomers", new CustomBodyWriter(GetAllCustomersImpl()));

      return message;

    }

 

    #endregion

    

  }

 

The first two arguments of the CreateMessage method specifies the soap version and soap action for the response message.

4. The client application also reads one customer object at time from the response message,

static IEnumerable<Customer> GetAllCustomers(Message message)

{

  XmlReader reader = message.GetReaderAtBodyContents();

  if (reader.LocalName != "customers")

  {

     throw new Exception("The service returned an invalid message");

  }

 

  XmlSerializer serializer = new XmlSerializer(typeof(Customer));

  reader.ReadStartElement("customers");

 

  while(!reader.EOF && reader.LocalName == "Customer")

  {

     Customer customer = (Customer)serializer.Deserialize(reader);

     yield return customer;

  }

 

  reader.ReadEndElement();

}

5. Finally, the client and the service, both have to be configured to use an "streamed" as transfer mode. Otherwise, all the messages will be buffered in memory.

<basicHttpBinding>

   <binding name="basic" transferMode="StreamedResponse" maxReceivedMessageSize="10000000">

      <security mode="None"></security>

   </binding>

</basicHttpBinding>

The "maxReceivedMessageSize" setting is also important because it limits the amount of data that the service can return. You should adjust it to a value according to the amount of data you might return in the service implementation.

You can download the complete sample from this location.

Unit Tests for WCF (and Moq) Part II

 

My latest post about "creating wrapper classes" for mocking the WCF context has started generating some controversies. I initially wrote those classes to decouple my service implementation from the concrete implementation of the WCF context,  something that  did not have anything to do with the static nature of the context. (I can still pass the current instance as an argument to my service implementation).

As I mentioned in my previous post, the WCF context is neither a base class (with virtual methods) nor an interface, so it can not easily mocked, that is main issue here.

I am not sure if TypeMock allows mocking this kind of class as well, probably yes, I have never used that tool before so I do not know.  It would be great to have a natural or easy support in C# for mocking non-virtual methods or statics, but it is not there now. I personally prefer writing some simple wrapper classes or "utterly useless wrappers" as someone call them  (In fact, it only took me 5 minutes to write them, and I do not think my productive was affected by that) rather than creating code that can only be tested by an specific tool. I am not saying that you should not use TypeMock, anyone is free to use the tool that works best for his needs.

Posted 20 May 2008 02:28 PM by cibrax | 1 comment(s)
Filed under: ,
Unit tests for WCF (And Moq)

As you may know, testing WCF services is not as simple as referencing a service implementation and start writing unit tests against it. If the service we want to test has a high dependency with the operation context, which is an static class, testing that service can be a very complicated task.

Many times that dependency can be removed thanks to the help of some WCF extensibility points like behaviors, authorization managers or authorization policies to name a few. For instance, if an operation implementation in our service is looking for specific security claims to check user permissions, that code could be moved to an authorization manager to make the resulting code easier to test.

However, there are some cases where the dependency with the context or other objects can not be completely removed (Or it is not solution), and therefore the Dependency Injection pattern comes to help us. I have already discussed how to use DI in WCF before, and other people have also done the same.

Ok, let's say that we are in that scenario and we want to use DI to remove all the dependencies of our service with the WCF operation context. How can we do that ?. The WCF context is neither a base class nor an interface, we can not mock it at all at first glance. Fortunately, there is a easy workaround to solve this problem, it consists of creating a public interface with all the properties and methods that we want to use (and mock) from the WCF context.

public interface IOperationContext

{

     event EventHandler OperationCompleted;

 

     // Methods

     T GetCallbackChannel<T>();

     void SetTransactionComplete();

 

     // Properties

     IContextChannel Channel { get; }

     IExtensionCollection<OperationContext> Extensions { get; }

     bool HasSupportingTokens { get; }

     ServiceHostBase Host { get; }

     MessageHeaders IncomingMessageHeaders { get; }

     MessageProperties IncomingMessageProperties { get; }

     MessageVersion IncomingMessageVersion { get; }

     InstanceContext InstanceContext { get; }

     bool IsUserContext { get; }

     MessageHeaders OutgoingMessageHeaders { get; }

     MessageProperties OutgoingMessageProperties { get; }

     RequestContext RequestContext { get; set; }

     IServiceSecurityContext ServiceSecurityContext { get; }

     string SessionId { get; }

     ICollection<SupportingTokenSpecification> SupportingTokens { get; }

}

Same thing can be done for the ServiceSecurityContext and WebOperationContext.

public interface IServiceSecurityContext

{

    AuthorizationContext AuthorizationContext { get; }

    ReadOnlyCollection<IAuthorizationPolicy> AuthorizationPolicies { get; }

    bool IsAnonymous { get; }

    IIdentity PrimaryIdentity { get; }

    WindowsIdentity WindowsIdentity { get; }

}

 

public interface IWebOperationContext

{

  IIncomingWebRequestContext IncomingRequest { get; }

  IOutgoingWebResponseContext OutgoingResponse { get; }

}

 

Secondly, we need a default implementation to wrap the existing WCF context functionality, this wrapper will only delegates method calls to the original context.

public class OperationContextWrapper : IOperationContext

  {

    OperationContext context;

 

    public OperationContextWrapper(OperationContext context)

    {

      this.context = context;

    }

 

    #region IOperationContext Members

 

    public event EventHandler OperationCompleted;

 

    public T GetCallbackChannel<T>()

    {

      return context.GetCallbackChannel<T>();

    }

 

    public void SetTransactionComplete()

    {

      context.SetTransactionComplete();

    }

 

    public IContextChannel Channel

    {

      get { return context.Channel; }

    }

 

    public IExtensionCollection<OperationContext> Extensions

    {

      get { return context.Extensions; }

    }

 

    public bool HasSupportingTokens

    {

      get { return context.HasSupportingTokens; }

    }

 

    public ServiceHostBase Host

    {

      get { return context.Host; }

    }

 

    public System.ServiceModel.Channels.MessageHeaders IncomingMessageHeaders

    {

      get { return context.IncomingMessageHeaders; }

    }

 

    public System.ServiceModel.Channels.MessageProperties IncomingMessageProperties

    {

      get { return context.IncomingMessageProperties; }

    }

 

    public System.ServiceModel.Channels.MessageVersion IncomingMessageVersion

    {

      get { return context.IncomingMessageVersion; }

    }

 

    public InstanceContext InstanceContext

    {

      get { return context.InstanceContext; }

    }

 

    public bool IsUserContext

    {

      get { return context.IsUserContext; }

    }

 

    public System.ServiceModel.Channels.MessageHeaders OutgoingMessageHeaders

    {

      get { return context.OutgoingMessageHeaders; }

    }

 

    public System.ServiceModel.Channels.MessageProperties OutgoingMessageProperties

    {

      get { return context.OutgoingMessageProperties; }

    }

 

    public System.ServiceModel.Channels.RequestContext RequestContext

    {

      get

      {

        return context.RequestContext;

      }

      set

      {

        context.RequestContext = value;

      }

    }

 

    public IServiceSecurityContext ServiceSecurityContext

    {

      get { return new ServiceSecurityContextWrapper(context.ServiceSecurityContext); }

    }

 

    public string SessionId

    {

      get { return context.SessionId; }

    }

 

    public ICollection<System.ServiceModel.Security.SupportingTokenSpecification> SupportingTokens

    {

      get { return context.SupportingTokens; }

    }

 

    #endregion

  }

 

public class ServiceSecurityContextWrapper : IServiceSecurityContext

  {

    ServiceSecurityContext context;

 

    public ServiceSecurityContextWrapper(ServiceSecurityContext context)

    {

      this.context = context;

    }

 

    #region IServiceSecurityContext Members

 

    public System.IdentityModel.Policy.AuthorizationContext AuthorizationContext

    {

      get

      {

        return this.context.AuthorizationContext;

      }

    }

 

    public ReadOnlyCollection<IAuthorizationPolicy> AuthorizationPolicies

    {

      get

      {

        return this.context.AuthorizationPolicies;

      }

    }

 

    public bool IsAnonymous

    {

      get

      {

        return this.context.IsAnonymous;

      }

    }

 

    public System.Security.Principal.IIdentity PrimaryIdentity

    {

      get

      {

        return this.context.PrimaryIdentity;

      }

    }

 

    public System.Security.Principal.WindowsIdentity WindowsIdentity

    {

      get

      {

        return this.context.WindowsIdentity;

      }

    }

 

    #endregion

  }

 

public class WebOperationContextWrapper : IWebOperationContext

  {

    private WebOperationContext context;

 

    public WebOperationContextWrapper(WebOperationContext context)

    {

      this.context = context;

    }

 

    #region IWebOperationContext Members

 

    public IIncomingWebRequestContext IncomingRequest

    {

      get { return new IncomingWebRequestContextWrapper(context.IncomingRequest); }

    }

 

    public IOutgoingWebResponseContext OutgoingResponse

    {

      get { return new OutgoingWebResponseContextWrapper(context.OutgoingResponse); }

    }

 

    #endregion

  }

Thirdly, the context must be injected as a dependency into the service. This can be done through a constructor or a property setter, (This is what our Unit test is going to use). If you do not want to deal with a DI framework at all because it can complicates the service implementation somehow, the service can have a default constructor to set up the default context implementation (the wrapper). This is the constructor that WCF will call by default when the service is created. In the example bellow, I will show how to do that for a simple REST service that uses the WCF WebOperationContext.

[ServiceContract]

public interface ICustomerService

{

    [OperationContract]

    [WebGet(UriTemplate = "/customers/{id}")]

    Customer FindCustomer(string id);

}

 

public class CustomerService : ICustomerService

{

  IWebOperationContext context;

 

  public CustomerService()

  {

    context = new WebOperationContextWrapper(WebOperationContext.Current);

  }

 

  public CustomerService(IWebOperationContext context)

  {

    this.context = context;

  }

Now that we have all the infrastructure in place, we only need a good mocking framework that helps us to create the mock objects for our tests. In this part, I should recommend Moq as the framework to use :). My friend Daniel Cazzulino has made an excellent work developing this framework.

The pattern for using Moq or other similar framework in a unit test is the following:

1. You create a mock object from an existing interface or base class. (The framework provides a way to do this).

2. You set the expectations for that mock object. This is what you want to be called, returned, set, etc.

3. You pass the mock object to the object under testing.

4. You call some methods on the object under testing, and afterwards, you verify that all the expectations were met.

An interesting thing that we can do with Moq is to mock the complete object graph of the WebOperationContext so we can reuse across all our tests.

public class MockWebContext : Mock<IWebOperationContext>

{

    Mock<IIncomingWebRequestContext> requestContextMock = new Mock<IIncomingWebRequestContext>();

    Mock<IOutgoingWebResponseContext> responseContextMock = new Mock<IOutgoingWebResponseContext>();

 

    public MockWebContext()

      : base()

    {

      this.ExpectGet(webContext => webContext.OutgoingResponse).Returns(responseContextMock.Object);

      this.ExpectGet(webContext => webContext.IncomingRequest).Returns(requestContextMock.Object);

 

      WebHeaderCollection requestHeaders = new WebHeaderCollection();

      WebHeaderCollection responseHeaders = new WebHeaderCollection();

      UriTemplateMatch uriTemplateMatch = new UriTemplateMatch();

 

      requestContextMock.ExpectGet(requestContext => requestContext.Headers).Returns(requestHeaders);

      requestContextMock.ExpectGet(requestContext => requestContext.UriTemplateMatch).Returns(uriTemplateMatch);

      responseContextMock.ExpectGet(responseContext => responseContext.Headers).Returns(responseHeaders);

    }

 

    public Mock<IIncomingWebRequestContext> IncomingRequest

    {

      get { return requestContextMock; }

    }

 

    public Mock<IOutgoingWebResponseContext> OutgoingResponse

    {

      get { return responseContextMock; }

    }

 

    public override void Verify()

    {

      base.Verify();

      requestContextMock.Verify();

      responseContextMock.Verify();

    }

 

    public override void VerifyAll()

    {

      base.VerifyAll();

      requestContextMock.VerifyAll();

      responseContextMock.VerifyAll();

    }

}

As you can see in that code, I basically created a mock for the IWebOperationContext that also returns mock objects for the inner properties like the IncomingRequest or OutgoingResponse. All the expectations like default collections or contexts were set in the constructor. We will use this mock later in the unit tests for the REST service.

Our REST service implementation is quite simple, it only looks for a customer with an specific identifier.

public Customer FindCustomer(string id)

{

   if (context.IncomingRequest.ContentType != "application/xml")

   {

      context.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.BadRequest;

      context.OutgoingResponse.SuppressEntityBody = true;

      return null;

   }

 

   if (id == "1")

      return new Customer { FirstName = "John", LastName = "Doe", Address = "Address" };

 

   context.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;

   context.OutgoingResponse.SuppressEntityBody = true;

 

   return null;

}

 

The service is expecting a "ContentType" http header equal to "application/xml", and returning a "Not Found" status code if the customer does not exists.

We can now write some unit tests to verify that our service is working as we initially expected. The first one will verify that a valid "Customer" instance is returned by the service is the "ContentType" header is set correctly, and the right customer id is passed as argument to the FindCustomer operation.

[Test]

public void ShouldReturnCustomer()

{

  MockWebContext mock = new MockWebContext();

  mock.IncomingRequest.ExpectGet(incomingRequest => incomingRequest.ContentType).Returns("application/xml");

 

  CustomerService service = new CustomerService(mock.Object);

  Customer customer = service.FindCustomer("1");

 

  Assert.IsNotNull(customer);

}

The most important parts of the test above are:

1. If the service ask for the content type, it should get "application/xml".

mock.IncomingRequest.ExpectGet(incomingRequest => incomingRequest.ContentType).Returns("application/xml");

2. The mock object is passed as argument to the service implementation.

CustomerService service = new CustomerService(mock.Object);

 

We can create a second test to verify that the status code is set to "NotFound" when an invalid customer id is passed as argument to the FindCustomer operation.

[Test]

public void ShouldSetStatusCodeIfCustomerNotFound()

{

   MockWebContext mock = new MockWebContext();

   mock.IncomingRequest.ExpectGet(incomingRequest => incomingRequest.ContentType).Returns("application/xml");

   mock.OutgoingResponse.ExpectSet(outgoingResponse => outgoingResponse.StatusCode).Callback(sc => Assert.AreEqual(HttpStatusCode.NotFound, sc));

 

   CustomerService service = new CustomerService(mock.Object);

   Customer customer = service.FindCustomer("5");

}


We are setting an expectation that the StatusCode should be "NotFound" when the customer id is not equal to "1". (This is done in Moq by means of a Callback).

mock.OutgoingResponse.ExpectSet(outgoingResponse => outgoingResponse.StatusCode).Callback(sc => Assert.AreEqual(HttpStatusCode.NotFound, sc));

Moq really simplifies everything, including the testing of services that depends on the WCF operation context :).

Another approach to test WCF services, as Ploeh mentioned in this post, is what he call integration testing. If you do integration testing, you are basically executing the service as a black box (the unit test in this case plays the role of the client application) using all the channel infrastructure provided by WCF. As you can notice, this approach will require a lot of plumbing code and configuration to host the service and set up the channels elements (Bindings and Behaviors).

Posted 16 May 2008 11:05 AM by cibrax | 8 comment(s)
Filed under: ,
Overview of FeedSync support in the Microsoft Sync Framework

What is FeedSync ?

If you have not heard about "FeedSync" yet, it is the official name of an open and interoperable standard for representing synchronization metadata in a XML format. This specification was formerly called by Microsoft as "SSE" (Simple Sharing Extensions), and its name was changed to "FeedSync" prior to the first release version.

The fact that the "FeedSync" model is completely based on XML and it is quite simple to represent, makes this specification a good candidate to guarantee interoperability with other platforms.

The complete specification is based on two fundamental aspects,

1. A way to represent the "FeedSync" model as XML extensions that can be easily attached to any existing document. The most common use nowadays is to include them as part of a syndication feed like RSS or ATOM to keep synchronization metadata about each available item. Many people have started proving parsers for this specification as part of their Syndication libraries, some examples are Simple Sharing Extensions For .NET, Rome for Java, or Argotic (.NET)

Let's take a quick look at the metadata attached to some items in a RSS feed.

<feed xmlns:sx='http://feedsync.org/2007/feedsync'>

  <title>Hello World</title>

  <link>http://weblogs.asp.net/cibrax</link>

  <description>this is my feed</description>

  <sx:sharing since='11-05-2007T19:33:27Z' until='14-05-2007T19:33:27Z'>

    <sx:related link='http://kzu/full' type='complete' />

  </sx:sharing>

  <item>

   <title>Foo Title</title>

   <description>Foo Description</description>

   <Foo Title='Foo' />

   <sx:sync id='d92d64f5-c006-4086-a35a-c5195448d3ad' updates='2' deleted='false' noconflicts='false'>

     <sx:history sequence='2' when='18-05-2007T19:33:27Z' by='Cibrax' />

     <sx:history sequence='1' when='14-05-2007T19:33:27Z' by='JohnFoo' />

    </sx:sync>  </item>

 

</feed>

First of all, it adds optional metadata at feed level through the "sharing" element to include aggregated information about related feeds or sources. (The since and until attributes in that element represents the lower and upper bounds of the items contained within the feed).

Secondly, it includes synchronization metadata at item level with the "sync" element. This element contains the following information:

a. An identifier to represent the item (Id attribute), this identifier must be unique across all the synchronization peers.

b. An history of updates that includes the person that made a change to the item, and the date/time of that change. As you can see, this information is quite simple, it does not say anything about what were the changes made to the item (We will see later that this information is actually not important for the merging algorithm).

c. Flags to indicate if the item was deleted or contains conflicts. (The same item version or sequence number was modified in one or more replicas at the same time).

The rest of the information not mentioned here is part of the RSS specification itself and it does not have anything to do with "FeedSync".

2. An algorithm that use the synchronization metadata to merge the items across several peers. For instance, to perform a bidirectional synchronization of local information between two peers. The algorithm also uses the metadata to detect conflicts at the moment of doing the merge operation.

For example, if we have the following information in two different replicas

REPLICA A

REPLICA B

  ItemA-Sequence1 ItemC-Sequence1
  ItemB-Sequence1  

After the first synchronization, the resulting information will be:

REPLICA A

REPLICA B

  ItemA-Sequence1 ItemC-Sequence1
  ItemB-Sequence1  ItemA-Sequence1
  ItemC-Sequence1  ItemB-Sequence1

Now, Let's say the replica B changes the item A and B( The sequence or version is incremented)

REPLICA A

REPLICA B

  ItemA-Sequence1 ItemC-Sequence1
  ItemB-Sequence1  ItemA-Sequence2
  ItemC-Sequence1  ItemB-Sequence2

If they synchronize again, the resulting information will be:

REPLICA A

REPLICA B

  ItemA-Sequence2 ItemC-Sequence1
  ItemB-Sequence2 ItemA-Sequence2
  ItemC-Sequence1 ItemB-Sequence2

Now, if both replicas change the same item before synchronizing, for instance ItemC. At the moment of synchronizing the information, they will have the same sequence for ItemC, and therefore a conflict will exist. (The algorithm to detect conflicts is more complex than this, I am just giving an example)

REPLICA A

REPLICA B

  ItemA-Sequence2  ItemC-Sequence2
  ItemB-Sequence2 ItemA-Sequence2
  ItemC-Sequence2 ItemB-Sequence2

Having these two important aspects, a developer wanting to synchronize information with other applications only has to represent that information as a FeedSync feed (A normal feed that includes "FeedSync" metadata) and expose it somewhere. Another application can later on combine that feed with its own feed using the merging algorithm, which will result in a full biredirectional synchronization between those two application.

As you can see, both aspects complement each other, an bidirectional synchronization can not be done with just one of them.

How to expose your information in a FeedSync feed with the Sync Framework

1. The first thing you have to do is to determine which information you will want to expose in the final feed. Let's say that you have several copies of a database with customer information spread across several locations (Different company's branches perhaps), and you want to keep all those copies synchronized. You will have to expose that information as part of a feed, so people in other locations can synchronize their data against that feed (This example assumes that one central feed is used, but you can actually have multiple feeds that synchronize each other having a kind of tree structure, this is one of the goodness about FeedSync, no central replica is required).

If you want to represent the customer's full name, address and phone number as an entry in a RSS feed, the entry will look as follow:

<item>

  <title>John Doe</title>

  <description>John Doe's Information</description>

  <Customer>

    <FullName>John Doe</FullName>

    <Address>Test Adress</Address>

    <PhoneNumber>xxx-xxxx-xxxx</PhoneNumber>   </Customer>

</item>

This mapping between the real data and a XML payload (The RSS's entry data) can be done in the Sync Framework by having a concrete implementation of "FeedItemConverter" class. The implementation of this class will know how to map custom data to a XML payload and vice versa.

public abstract class FeedItemConverter

{

  protected FeedItemConverter();

  public abstract string ConvertItemDataToXmlText(object itemData); //Method to convert the actual item data into XML

  public abstract object ConvertXmlToItemData(string itemXml); //Method to convert the XML data into the item data

}

I personally do not like much the signature of those methods, an string could be anything (itemXml), not just XML and that can not be enforced by the current API design. I would prefer to have something like this:

public abstract class FeedItemConverter

{

  protected FeedItemConverter();

  public abstract void WriteItemDataToXml(object itemData, XmlWriter xmlWriter); //Method to convert the actual item data into XML

  public abstract object ReadItemDataFromXml(XmlReader xmlReader); //Method to convert the XML data into the item data

}

In the sample above, you should implement a "CustomerFeedItemConverter" to convert a customer instance into XML the xml representation and vice versa.

2. Secondly, you have to provide a mapping between your internal identifiers and the identifiers used in the synchronization metadata. From the MSDN documentation "

"A FeedIdConverter can convert replica IDs and item IDs from the flexible-length format of the provider to strings, and vice versa. Also, the ID converter must be able to generate a replica ID for an anonymous change. The FeedSync history for a change contains three potential attributes: sequence, when, and by. The by attribute represents the replica that made the change, but it is not required by the FeedSync schema and so might be absent. If a change does not include a by value, a replica ID must be generated for the change by combining the sequence and when values"

public abstract class FeedIdConverter

{

  protected FeedIdConverter();

  public abstract SyncIdFormatGroup IdFormats { get; }

  public abstract string ConvertItemIdToString(SyncId itemId);

  public abstract string ConvertReplicaIdToString(SyncId replicaId);

  public abstract SyncId ConvertStringToItemId(string value);

  public abstract SyncId ConvertStringToReplicaId(string value);

  public abstract SyncId GenerateAnonymousReplicaId(string when, uint sequence);

}

Since the implementation of this provider will be the same most of the times, I think it would be a good idea to provide a default implementation of this provider as part of the Sync framework (It could provide extensibility points through virtual methods).

3. Once you have the item and id converters, they should be enough to start consuming or publishing FeedSync feeds with your custom information. The framework comes with two classes for that purpose, FeedConsumer and FeedProducer.

public class FeedProducer

{

  public FeedProducer(KnowledgeSyncProvider storeProvider, FeedIdConverter idConverter, FeedItemConverter itemConverter);

public FeedIdConverter IdConverter { get; set; }

  public EndpointState IncrementalFeedBaseline { get; set; }

  public FeedItemConverter ItemConverter { get; set; }

  public KnowledgeSyncProvider StoreProvider { get; set; }

  public void ProduceFeed(Stream feedStream);

}

public class FeedConsumer

{

  public FeedConsumer(KnowledgeSyncProvider storeProvider, FeedIdConverter idConverter, FeedItemConv