Transaction Per Request using AutoFac in WebAPI

When working with business applications, transactions plays an important role and providing atomic transactions is a good practice to commit or rollback transaction on either condition. In this post we will implement the Transaction per request in Web API controllers using AutoFac and action filters. Transaction per request is a recommended approach when designing your Web API as it provides the Database object per request and no matter how many transactions you are doing in particular request but provides commit and rollback feature using action filters. We will see how easy it is to handle that using AutoFac dependency injector

Following are the steps you can implement in your Web API project to implement Transaction Per request.

1. FIrst of all add the Autofac for Web API package through NuGet

image

2. Add Entity framework file and connect to some data source. In my case I have ProductEntities and below is the Web API code of Products

public class ProductsController : ApiController
{

ProductsEntities context;

public ProductsController(ProductsEntities entities)
{
context = entities;
}

// GET: api/Products
public IEnumerable<Product> Get()
{
return context.Products.AsEnumerable();
}

// GET: api/Products/5
public Product Get(int id)
{
return context.Products.Where(i => i.ProductID == id).FirstOrDefault();
}

// POST: api/Products
public void Post(Product product)
{
context.Products.Add(product);
context.SaveChanges();

}

// DELETE: api/Products/5
public void Delete(int id)
{
var product = context.Products.Where(i => i.ProductID == id).FirstOrDefault();
if (product != null)
{
context.Products.Remove(product);
context.SaveChanges();
}
}
}

 

I have defined a pamaterized constructor that takes ProductEntities as a parameter to perform CRUD operation on database

4. Now go to your Startup class and write following code snippet.

using Autofac;
using Autofac.Integration.WebApi;
using System.Reflection;

public void Configuration(IAppBuilder app)
{

        var builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;

//Register all Controllers with AutoFac so it will inject ProductEntities by calling
//parameterized constructors
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);

//Initialize ProductEntities per request
builder.RegisterType<ProductsEntities>().InstancePerRequest();

var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

ConfigureAuth(app);

}

First initialize the dependency container builder object and register API controllers that resides in your project by calling builder.RegisterApiControllers method.  After that I have register the ProductEntities type as InstancePerRequest. This InstancePerRequest will create the new context object per request to preform CRUD operation. Next, build your builder and specify the dependency resolver for your Web API.

5. That’s all set for injecting ProductEntities in Web API Controllers

6. Now in order to handle transactions, we will create a custom ActionFilter class that imlements IAutofacActionFilter interface

It provides two methods OnActionExecuted and OnActionExecuting that you can use to perform begin transactions and commit/rollback transactions.

public class TransactionActionFilter : IAutofacActionFilter
{
public void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
throw new NotImplementedException();
}

public void OnActionExecuting(HttpActionContext actionContext)
{
throw new NotImplementedException();
}
}

But before writing code to begin or commit transactions we have to inject the ProductEntities so create parameterized constructor and pass ProductEntities. So lets add a TransactionActionFilter constructer with having ProductEnttities as a parameter

ProductsEntities context;
public TransactionActionFilter(ProductsEntities entities)
{
context = entities;
}

7. Following is the code to handle transactions on action executed and executing methods

DbContextTransaction currentTransaction;

public void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Exception != null)
currentTransaction.Rollback();
else
currentTransaction.Commit();
}

public void OnActionExecuting(HttpActionContext actionContext)
{
currentTransaction= context.Database.BeginTransaction();
}

 

8. Finally, register the action filter for Web API controller method to which you want to have transaction applied on. Once the request comes the OnExecuting will be invoked before the actual method call and after it is executed OnExecuted method will be invoked which check if there is any exception and commit or rollback the transaction accordingly.

Register Web API Filter provider

builder.RegisterWebApiFilterProvider(config);

Then add following code to register TransactionActionFilter with your Web API Controller’s method.

builder.Register(c => new TransactionActionFilter(c.Resolve<ProductsEntities>()))
.AsWebApiActionFilterFor<ProductsController>(c => c.Post(default(Product)))
.InstancePerRequest();

 

builder.Build() should be called after all declaration of container injections.

Hope this helps!