FilterAttribute Property Injection in Autofac MVC 3 Integration

by Alex Meyer-Gleaves 24 March 2011 - 8:56 PM

The current mechanism for performing property injection on FilterAttribute instances via the ExtensibleActionInvoker had to be removed recently due to a rather nasty bug. These are the notes that Nick provided outlining the problem he discovered (possibly with the help of the exciting new Whitebox profiler).

Because the filters passed from the base action invoker also include the controller, property injection happens on the controller itself several times as the filters are processed.

The filter attributes also included in the collection may also be singletons cached by MVC, and so it is quite likely that dependencies may be overwritten with those from a concurrently executing request.

In all this behaviour is probably too risky to reliably support.

Removed property injection routine. (Breaking change.)

I have replaced the old mechanism using an approach that leverages the improved dependency injection support added to MVC 3 (this will be in the next release). To make use of property injection for your filter attributes all you will need to do is call the RegisterFilterProvider method on the ContainerBuilder before building your container and providing it to the AutofacDependencyResolver.

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();
builder.RegisterFilterProvider();

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Then you can add properties to your filter attributes and any matching dependencies that are registered in the container will be injected into the properties. For example, the action filter below will have the ILogger instance that was registered above injected. Note that the attribute itself does not need to be registered in the container.

public class CustomActionFilter : ActionFilterAttribute
{
    public ILogger Logger { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Logger.Log("OnActionExecuting");
    }
}

The same simple approach applies to the other filter attribute types such as authorization attributes.

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public ILogger Logger { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        Logger.Log("AuthorizeCore");
        return true;
    }
}

After applying the attributes to your actions as required your work is done.

[CustomActionFilter]
[CustomAuthorizeAttribute]
public ActionResult Index()
{
    // ...
}

To make this work I added a custom FilterAttributeFilterProvider implementation. The custom filter provider delegates the job of collecting the filters to the base class. Once the filters have been retrieved by the base class, the ILifetimeScope for the current HTTP request is retrieved and used to perform property injection on the filters. The false passed to the base FilterAttributeProvider constructor sets the cacheAttributeInstances parameter to ensure that attribute instances are not cached. Allowing the attribute instances to be cached would result in race conditions and other unexpected behaviour.

/// <summary>
/// Defines a filter provider for filter attributes that performs property injection.
/// </summary>
public class AutofacFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
    /// <summary>
    /// Initializes a new instance of the <see cref="AutofacFilterAttributeFilterProvider"/> class.
    /// </summary>
    /// <remarks>
    /// The <c>false</c> constructor parameter passed to base here ensures that attribute instances are not cached.
    /// </remarks>
    public AutofacFilterAttributeFilterProvider() : base(false)
    {
    }

    /// <summary>
    /// Aggregates the filters from all of the filter providers into one collection.
    /// </summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="actionDescriptor">The action descriptor.</param>
    /// <returns>
    /// The collection filters from all of the filter providers with properties injected.
    /// </returns>
    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext, actionDescriptor).ToArray();
        var lifetimeScope = AutofacDependencyResolver.Current.RequestLifetimeScope;

        if (lifetimeScope != null)
            foreach (var filter in filters)
                lifetimeScope.InjectProperties(filter.Instance);

        return filters;
    }
}

The RegisterFilterProvider method has been added to the ContainerBuilder using an extension method. This method will register the AutofacFilterAttributeFilterProvider using the IFilterProvider interface that MVC uses when asking the dependency resolver for filter providers. Following the instructions outlined in Brad Wilson’s post on the subject of dependency injection and filters, I made sure that the default FilterAttributeFilterProvider instance is removed from the static collection of providers.

/// <summary>
/// Registers the <see cref="AutofacFilterAttributeFilterProvider"/>.
/// </summary>
/// <param name="builder">The container builder.</param>
public static void RegisterFilterProvider(this ContainerBuilder builder)
{
    if (builder == null) throw new ArgumentNullException("builder");

    foreach (var provider in FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().ToArray())
        FilterProviders.Providers.Remove(provider);

    builder.RegisterType<AutofacFilterAttributeFilterProvider>()
        .As<IFilterProvider>()
        .SingleInstance();
}

If you were using the old mechanism you will have breaking changes to contend with, but as you can see it should be easy to get back on track again.

Tags: ,

Autofac | Web Development

View Page Injection in Autofac ASP.NET MVC 3 Integration

by Alex Meyer-Gleaves 29 December 2010 - 4:31 PM

The increased support for dependency injection in ASP.NET MVC 3 includes the ability to have your view pages created by your favourite container.

Historically, these classes have not had access to dependency injection/service location functionality, because their creation was buried deep inside the implementation of the view engine. In MVC 3, we have updated the built-in view engines to attempt to create the view page classes via the service locator; if that fails, it will fall back to using Activator.CreateInstance, just like in previous versions of MVC.

Because the view pages are dynamically compiled at runtime a few restrictions have been imposed; you cannot use constructor injection and your view pages must inherit from a custom base class.

The problem is that your .aspx/.ascx/.cshtml/.vbhtml files are converted into classes at runtime by the ASP.NET Build Manager (in collaboration with build providers). When those classes are auto generated, they are auto generated only with a single parameterless constructor.

We looked at auto-generating constructors, but it turns out that we don't actually know enough about the base class when we're generating the code to actually do any reflection on it, so it's not really possible for us to look at the base class and determine which constructors it may or may not have.

Happy that these limitations are not going to pose any serious problems let’s move onto the Autofac integration. Time for yet another uninspiring example, but one that should be easy to follow and doesn’t require too much typing on my part. Imagine that we have a service that provides common company information such as a copyright that we need to display on all our view pages.

public interface ICompanyInformation
{
    string Copyright { get; }
}

There is of course an implementation of the service that returns the dynamic copyright information (you were warned about the example).

public class CompanyInformation : ICompanyInformation
{
    public string Copyright
    {
        get { return string.Format("Copywrong &copy; {0} ACME Corporation", DateTime.Now.Year); }
    }
}

In the application start event we build our container and register the service along with our controllers. We also add a registration source called ViewRegistrationSource.

ContainerBuilder builder = new ContainerBuilder();
builder.Register(c => new CompanyInformation()).As<ICompanyInformation>().InstancePerHttpRequest();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterSource(new ViewRegistrationSource());

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

The registration source is where all the magic happens. A registration source allows you to create an adapter that will dynamically provide a registration for a service. We know that MVC will ask the container for an instance of the view page before it attempts to create it itself, so we can use the registration source to make sure that the container always knows how to provide such an instance. Below is the implementation of the registration source for those that are interested in the details.

public class ViewRegistrationSource : IRegistrationSource
{
    public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        var typedService = service as IServiceWithType;

        if (typedService != null && IsSupportedView(typedService.ServiceType))
            yield return RegistrationBuilder.ForType(typedService.ServiceType)
                .PropertiesAutowired()
                .InstancePerHttpRequest()
                .CreateRegistration();
    }

    public bool IsAdapterForIndividualComponents
    {
        get { return false; }
    }

    static bool IsSupportedView(Type serviceType)
    {
        return serviceType.IsAssignableTo<WebViewPage>() 
            || serviceType.IsAssignableTo<ViewPage>()
            || serviceType.IsAssignableTo<ViewMasterPage>()
            || serviceType.IsAssignableTo<ViewUserControl>();
    }
}

If the requested service inherits from one of the supported view base classes, the RegistrationBuilder.ForType helper is used to build the registration. The registration also makes sure that property injection is performed and that the lifetime is scoped to the HTTP request. The Razor view base class WebViewPage is supported, along with the WebForms base classes ViewPage, ViewMasterPage and ViewUserControl.

To get properties on the view page that can be injected by the container, you need to slot your own base class into the inheritance hierarchy. This is as simple as creating an abstract class that derives from WebViewPage or WebViewPage<T> when using the Razor view engine.

public abstract class CustomViewPage : WebViewPage
{
    public ICompanyInformation CompanyInformation { get; set; }
}

If you are using the WebForms view engine in your MVC project you would derive from the ViewPage or ViewPage<T> class instead.

public abstract class CustomViewPage : ViewPage
{
    public ICompanyInformation CompanyInformation { get; set; }
}

The last thing you need to do is ensure that your actual view page inherits from your custom base class. This can be achieved using the @inherits directive inside your .cshtml file for the Razor view engine.

@inherits Example.Views.Shared.CustomViewPage

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
<p>
    This is the page content.
</p>
<p>
    @CompanyInformation.Copyright
</p>

When using the WebForms view engine you set the Inherits attribute on the @ Page directive inside you .aspx file instead.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage"%>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%: ViewBag.Message %></h2>
    <p>
        This is the page content.
    </p>
    <p>
        <%= CompanyInformation.Copyright %>
    </p>
</asp:Content>

Making your custom base class inherit from the generic WebViewPage<T> or ViewPage<T> class allows you to provide your strongly typed model as the generic type parameter. You can of course choose to leave the generic type parameter in your base class open making it more reusable.

public abstract class CustomViewPage<T> : WebViewPage<T>
{
    public ICompanyInformation CompanyInformation { get; set; }
}

You simply provide the model type as the closing generic parameter in the type declared in the @inherits or Inherits attribute of the page.

@inherits Example.Views.Shared.CustomViewPage<Example.Models.CustomModel> 

Taking advantage of view page injection is a very simple matter. No doubt you will have much more creative uses for this than the simplified example shown here.

Tags: ,

Autofac | Web Development

Model Binder Injection in Autofac ASP.NET MVC 3 Integration

by Alex Meyer-Gleaves 8 December 2010 - 4:30 PM

The Autofac MVC integration supported model binder injection in the MVC 2 version, but improvements in the dependency injection support offered by MVC 3 has allowed the implementation to be made cleaner. ASP.NET MVC 3 introduces the IModelBinderProvider interface that allows the implementer to determine what model binder should be used for a particular type.

Developers who implement this interface can optionally return an implementation of IModelBinder for a given type (they should return null if they cannot create a binder for the given type).

Let’s start by looking at how the model binder injection is configured in the MVC integration. You first create a class that implements IModelBinder like you would when creating any other model binder in MVC. Next you apply the ModelBinderType attribute provided as part of the integration to indicate what types the model binder supports binding. The simple example below declares that the model binder supports binding for string types.

[ModelBinderType(typeof(string))]
public class StringBinder : IModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Do implementation here.
    }
}

You then use the RegisterModelBinders extension method on the ContainerBuilder to register all the IModelBinder types that are present in one or more assemblies.

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());

The interesting part about the implementation of the assembly scanning is that it finds the types the model binder supports through the ModelBinderType attributes and then adds this information as metadata to the registration.

public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
    RegisterModelBinders(this ContainerBuilder builder, params Assembly[] modelBinderAssemblies)
{
    return builder.RegisterAssemblyTypes(modelBinderAssemblies)
        .Where(type => typeof(IModelBinder).IsAssignableFrom(type))
        .As<IModelBinder>()
        .InstancePerHttpRequest()
        .WithMetadata(AutofacModelBinderProvider.MetadataKey, type => 
            (from ModelBinderTypeAttribute attribute in type.GetCustomAttributes(typeof(ModelBinderTypeAttribute), true)
             from targetType in attribute.TargetTypes
            select targetType).ToList());
}

You must also remember to register the AutofacModelBinderProvider using the RegisterModelBinderProvider extension method. This is Autofac's implementation of the new IModelBinderProvider interface.

builder.RegisterModelBinderProvider();

The constructor of the AutofacModelBinderProvider requests that an IEnumerable<Meta<Lazy<IModelBinder>>> be provided. When the GetBinder method is called through the IModelBinderProvider interface, the list of Meta<T> about the components is queried to locate any potential matches based on the types stored in the metadata. The Lazy<T> part of dependency makes sure that we do not actually create an instance of the IModelBinder until it is actually needed.

public IModelBinder GetBinder(Type modelType)
{
    Meta<Lazy<IModelBinder>> modelBinder = _modelBinders
        .FirstOrDefault(binder => ((List<Type>)binder.Metadata[MetadataKey]).Contains(modelType));
    return (modelBinder != null) ? modelBinder.Value.Value : null;
}

This dynamic approach to handling model binder injection removes the need for a special wrapper around each IModelBinder component, and avoids having to register this wrapper directly into the static ModelBinders.Binders dictionary.

Tags:

Autofac | Web Development

ASP.NET MVC 3 Beta integration for Autofac

by Alex Meyer-Gleaves 4 November 2010 - 7:38 PM

I have just checked into trunk a first pass at the ASP.NET MVC 3 Beta integration for Autofac. In hope of simplifying the requirements for those getting started with the integration I wanted to prevent the need to:

The code below is an example of all you would need to put into the application start event to get up and running.

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

The core piece of the integration is the AutofacDependencyResolver. This is an implementation of the IDependencyResolver interface that Brad Wilson outlines in his blog post series on ASP.NET MVC 3 Service Location. The interface requires you to implement two simple methods: GetService and GetServices. When no service is found GetService should return null, and GetServices should return an empty IEnumerable<object>. The implementation of these methods ends up being straight forward (ignoring for now the code related to managing the CurrentLifetimeScope).

public object GetService(Type serviceType)
{
    return CurrentLifetimeScope.IsRegistered(serviceType) ? CurrentLifetimeScope.Resolve(serviceType) : null;
}

public IEnumerable<object> GetServices(Type serviceType)
{
    Type enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(serviceType);
    object instance = CurrentLifetimeScope.Resolve(enumerableServiceType);
    return ((IEnumerable)instance).Cast<object>();
}

When MVC needs to create a controller it will ask the DependencyResolver for an instance. The AutofacDependencyResolver returns the controllers that are registered in the container it was provided. These are usually registered using the RegisterControllers method on the ContainerBuilder as shown in the first code sample. There is no longer a need to create a class that derives from the DefaultControllerFactory for the sole purpose of returning controller instances. This means the AutofacControllerFactory is no longer required and has been removed.

The Autofac MVC integration has always supported the concept of a HTTP request lifetime scope. This means that the lifetime of a service can be scoped to the current HTTP request. The ILogger service registration in the sample code above uses the InstancePerHttpRequest method to indicate that the same instance of the logger service should be used for all dependency resolutions that occur during the current HTTP request. To make sure that the nested lifetime scope that Autofac creates for each request is disposed, it needs to be notified when the request has ended.

The only reliable way to do this is to create a HTTP module that subscribes to the EndRequest event of the HttpApplication. To register a HTTP module you need to add an entry to the web configuration file, which is something that I was hoping to avoid. Rick Strahl outlines one way of achieving programmatic registration of a module in his Dynamically hooking up HttpModules post, but for the integration this would require the user to manually add the code to their HttpApplication instance (by default called MvcApplication).

It turns out that there is in fact another way to programmatically register a module. The Microsoft.Web.Infrastructure.dll assembly that ships with the ASP.NET Web Pages installer (AspNetWebPages.msi) contains a rather helpful class called DynamicModuleUtility. It has a single method called RegisterModule that accepts a Type for the module to register. You can only call this helper from a method that is marked as pre application start code as defined by the PreApplicationStartMethodAttribute applied to an assembly. The same trick is used in System.Web.Pages.dll to register the new WebPageHttpModule. Phil Haack has a blog post that talks about the PreApplicationStartMethodAttribute and some other interesting new ASP.NET 4 features in greater detail if you are keen to know more. You need to install ASP.NET Web Pages before installing ASP.NET MVC 3 so we know the assembly with this helpful little gem will be available.

In the Autofac integration we first needed to add the assembly attribute.

[assembly: PreApplicationStartMethod(typeof(PreApplicationStartCode), "Start")]

This points to a static class that contains a single static method called Start. Inside this method we call the DynamicModuleUtility to register the RequestLifetimeModule that will informs us when the HTTP request has ended. There is no need to ever call this class directly but unfortunately, it and the method must be public. That is why we have the EditorBrowsable attribute being applied in order to hide the class from the editor. Not really that much work to save a user from having to dive into the web configuration file.

[EditorBrowsable(EditorBrowsableState.Never)]
public static class PreApplicationStartCode
{
    private static bool _startWasCalled;

    public static void Start()
    {
        if (_startWasCalled) return;

        _startWasCalled = true;
        DynamicModuleUtility.RegisterModule(typeof(RequestLifetimeModule));
    }
}

There is a new interface in the MVC 3 integration called ILifetimeScopeProvider. The HTTP module RequestLifetimeModule shown above actually implements this interface and is the default implementation used by the AutofacDependencyResolver. You can see from the AutofacDependencyResolver code shown at the start of the post that the resolutions are happening from the CurrentLifetimeScope property.

internal ILifetimeScope CurrentLifetimeScope
{
    get
    {
        if (_lifetimeScopeProvider == null)
            _lifetimeScopeProvider = GetRequestLifetimeModule();
        return _lifetimeScopeProvider.GetLifetimeScope(_container, _configurationAction);
    }
}

You can add your own ILifetimeScopeProvider implementation to the container that is passed to the AutofacDependencyResolver if you want to replace the HTTP request based lifetime behaviour. The AutofacDependencyResolver will attempt to retrieve it from the container during its constructor. Because the RequestLifetimeModule is the default ILifetimeScopeProvider and an instance was already created by ASP.NET when the module was initialised, we can go and grab that from the HttpModuleCollection of the current HttpApplication.

static ILifetimeScopeProvider GetRequestLifetimeModule()
{
    HttpModuleCollection httpModules = HttpContext.Current.ApplicationInstance.Modules;
    for (int index = 0; index < httpModules.Count; index++)
    {
        if (httpModules[index] is RequestLifetimeModule)
            return (RequestLifetimeModule)httpModules[index];
    }
    throw new InvalidOperationException(string.Format(
        AutofacDependencyResolverResources.HttpModuleNotLoaded, typeof(RequestLifetimeModule)));
}

None of the model binding code has been moved into the new integration yet. I am hoping that this can be refactored to use the new IModelBinderProvider interface. This is only a first pass based on a new approach so it is likely that some of this will change. I have certainly found the exercise interesting enough that I thought it was worth sharing the start of the journey.

Tags: ,

Autofac | Web Development

Introducing Action Injection with Autofac ASP.NET MVC Integration

by Alex Meyer-Gleaves 16 May 2010 - 7:33 PM

There are currently two main approaches to performing dependency injection, Constructor Injection and Setter Injection. The more popular of the two approaches is Constructor Injection. The dependencies that a type has are made obvious because they must be supplied in order to construct an instance. This also makes it easier for you to ensure that a newly instantiated object is in a valid state. When working with a type the constructor is usually the first thing that you come into contact with.

With Setter Injection, also known as Property Injection, it is much more difficult to tell what the dependencies are when looking at the type from the outside. Setter Injection is most useful when you have no control over the instantiation of the type that requires the dependencies to be injected. This is a common scenario for ASP.NET WebForms where the activation of a Page instance is performed by the runtime. You do not have an opportunity to take over the activation process, and the first chance you have to perform dependency injection is when you are provided with an existing instance of Page. In this case you have no choice but to inject the dependencies into the type via its properties.

ASP.NET MVC has many extensibility points and is very flexible. It provides you with the opportunity to take over the creation of your Controller instances by creating your own factory that implements IControllerFactory, or more commonly by deriving from the DefaultControllerFactory and overriding the GetControllerInstance method. This makes it possible for your controllers to take advantage of Constructor Injection, and is exactly what the Autofac ASP.NET MVC Integration does. When it comes to unit testing your controller classes, it becomes very easy to see what dependencies it has, and to provide mock implementations for those dependencies.

An issue that is often raised in regards to Constructor Injection is what some people like to call Constructor Bloat. This may indicate that you are not following the Single Responsibility Principle and that some refactoring may be in order. The number of constructor parameters that would be considered too many would no doubt vary depending on who you ask. In the case of ASP.NET MVC controllers the number of constructor dependencies is more likely to be higher than for other classes. The level of responsibility for a controller is usual greater than what you would expect for an ordinary internal component. This is the result of mapping an external view of the application (URL based) onto an internal representation (controller based).

It turns out that both Nicholas Blumhardt and I found ourselves shifting some of these dependencies out of the controller’s constructor and into the action methods that actually require them. We were both fairly surprised to find out that the other had independently been doing exactly the same thing, and at this point discussed if there was something wrong with the approach because it seemed that no one else was doing it. Surely all good ideas have already been done so this one must be bad. I personally feel that having dependencies injected into your action method should not feel like a foreign concept because that is exactly what MVC is already doing for you with your existing parameters.

For lack of any official term that I am aware of, Action Injection is what I am calling this particular approach to dependency injection in ASP.NET MVC. The more I play around with this approach the more I like it. Your constructor is provided the dependencies that are shared by all actions in your controller, and each individual action can request any additional dependencies that it needs. Now when writing unit tests for your actions there is no need to provide mock implementations for dependencies that your action will not be interacting with. The end result is less mocks in your unit tests and a clear indication of the action’s actual dependencies.

Nick and I have decided to test out the idea of Action Injection in the Autofac ASP.NET MVC Integration. The changes are only in the source code at the moment and have not yet been included in a release. I mentioned earlier that MVC is very extensible and the process for invoking your action methods is no different. It is possible to replace the default behaviour by creating your own IActionInvoker. The easiest way to do this is by deriving from the AsyncControllerActionInvoker class and overriding the appropriate methods. A controller can be requested to use your custom action invoker by assigning an instance to the controller's ActionInvoker property. The current source includes a registration extension that allows you to register an IActionInvoker instance that will be assigned to a controller as it is activated. There is a default IActionInvoker implementation called ExtensibleActionInvoker that allows dependencies to be injected into your action methods. It can also do Setter Injection on your filters but that is a topic for another post. As the name suggests, you can extend this class and add any additional behaviour that you require. Registering controllers in the HttpApplication start would look something like this.

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterType<ExtensibleActionInvoker>()
    .As<IActionInvoker>()
    .WithParameter("injectActionMethodParameters", true);
builder.RegisterControllers(Assembly.GetExecutingAssembly())
    .InjectActionInvoker();

// Register other services.

IContainer container = builder.Build();
_containerProvider = new ContainerProvider(container);

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

I will not go into further detail on the implementation at this point because it may be tweaked a little before being released. Instead, let us look at an example of how we could make our action dependencies clearer using Action Injection. The NotifyController class below has action methods that send the current user a message using different delivery methods.

public class NotifyController
{
    public NotifyController(ILogger logger, 
        IEmailNotifier emailNotifier, 
        ISmsNotifier smsNotifier, 
        IMessengerNotifier messengerNotifier)
    {
        // Implementation.
    }
    
    public ActionResult Email(string message)
    {
        // Implementation.
    }
    
    public ActionResult Sms(string message)
    {
        // Implementation.
    }

    public ActionResult Messenger(string message)
    {
        // Implementation.
    }
}

There are three action methods on this controller and four dependencies that must be provided through the constructor. To unit test any of the action methods all four of the dependencies will need to be mocked. In this controller the ILogger instance is required by all action methods, but the remaining notifier dependencies are each required only by one action method. The controller could be refactored so that it takes the one ILogger dependency through its constructor, and each action could take its particular notifier dependency through a method parameter. Here is an example of how the refactored code would look.

public class NotifyController
{
    public NotifyController(ILogger logger)
    {
        // Implementation.
    }
    
    public ActionResult Email(string message, IEmailNotifier emailNotifier)
    {
        // Implementation.
    }
    
    public ActionResult Sms(string message, ISmsNotifier smsNotifier)
    {
        // Implementation.
    }

    public ActionResult Messenger(string message, IMessengerNotifier messengerNotifier)
    {
        // Implementation.
    }
}

Now when testing the action methods we only ever need to provide two mock services. There is no need to provide additional mock services that will never be used. Assuming we only had one unit test per action and setup our mocks inside each unit test, we would have halved the number of mocks required, taking the total from twelve down to six. That certainly seems like an improvement to me.

I would be interested to know what you think about this idea. Is it totally crazy or could there be something to it? Maybe you too have already been doing this and could share how it has been working out for you.

Tags: ,

Autofac | Web Development

Switching to reCAPTCHA for Comment Spam protection

by Alex Meyer-Gleaves 30 March 2010 - 6:45 PM

reCAPTCHA I recently posted about using CAPTCHA on my blog in an attempt to reduce the amount of comment spam. The implementation I posted about has worked well for me but I decided I would like to switch to reCAPTCHA. Not only is this free CAPTCHA service robust and well tested, it also helps to digitize books, newspapers and old time radio shows. Taking the thousands of hours people spend entering CAPTCHA information each day and utilizing them for an additional purpose is a brilliant idea.

As with the previous solution I was sure that someone would have already done the work to integrate reCAPTCHA with BlogEngine.NET. My assumption was correct and I quickly found a solution in the form of an extension written by Filip Stanek. I followed the simple installation process and had the control appearing in the comment form straight away. After a short period of testing I quickly found a couple of problems. Once the first comment was added all subsequent comments entered resulting in an error that was reported via the callback. The log viewer added to the administration area was also throwing an exception and failing to load.

I tracked both of these problems down to the extension expecting the return value from BlogService.LoadFromDataStore to be a Stream. This method returns an object instance and delegates its work to the currently configured BlogProvider. The BlogProvider.LoadFromDataStore method also returns object, and it turns out that the type of the object returned will be different depending on the provider being used. My data store is a VistaDB.NET database so I am using the DbBlogProvider instead of the default XmlBlogProvider. Unfortunately the DbBlogProvider returns a string and the XmlBlogProvider returns a Stream. There is nothing stopping the next provider that is written from returning yet another type. This no doubt makes life difficult for those writing BlogEngine.NET extensions.

To get the extension working with the DbBlogProvider you will need to make a couple of small changes. In the Recaptcha.cs file, find the code below in the UpdateLog method.

Stream s = (Stream)BlogService.LoadFromDataStore(BlogEngine.Core.DataStore.ExtensionType.Extension, "RecaptchaLog");
List<RecaptchaLogItem> log = new List<RecaptchaLogItem>();
if (s != null)
{
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<RecaptchaLogItem>));
    log = (List<RecaptchaLogItem>)serializer.Deserialize(s);
    s.Close();
}
log.Add(logItem);

Replace it with the following code.

string data = (string)BlogService.LoadFromDataStore(BlogEngine.Core.DataStore.ExtensionType.Extension, "RecaptchaLog");
List<RecaptchaLogItem> log = new List<RecaptchaLogItem>();
if (!string.IsNullOrEmpty(data))
{
    using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(data)))
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<RecaptchaLogItem>));
        log = (List<RecaptchaLogItem>)serializer.Deserialize(stream);
    }
}
log.Add(logItem);

In the RecaptchaLogViewer.aspx.cs file, find the code below in the BindGrid method.

Stream s = (Stream)BlogService.LoadFromDataStore(BlogEngine.Core.DataStore.ExtensionType.Extension, "RecaptchaLog");
List<RecaptchaLogItem> log = new List<RecaptchaLogItem>();
if (s != null)
{
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<RecaptchaLogItem>));
    log = (List<RecaptchaLogItem>)serializer.Deserialize(s);
    s.Close();
}

Replace it with the following code.

string data = (string)BlogService.LoadFromDataStore(BlogEngine.Core.DataStore.ExtensionType.Extension, "RecaptchaLog");
List<RecaptchaLogItem> log = new List<RecaptchaLogItem>();
if (!string.IsNullOrEmpty(data))
{
    using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(data)))
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<RecaptchaLogItem>));
        log = (List<RecaptchaLogItem>)serializer.Deserialize(stream);
    }
}

You should now be able to use the extension with the DbBlogProvider without any problems. The rest of the extension seems to work without any problems and appears to be well written overall. It is definitely worth checking out if you are looking for a reCAPTCHA solution for BlogEngine.NET.

Tags:

BlogEngine.NET | Web Development

DomainDataSource Extension Methods

by Alex Meyer-Gleaves 13 August 2009 - 6:48 PM

To add a new item or edit an existing item in the DomainDataSource that ships with the .NET RIA Services, you must first cast the DataView property to an IEditableCollectionView. Jeff Handley does a good job of explaining the reason for this in his DomainDataSource.DataView post.

David Yack left a comment on the .NET RIA Services forum with a link to his post where he shares his inherited DomainDataSource class. The inherited class adds methods for adding and editing items that do all the casting to IEditableCollectionView for you. I really liked the idea but didn’t want to create my own derived class, so I took his implementation and turned it into a set of extension methods that are exposed on all DomainDataSource instances.

Update (24-09-2009): Added a Remove extension method. Thanks to Phil Steel for posting the code in his comment.

/// <summary>
///    Extensions to the <see cref="DomainDataSource"/> for adding and editing items.
/// </summary>
public static class DomainDataSourceExtensions
{
    /// <summary>
    /// Adds a new item to the collection.
    /// </summary>
    /// <typeparam name="T">The type of the item to add.</typeparam>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <returns>The newly added item.</returns>
    public static T AddNew<T>(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        return (T)collection.AddNew();
    }

    /// <summary>
    /// Edits an item in the collection.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <param name="itemToEdit">The item to edit.</param>
    public static void EditItem(this DomainDataSource source, object itemToEdit)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        collection.EditItem(itemToEdit);
    }

    /// <summary>
    /// Removes an item from the collection.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    /// <param name="itemToRemove">The item to remove.</param>
    public static void Remove(this DomainDataSource source, object itemToRemove)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        collection.Remove(itemToRemove);
    }

    /// <summary>
    /// Commits the add or edit transaction.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    public static void CommitNewAndEdit(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        if (collection.IsAddingNew)
        {
            collection.CommitNew();
        }
        if (collection.IsEditingItem)
        {
            collection.CommitEdit();
        }
    }

    /// <summary>
    /// Cancels the add or edit transaction.
    /// </summary>
    /// <param name="source">The <see cref="DomainDataSource"/> being extended.</param>
    public static void CancelNewAndEdit(this DomainDataSource source)
    {
        IEditableCollectionView collection = ((IEditableCollectionView)source.DataView);
        if (collection.IsAddingNew)
        {
            collection.CancelNew();
        }
        if (collection.IsEditingItem)
        {
            collection.CancelEdit();
        }
    } 
}

Thanks for sharing the code David.

Tags: ,

Silverlight | Web Development

Using REST in NAnt with a custom HTTP Task

by Alex Meyer-Gleaves 18 June 2009 - 5:42 PM

I needed to make HTTP requests to a REST web service from a NAnt script today so I knocked up a custom task. The HttpClient class from the WCF REST Starter Kit that I blogged about previously came in handy to offload most of the heavy lifting, leaving me to worry about the task related implementation details. The task supports all the HTTP methods and allows you to specify the content type and the content itself. You can also retrieve the response content and status code through properties set by the task. This was all achieved with surprisingly little code.

using System;
using System.Collections.Generic;
using System.Net;

using Microsoft.Http;

using NAnt.Core;
using NAnt.Core.Attributes;

namespace AlexMG.NAntTasks
{
    [TaskName("http")]
    public class HttpTask : Task
    {
        private static readonly List<HttpStatusCode> successCodes = new List<HttpStatusCode>
        {
            HttpStatusCode.OK,
            HttpStatusCode.Created,
            HttpStatusCode.Accepted,
            HttpStatusCode.NonAuthoritativeInformation,
            HttpStatusCode.NoContent,
            HttpStatusCode.ResetContent,
            HttpStatusCode.PartialContent
        };

        [TaskAttribute("url", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string Url { get; set; }

        [TaskAttribute("method", Required = false)]
        [StringValidator(AllowEmpty = true)]
        public string Method { get; set; }

        [TaskAttribute("content", Required = false)]
        [StringValidator(AllowEmpty = true)]
        public string Content { get; set; }

        [TaskAttribute("contenttype", Required = false)]
        [StringValidator(AllowEmpty = true)]
        public string ContentType { get; set; }

        [TaskAttribute("connectiontimeout", Required = false)]
        public int ConnectionTimeout { get; set; }

        [TaskAttribute("responseproperty", Required = false)]
        [StringValidator(AllowEmpty = true)]
        public string ResponseProperty { get; set; }

        [TaskAttribute("statuscodeproperty", Required = false)]
        [StringValidator(AllowEmpty = true)]
        public string StatusCodeProperty { get; set; }

        protected override void ExecuteTask()
        {
            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage();

            if (!string.IsNullOrEmpty(Method))
            {
                request.Method = Method;
            }

            request.Uri = new Uri(Url);
            
            if (!string.IsNullOrEmpty(ContentType))
            {
                request.Headers.ContentType = ContentType;
            }

            if (!request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase))
            {
                request.Content = (string.IsNullOrEmpty(Content)) ? HttpContent.CreateEmpty() : HttpContent.Create(Content);
                request.Headers.ContentLength = request.Content.GetLength();
            }
            
            if (ConnectionTimeout != 0)
            {
                client.TransportSettings.ConnectionTimeout = TimeSpan.FromSeconds(ConnectionTimeout);
            }

            Project.Log(Level.Info, "Executing HTTP request.");
            Project.Log(Level.Info, "Url: {0}", request.Uri);
            Project.Log(Level.Info, "Method: {0}", request.Method);
            Project.Log(Level.Info, "Content Type: {0}", request.Headers.ContentType);
            Project.Log(Level.Info, "Connection Timeout: {0}", client.TransportSettings.ConnectionTimeout);

            try
            {
                HttpResponseMessage response = client.Send(request);

                if (FailOnError)
                {
                    response.EnsureStatusIsSuccessful();    
                }

                if (!string.IsNullOrEmpty(StatusCodeProperty))
                {
                    Project.Properties[StatusCodeProperty] = response.StatusCode.ToString();
                }

                if (successCodes.Contains(response.StatusCode) && !string.IsNullOrEmpty(ResponseProperty))
                {
                    Project.Properties[ResponseProperty] = response.Content.ReadAsString();
                }

                Project.Log(Level.Info, "Received HTTP response.");
                Project.Log(Level.Info, "Status Code: {0}", response.StatusCode);
                Project.Log(Level.Info, "Content Type: {0}", response.Headers.ContentType);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                string message = string.Format("The HTTP '{0}' request to '{1}' failed:{2}{3}", Method, Url, Environment.NewLine, ex.Message);
                throw new BuildException(message, ex);
            }
        }
    }
}

Using the task is simple. The only mandatory attribute is url and the default HTTP method is GET. Here is a sample NAnt project showing how to use the <http/> task.

<?xml version="1.0"?>
<project name="Http">
  <http url="http://www.howtocreate.co.uk/operaStuff/userjs/samplexml.xml"
        method="GET"
        contenttype="text/xml"
        connectiontimeout="30"
        responseproperty="response"
        statuscodeproperty="status"
        failonerror="true" />

  <echo message="Response: ${response}" />
  <echo message="Status Code: ${status}" />
</project>

I have attached the source code and task assembly below. The compiled assembly has the Microsoft.Http.dll assembly from the WCF REST Starter Kit merged into it using the ILMerge tool. This makes deployment easier by removing the chance of accidentally forgetting to deploy the dependency. If you are compiling from source code you will need to update the xcopy command in the post-build event to point to the location of your NAnt bin folder.

HttpNAnt Binary.zip (139.62 kb)

HttpNAnt Source.zip (1.06 mb)

Tags: , , ,

Garage Sale Code | Development Tools | Web Development | Web Services

C# wrapper for the Google AJAX Language API

by Alex Meyer-Gleaves 28 April 2009 - 6:09 PM

Introduction

The Google AJAX Language API allows you to perform text translations using a REST based web service API. Being an AJAX targeted API the web service returns a JSON formatted response that is easy to work with in JavaScript. Working with REST web services and JSON responses in C# is also easy. I decided to check out the API by writing a C# wrapper that would allow me to easily translate a string in any of the supported languages. A quick search will show that I am certainly not the first person to do this, but I don’t care as I wanted to do it my way and for myself.

Response Classes

The DataContractJsonSerializer added to the .NET Framework 3.5 makes it easy to serialize and deserialize between JSON and CLR objects. I created classes to represented the JSON response from the web service. The first is the TranslationResponse. You will notice I have used the DataContract and DataMember attributes so I can map my Pascal cased property names to the camel cased property names used in the JSON response. Even when working with JSON it feels dirty when I don’t follow my naming conventions.

/// <summary>
///     The translation response returned from Google.
/// </summary>
[DataContract(Name = "translateResponse")]
public class TranslationResponse
{
    /// <summary>
    ///     Gets or sets the response data.
    /// </summary>
    [DataMember(Name = "responseData")]
    public ResponseData ResponseData { get; set; }

    /// <summary>
    ///     Gets or sets the response details.
    /// </summary>
    /// <remarks>
    ///     This value is only present when the request fails
    ///     and will contain a diagnostic string.
    /// </remarks>
    [DataMember(Name = "responseDetails")]
    public string ResponseDetails { get; set; }

    /// <summary>
    ///     Gets or sets the response status.
    /// </summary>
    /// <remarks>
    ///     A status other than 200 indicates failure.
    /// </remarks>
    [DataMember(Name = "responseStatus")]
    public int ResponseStatus { get; set; }
}

The second class is ResponseData that contains the translated text and source language if it was automatically detected. This occurs when the source language is not provided in the request.

/// <summary>
///     The data part of the response from Google.
/// </summary>
[DataContract(Name = "responseData")]
public class ResponseData
{
    /// <summary>
    ///     Gets or sets the translated text.
    /// </summary>
    [DataMember(Name = "translatedText")]
    public string TranslatedText { get; set; }

    /// <summary>
    ///     Gets or sets the detected source language.
    /// </summary>
    /// <remarks>
    ///     This value is only present when the source language was not provided
    ///     in the request and needed to be detected automatically.
    /// </remarks>
    [DataMember(Name = "detectedSourceLanguage")]
    public string DetectedSourceLanguage { get; set; }
}

Request Helpers

I created some classes to help make the request simple to construct. The Language class contains a property for each of the supported languages. The properties return two letter ISO language names that are used in the request. I grabbed the list from the documentation and with a quick bit of string replacement had the C# class ready to go. You didn’t really think I typed them all out did you?

/// <summary>
///     The languages supported by the Google AJAX Language API.
/// </summary>
public static class Language
{
    public static readonly string Afrikaans = "af";
    public static readonly string Albanian = "sq";
    public static readonly string Amharic = "am";
    public static readonly string Arabic = "ar";
    public static readonly string Armenian = "hy";
    public static readonly string Azerbaijani = "az";
    public static readonly string Basque = "eu";
    public static readonly string Belarusian = "be";
    public static readonly string Bengali = "bn";
    public static readonly string Bihari = "bh";
    public static readonly string Bulgarian = "bg";
    public static readonly string Burmese = "my";
    public static readonly string Catalan = "ca";
    public static readonly string Cherokee = "chr";
    public static readonly string Chinese = "zh";
    public static readonly string ChineseSimplified = "zh-CN";
    public static readonly string ChineseTraditional = "zh-TW";
    public static readonly string Croatian = "hr";
    public static readonly string Czech = "cs";
    public static readonly string Danish = "da";
    public static readonly string Dhivehi = "dv";
    public static readonly string Dutch = "nl";
    public static readonly string English = "en";
    public static readonly string Esperanto = "eo";
    public static readonly string Estonian = "et";
    public static readonly string Filipino = "tl";
    public static readonly string Finnish = "fi";
    public static readonly string French = "fr";
    public static readonly string Galician = "gl";
    public static readonly string Georgian = "ka";
    public static readonly string German = "de";
    public static readonly string Greek = "el";
    public static readonly string Guarani = "gn";
    public static readonly string Gujarati = "gu";
    public static readonly string Hebrew = "iw";
    public static readonly string Hindi = "hi";
    public static readonly string Hungarian = "hu";
    public static readonly string Icelandic = "is";
    public static readonly string Indonesian = "id";
    public static readonly string Inuktitut = "iu";
    public static readonly string Italian = "it";
    public static readonly string Japanese = "ja";
    public static readonly string Kannada = "kn";
    public static readonly string Kazakh = "kk";
    public static readonly string Khmer = "km";
    public static readonly string Korean = "ko";
    public static readonly string Kurdish = "ku";
    public static readonly string Kyrgyz = "ky";
    public static readonly string Laothian = "lo";
    public static readonly string Latvian = "lv";
    public static readonly string Lithuanian = "lt";
    public static readonly string Macedonian = "mk";
    public static readonly string Malay = "ms";
    public static readonly string Malayalam = "ml";
    public static readonly string Maltese = "mt";
    public static readonly string Marathi = "mr";
    public static readonly string Mongolian = "mn";
    public static readonly string Nepali = "ne";
    public static readonly string Norwegian = "no";
    public static readonly string Oriya = "or";
    public static readonly string Pashto = "ps";
    public static readonly string Persian = "fa";
    public static readonly string Polish = "pl";
    public static readonly string Portuguese = "pt-PT";
    public static readonly string Punjabi = "pa";
    public static readonly string Romanian = "ro";
    public static readonly string Russian = "ru";
    public static readonly string Sanskrit = "sa";
    public static readonly string Serbian = "sr";
    public static readonly string Sindhi = "sd";
    public static readonly string Sinhalese = "si";
    public static readonly string Slovak = "sk";
    public static readonly string Slovenian = "sl";
    public static readonly string Spanish = "es";
    public static readonly string Swahili = "sw";
    public static readonly string Swedish = "sv";
    public static readonly string Tagalog = "tl";
    public static readonly string Tajik = "tg";
    public static readonly string Tamil = "ta";
    public static readonly string Telugu = "te";
    public static readonly string Thai = "th";
    public static readonly string Tibetan = "bo";
    public static readonly string Turkish = "tr";
    public static readonly string Uighur = "ug";
    public static readonly string Ukrainian = "uk";
    public static readonly string Unknown = "";
    public static readonly string Urdu = "ur";
    public static readonly string Uzbek = "uz";
    public static readonly string Vietnamese = "vi";
}

I also created a TextFormat enumeration that allows you to specify the format of the text to be translated. The only choices are HTML or plain text. If the URL argument for “format” is not provided the Language API assumes that the input is plain text.

/// <summary>
///     The format of the text to be translated.
/// </summary>
public enum TextFormat
{
    /// <summary>
    ///     The text to translate is HTML.
    /// </summary>
    Html,

    /// <summary>
    ///     The text to translate is plain text.
    /// </summary>
    Text
}

Making the Request

To make the request I decided to use the HttpClient class from the WCF REST Starter Kit. I have blogged about this class previously and it makes working with REST web services a walk in the park. Before jumping into the actual implementation lets have a look at some sample calling code. The static Google class contains an overloaded Translate method that accepts parameters for the text to be translated, source language, destination language and input text format.

TranslationResponse response = Google.Translate("Hello, world!", Language.English, Language.French, TextFormat.Text);

Console.WriteLine("Status: " + response.ResponseStatus);
Console.WriteLine("Details: " + response.ResponseDetails);
Console.WriteLine("Detected Source Language: " + response.ResponseData.DetectedSourceLanguage);
Console.WriteLine("Translated Text: " + response.ResponseData.TranslatedText);

The Language class can be used to specify the source and destination languages. The language parameters are actually string values and can be provided dynamically if required. Using the Language class is simply a convenience that ensures the language values are correct and makes the method easier to use when the values can be hardcoded.

The TextFormat enumeration is used to indicate the format of the text to be translated. Because the parameter is an enumeration the value provided can never be invalid. Plain text is the default when an overload of the Translate method is used that does not require a value for the parameter.

The Translate method returns the deserialized TranslationResponse. I decided to return the response object as it is difficult to report errors without throwing an exception if only the translated text is returned. The response can also include other useful information and I didn’t want to use out parameters to return it.

If the ResponseStatus property of the response contains a value other than 200 a failure has occurred. This value can be different to the real HTTP status code returned to the HttpClient. If the call “virtually” failed the ResponseDetails property will contain an error message and the ResponseData property will be null. If the call was successful the TranslatedText property of the ResponseData will contain the translated text. The DetectedSourceLanguage property will only contain a value if the source language was not provided and was discovered during translation.

Implementation Details

The Translate method from the Google class can be seen below.

/// <summary>
///     Translates the specified text.
/// </summary>
/// <param name="text">
///     The text to translate.
/// </param>
/// <param name="sourceLanguage">
///     The language to translate from.
/// </param>
/// <param name="destinationLanguage">
///     The language to translate to.
/// </param>
/// <param name="textFormat">
///     The format of the text to be translated.
/// </param>
/// <returns>
///     A response that includes the translated text and status information.
/// </returns>
/// <exception cref="ArgumentException">
///     Thrown if the text to translate or destination language is null or empty.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
///     Thrown if the HTTP response status code is not 200.
/// </exception>
/// <exception cref="ApplicationException">
///     Thrown if the response fails due to a non-communication related problem.
///     The response details returned from Google are included in the exception message.
/// </exception>
/// <remarks>
///     If the source language is not provided it will be automatically detected.
/// </remarks>
public static TranslationResponse Translate(string text, string sourceLanguage, string destinationLanguage, TextFormat textFormat)
{
    if (string.IsNullOrEmpty(text)) throw new ArgumentException("The 'text' parameter is invalid.", "text");
    if (string.IsNullOrEmpty(destinationLanguage)) throw new ArgumentException("The 'destinationLanguage' parameter is invalid.", "destinationLanguage");

    HttpClient client = new HttpClient("http://ajax.googleapis.com/");

    HttpQueryString queryString = new HttpQueryString
    {
        {"v", "1.0"},
        {"hl", Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName},
        {"langpair", string.Format("{0}|{1}", sourceLanguage.ToLowerInvariant(), destinationLanguage.ToLowerInvariant())},
        {"q", text},
        {"format", textFormat.ToString().ToLower()}
    };

    Uri serviceUri = new Uri("ajax/services/language/translate", UriKind.Relative);

    HttpResponseMessage responseMessage = client.Get(serviceUri, queryString);
    responseMessage.EnsureStatusIsSuccessful();

    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TranslationResponse));
    return (TranslationResponse)serializer.ReadObject(responseMessage.Content.ReadAsStream());
}

After checking the required arguments have been provided a new instance of the HttpClient is created. The client is provided with the Google API domain name for the base address. Next the HttpQueryString class, also from the starter kit, is used to build the query string. This class takes care of all the encoding and string formatting work.

The query string arguments are straight forward:

  • “v” is the version of the API and is hardcoded to “1.0”.
  • “hl” is the host language which is retrieved from the current thread.
  • “langpair” is a pipe separated pair of two letter ISO language names.
  • “q” is the text to be translated.
  • “format” indicates the format of the text to be translated (HTML or plain text).

A new Uri instance is created with the relative address to the translation web service. When the Get method is called on the HttpClient with the relative URL and query string a HttpResponseMessage is returned. The EnsureStatusIsSuccessful method on the response is called to ensure that the HTTP status code returned is 200 (OK). An ArgumentOutOfRangeException will be thrown if the status code is not 200.

Finally, an instance of the DataContractJsonSerializer is created ready to serialize and deserialize instances of the TranslationResponse type. The HTTP response is retrieved as a Stream and provided to the ReadObject method of the DataContractJsonSerializer. The deserialized response is then returned to the caller.

Summary

The Language API is an example of another service from Google that is both cool and free. The WCF REST Starter Kit makes working with REST web services really simple, and JSON is no longer a format that is only useful to web developers working in JavaScript thanks to the DataContractJsonSerializer. I have attached a Visual Studio 2008 solution with the full source code.

GoogleTranslator.zip (136.21 kb)

Tags: ,

Garage Sale Code | Web Development | Web Services

Bugs in the bit.ly REST API

by Alex Meyer-Gleaves 17 April 2009 - 8:15 PM

Introduction

bit.ly is one of the many websites that offer URL shortening services. It’s certainly one of the better services and integrates nicely with Twitter. I decided to take a look at their REST API but quickly found problems with the expand service, including an obvious bug when results are returned as XML instead of JSON. All of the services allow you to specify JSON or XML as the format for the response. The default response format is JSON.

Invalid XML

The service for expanding a URL from its shortened representation returns XML that includes the hash for the URL as one of the elements. The problem is that the hash for a URL can, and often does, start with a numeric character. One of the naming rules for an XML element name is that it cannot start with a numeric or punctuation character.

If you run the example URL provided in the API documentation for expand in the browser, and append format=xml to the query string, you will see a parsing error regarding the element name. You can test the link below and see that an error will be displayed regardless of the browser you are using. Firefox, Internet Explorer and Google Chrome all validate an XML response before rendering it.

http://api.bit.ly/expand?version=2.0.1&shortUrl=http://bit.ly/31IqMl&login=bitlyapidemo&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&format=xml

This also means you cannot load the XML into an XDocument or XmlDocument in .NET. Both classes validate the XML and throw an XmlException if validation fails. When provided with the invalid XML both throw an exception with the same message:

System.Xml.XmlException: Name cannot begin with the '3' character, hexadecimal value 0x33. Line 5, position 4.

You can see the problem element on line 5 in the XML below. If you attempt to use the Paste XML as Types feature in the WCF REST Starter Kit with this XML you will find that it also throws the same exception.

<bitly>
    <errorCode>0</errorCode>
    <errorMessage></errorMessage>
    <results>
        <31IqMl>
            <longUrl>http://cnn.com/</longUrl>
        </31IqMl>
    </results>
    <statusCode>OK</statusCode>
</bitly>

Serialization Issues

The JSON and XML responses from the expand service are not serialization friendly for .NET consumers. Had the Paste XML as Types feature mentioned above actually managed to generate a .NET type you would find that it too was invalid. The hash name that was invalid in the XML also prevents you from creating a .NET type to use with serializers such as the XmlSerializer, DataContractSerializer and DataContractJsonSerializer.

The naming issue still exists, except this time instead of XML elements, it’s the names of .NET properties that cannot start with a number. The more important issue though is that the names of the XML element and JSON pairs are actually variable. This prevents them from being mapped to a property on a .NET type by the serializer. If the hash was a value associated with a fixed XML element name or JSON pair name you would be able to deserialize the result into a .NET type.

Conclusion

The other services in the bit.ly REST API do not suffer the same problem. They use fixed and valid names for the XML elements and JSON pairs. Despite being a little surprised to find these problems, I remain a fan of the bit.ly service and would happily recommend it. These sort of mistakes happen to all of us, but you never hope to see them find their way into a public API.

Tags: ,

Web Development

About the author

Alex Meyer-Gleaves I'm a Technical Architect living in Australia (that island like continent in the southern hemisphere). I love Microsoft .NET and C#. I hate early mornings, slow drivers and Lotus Notes.

Twitter

Google Shared

 

Month List

Recent Comments

Comment RSS

Links

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010