Implementing a Unit Of Work with WCF WebApi

1.3k views Asked by At

One of the challenges I'm facing with the new WCF WebApi is that I cannot cleanly implement a UnitOfWork pattern.

As a quick background, the pattern works by starting a unit-of-work at the beginning of the request, doing some work, and then afterwards either rolling back or committing the unit of work.

It's pretty easy to setup code which will "start" the unit-of-work, utilizing the HttpMessageHandler functionality. And via Task<> library, I can write a continuation which executes after the request is handled. However, I cannot always determine if a fault occurred so that I can rollback.

WCF has low-level support for faults, and in a traditional WCF service endpoint you can check to see if the channel has faulted (for instance, from inside an IMessageInspector). But the WebApi seems to be preventing this behavior.

The WebApi does expose an HttpErrorHandler contract. However this is very limited since you don't have access to the instance context or service instance, so I don't have access to my unit-of-work.

I wonder what other approaches have been used to implement the unit-of-work pattern here?

4

There are 4 answers

0
Joseph Daigle On BEST ANSWER

Pedro and Darrel both gave great suggestions. In the solution I finally came up with, I ended up using a message handler:

public class UnitOfWorkHandler : DelegatingHandler 
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    {
        var unitOfWork = new UnitOfWork();
        unitOfWork.Begin();
        return base.SendAsync(request, cancellationToken).ContinueWith(result => 
            {
                if (result.Result is HttpResponseMessage && ((HttpResponseMessage)result.Result).IsSuccessStatusCode) 
                {
                    unitOfWork.Commit();
                } 
                else 
                {
                    unitOfWork.Rollback();
                }
                return result.Result;
            });
    }
}

I would have used Darrel's suggestion of storing a reference to the UnitOfWork on the HttpRequestMessage properties collection, however since the Task continuation is implemented as a closure I can simply reference the unit of work I created in its outer scope.

0
Joel On

My scenario:

  • Controller (needs repo)
  • Repo (needs IUnitOfWork)
  • Action filter (needs IUnitOfWork as well)

The problem:

DI in action filter has been bothering me for a while. I like Joseph's approach, I really do. Having my unit of work created (or started) before each request seems natural to me. Since action filters may be cached, they don't use the same dependency scope as controllers. Hence, Setter injection is need.

The solution:

Configure structuremap the same way as I would if I had no action filters. Something like this:

public class NHibernateRegistry : Registry
{
    public NHibernateRegistry()
    {
        For<ISessionFactory>).Singleton().Use(
            NhSessionFactoty.Instance.SessionFactory);
        For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<NhUnitOfWork>();
        For(typeof(IBaseRepository<,>)).Use(typeof(BaseRepository<,>));
    }
}

NhSessionFactoty encapsulates my hibernate config and allows to get a single ISessionFactory to use in my application. NhUnitOfWork implements my IUnitOfWork interface, and handles session and transaction management.

The action filter attribute (adapted from Joseph's answer):

public class UnitOfWorkAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        /* Check this line, it's a problem solver!! */
        var uow = (IUnitOfWork)actionContext.Request.GetDependencyScope()
            .GetService(typeof(IUnitOfWork));
        uow.Begin();
    }

    public override void OnActionExecuted(
        HttpActionExecutedContext actionExecutedContext)
    {
        var uow = (IUnitOfWork)actionExecutedContext.Request.GetDependencyScope()
            .GetService(typeof(IUnitOfWork));

        try
        {
            if (actionExecutedContext.Exception == null)
                uow.Commit();
            else
                uow.Rollback();
        }
        catch
        {
            uow.Rollback();
            throw;
        } 
        /*finally
        {
            uow.Dispose();
        }*/ // Resources are released in Application_EndRequest (Globals.cs)
    }
}

and finally my base controller:

[UnitOfWork]
public class ControllerBaseUow : ApiController {}
/* Then, in my case, I inject Repositories via contructor */

It works because in OnActionExecuting we get the same dependency scope used in controllers.

then work like you normally would with DI :)

0
Pedro Felix On

1) You can use operation handlers or message handlers to set up and tear down the Unit of Work (UoW) a) Message handlers have endpoint scope, so they apply to all the operations. b) Operation handlers have operation scope and may be useful if only some operation require the UoW.

2) As Darrel stated, all the contextual information regarding a HTTP request should be added to the HttpRequestMessage property bag.

3) In the Web API model, there aren't faults (fault is a SOAP construct). You probably should rely on the HTTP response status to check if the operation was sucessfull (2xx) or not (4xx, 5xx).

1
Darrel Miller On

There is a properties collection that hangs off HttpRequestMessage that you can probably stuff your unit of work object in so that you can access it on the return path.