Autofac Open Generics Feature to Register Generic Services

Autofac, an awesome IoC container for .NET platform, has an out of the box generic service registration feature which we will quickly cover in this blog post.
2013-02-05 08:46
Tugberk Ugurlu


This is going to be a quick and dirty blog post but hopefully, will take this giant stupidity out of me. Autofac, an awesome IoC container for .NET platform, has an out of the box generic service registration feature and I assume nearly all IoC containers have this today which makes me feel stupid because I have been knowing this for only a month or so Smile I was doing something like below before.

private static void RegisterRepositories(ContainerBuilder builder) {
 
    Type baseEntityType = typeof(BaseEntity);
    Assembly assembly = baseEntityType.Assembly;
    IEnumerable<Type> entityTypes = assembly.GetTypes().Where(
        x => x.IsSubclassOf(baseEntityType));
        
    foreach (Type type in entityTypes) {
 
        builder.RegisterType(typeof(EntityRepository<>)
               .MakeGenericType(type))
               .As(typeof(IEntityRepository<>).MakeGenericType(type))
               .InstancePerApiRequest();
    }
}

Then, Ben Foster pinged me on twitter:

This tweet made me look for alternative approaches and I found out the Autofac's generic service registration feature. Here is how it looks like now:

private static void RegisterRepositories(ContainerBuilder builder) {
 
    builder.RegisterGeneric(typeof(EntityRepository<>))
           .As(typeof(IEntityRepository<>))
           .InstancePerApiRequest();
}

Way better! Autofac also respects generic type constraints. Here is a quote from the Autofac documentation:

Autofac respects generic type constraints. If a constraint on the implementation type makes it unable to provide a service the implementation type will be ignored.

If you didn't know this feature before, you do know it now Smile Enjoy it!

Hierarchical Resource Structure in ASP.NET Web API

This post explains the concerns behind the hierarchical resource structure in ASP.NET Web API such as routing, authorization and ownership.
2013-02-04 08:11
Tugberk Ugurlu


I came across a question on Stackoverflow today about the hierarchical resource structure in ASP.NET Web API: http://stackoverflow.com/questions/14674255. The question is basically about the following issue:

I have the following schema that I'd like to implement in ASP.NET Web API. What is the proper approach?

http://mydomain/api/students
http://mydomain/api/students/s123
http://mydomain/api/students/s123/classes
http://mydomain/api/students/s123/classes/c456

With this nice hierarchical approach, you have more concerns that routing here in terms of ASP.NET Web API. There is a good sample application which adopts the hierarchical resource structure: PingYourPackage. I definitely suggest you to check it out.

Let me explain the concerns here in details by setting up a sample scenario. This may not be the desired approach for these types of situations but lays out the concerns very well and if you have a better way to eliminate these concerns, I'd be more that happy to hear those.

Let's say you have the below two affiliates inside your database for a shipment company:

  • Affiliate1 (Id: 100)
  • Affiliate2 (Id: 101)

And then assume that these affiliates have some shipments attached to them:

  • Affiliate1 (Key: 100)
    • Shipment1 (Key: 100)
    • Shipment2 (Key: 102)
    • Shipment4 (Key: 104)
  • Affiliate2 (Key: 101)
    • Shipment3 (Key: 103)
    • Shipment5 (Key: 105)

Finally, we want to have the following resource structure:

  • GET api/affiliates/{key}/shipments
  • GET api/affiliates/{key}/shipments/{shipmentKey}
  • POST api/affiliates/{key}/shipments
  • PUT api/affiliates/{key}/shipments/{shipmentKey}
  • DELETE api/affiliates/{key}/shipments/{shipmentKey}

In view of ASP.NET Web API, we have three obvious concerns here: routing, authorization and ownership. Let's go through this one by one.

The below code snippets have been taken from the PingYourPackage source code. They won't probably work if you copy and paste them but you will get the idea.

Routing Concerns

Assume that we are sending a GET request against /api/affiliates/105/shipments/102 (considering our above scenario). Notice that the affiliate key is 105 here which doesn't exist. So, we would want to terminate the request here ASAP. We can achieve this with a per-route message handler as early as possible. The following AffiliateShipmentsDispatcher is responsible for checking the affiliate existence and acting on the result.

public class AffiliateShipmentsDispatcher : DelegatingHandler {

  protected override Task<HttpResponseMessage> SendAsync(
      HttpRequestMessage request, 
      CancellationToken cancellationToken) {

      // We know at this point that the {key} route variable has 
      // been supplied. Otherwise, we wouldn't be here. So, just get it.
      IHttpRouteData routeData = request.GetRouteData();
      Guid affiliateKey = Guid.ParseExact(routeData.Values["key"].ToString(), "D");

      IShipmentService shipmentService = request.GetShipmentService();
      if (shipmentService.GetAffiliate(affiliateKey) == null) {

          return Task.FromResult(
              request.CreateResponse(HttpStatusCode.NotFound));
      }

      return base.SendAsync(request, cancellationToken);
  }
}

I am here using a few internal extension methods which are used inside the project but the idea is simple: go to the database and check the existence of the affiliate. If it doesn't exist, terminate the request and return back the "404 Not Found" response. If it exists, continue executing by calling the base.SendAsync method which will invoke the next message handler inside the chain. Which message handler is the next here? Good question, you dear reader! It's going to be the HttpControllerDispatcher which basically puts us inside the controller pipeline. To attach this handler to a route, we need to create a pipeline first to include the controller pipeline by chaining AffiliateShipmentsDispatcher and HttpControllerDispatcher together. The following code snippet shows the AffiliateShipmentsHttpRoute registration.

public class RouteConfig {

    public static void RegisterRoutes(HttpConfiguration config) {

        var routes = config.Routes;

        // Pipelines
        HttpMessageHandler affiliateShipmentsPipeline =
            HttpClientFactory.CreatePipeline(
                new HttpControllerDispatcher(config),
                new[] { new AffiliateShipmentsDispatcher() });

        // Routes
        routes.MapHttpRoute(
            "AffiliateShipmentsHttpRoute",
            "api/affiliates/{key}/shipments/{shipmentKey}",
            defaults: new { controller = "AffiliateShipments", shipmentKey = RouteParameter.Optional },
            constraints: null,
            handler: affiliateShipmentsPipeline);

        routes.MapHttpRoute(
            "DefaultHttpRoute",
            "api/{controller}/{key}",
            defaults: new { key = RouteParameter.Optional },
            constraints: null);
    }
}

Authorization Concerns

If you have some type of authentication in place, you would want to make sure (in our scenario here) that the authenticated user and the requested affiliate resource is related. For example, assume that Affiliate1 is authenticated under the Affiliate role and you have the AuthorizeAttribute registered to check the "Affiliate" role authorization. In this case, you will fail miserably because this means that Affiliate1 can get to the following resource: /api/affiliates/101/shipments which belongs to Affiliate2. We can eliminate this problem with a custom AuthorizeAttribute which is similar to below one:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AffiliateShipmentsAuthorizeAttribute : AuthorizeAttribute {

    public AffiliateShipmentsAuthorizeAttribute() {

        base.Roles = "Affiliate";
    }

    public override void OnAuthorization(HttpActionContext actionContext) {
        
        base.OnAuthorization(actionContext);

        // If not authorized at all, don't bother checking for the 
        // user - affiliate relation
        if (actionContext.Response == null) { 

            // We are here sure that the request has been authorized and 
            // the user is in the Affiliate role. We also don't need 
            // to check the existence of the affiliate as it has 
            // been also already done by AffiliateShipmentsDispatcher.

            HttpRequestMessage request = actionContext.Request;
            Guid affiliateKey = GetAffiliateKey(request.GetRouteData());
            IPrincipal principal = Thread.CurrentPrincipal;
            IShipmentService shipmentService = request.GetShipmentService();
            bool isAffiliateRelatedToUser =
                shipmentService.IsAffiliateRelatedToUser(
                    affiliateKey, principal.Identity.Name);

            if (!isAffiliateRelatedToUser) {

                // Set Unauthorized response as the user and 
                // affiliate isn't related to each other. You might
                // want to return "404 NotFound" response here if you don't
                // want to expose the existence of the affiliate.
                actionContext.Response = 
                    request.CreateResponse(HttpStatusCode.Unauthorized);
            }
        }
    }

    private static Guid GetAffiliateKey(IHttpRouteData routeData) {

        var affiliateKey = routeData.Values["key"].ToString();
        return Guid.ParseExact(affiliateKey, "D");
    }
}

This will be registered at the controller level for the AffiliateShipmentsController.

Ownership Concerns

Consider this URI for an HTTP GET request: /api/affiliates/100/shipments/102. This URI should get us the correct data. However, what would happen for the this URI: /api/affiliates/100/shipments/103? This should get you a "404 Not Found" HTTP response because the affiliate whose Id is 100 doesn't own the shipment whose id is 103. Inside the PingYourPackage project, I ensured the ownership of the resource with the following authorization filter which will be applied to proper action methods.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class EnsureShipmentOwnershipAttribute 
    : Attribute, IAuthorizationFilter {

    private const string ShipmentDictionaryKey = 
        "__AffiliateShipmentsController_Shipment";
        
    public bool AllowMultiple { get { return false; } }

    public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(
        HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> continuation) {

        // We are here sure that the user is authanticated and request 
        // can be kept executing because the AuthorizeAttribute has 
        // been invoked before this filter's OnActionExecuting method.
        // Also, we are sure that the affiliate is associated with
        // the currently authanticated user as the previous action filter 
        // has checked against this.
        IHttpRouteData routeData = actionContext.Request.GetRouteData();
        Uri requestUri = actionContext.Request.RequestUri;

        Guid affiliateKey = GetAffiliateKey(routeData);
        Guid shipmentKey = GetShipmentKey(routeData, requestUri);

        // Check if the affiliate really owns the shipment
        // whose key came from the request. We don't need to check the 
        // existence of the affiliate as this check has been already 
        // performed by the AffiliateShipmentsDispatcher.
        IShipmentService shipmentService = 
            actionContext.Request.GetShipmentService();
        Shipment shipment = shipmentService.GetShipment(shipmentKey);

        // Check the shipment existance
        if (shipment == null) {

            return Task.FromResult(
                new HttpResponseMessage(HttpStatusCode.NotFound));
        }

        // Check the shipment ownership
        if (shipment.AffiliateKey != affiliateKey) {

            // You might want to return "404 NotFound" response here 
            // if you don't want to expose the existence of the shipment.
            return Task.FromResult(
                new HttpResponseMessage(HttpStatusCode.Unauthorized));
        }

        // Stick the shipment inside the Properties dictionary so 
        // that we won't need to have another trip to database.
        // The ShipmentParameterBinding will bind the Shipment param
        // if needed.
        actionContext.Request
            .Properties[ShipmentDictionaryKey] = shipment;

        // The request is legit, continue executing.
        return continuation();
    }

    private static Guid GetAffiliateKey(IHttpRouteData routeData) {

        var affiliateKey = routeData.Values["key"].ToString();
        return Guid.ParseExact(affiliateKey, "D");
    }

    private static Guid GetShipmentKey(
        IHttpRouteData routeData, Uri requestUri) {

        // We are sure at this point that the shipmentKey value has been
        // supplied (either through route or quesry string) because it 
        // wouldn't be possible for the request to arrive here if it wasn't.
        object shipmentKeyString;
        if (routeData.Values.TryGetValue("shipmentKey", out shipmentKeyString)) {

            return Guid.ParseExact(shipmentKeyString.ToString(), "D");
        }

        // It's now sure that query string has the shipmentKey value
        var quesryString = requestUri.ParseQueryString();
        return Guid.ParseExact(quesryString["shipmentKey"], "D");
    }
}

Now, this filter can be applied to proper action methods to allow the proper authorization. At the very end, the AffiliateShipmentsController class looks clean and readable:

[AffiliateShipmentsAuthorize]
public class AffiliateShipmentsController : ApiController {

    // We are OK inside this controller in terms of 
    // Affiliate existance and its relation with the current 
    // authed user has been checked by the handler 
    // and AffiliateShipmentsAuthorizeAttribute.

    // The action method which requests the shipment instance:
    // We can just get the shipment as the shipment 
    // existance and its ownership by the affiliate has been 
    // approved by the EnsureShipmentOwnershipAttribute.
    // The BindShipmentAttribute can bind the shipment from the
    // Properties dictionarty of the HttpRequestMessage instance
    // as it has been put there by the EnsureShipmentOwnershipAttribute.

    private const string RouteName = "AffiliateShipmentsHttpRoute";
    private readonly IShipmentService _shipmentService;

    public AffiliateShipmentsController(IShipmentService shipmentService) {

        _shipmentService = shipmentService;
    }

    public PaginatedDto<ShipmentDto> GetShipments(
        Guid key, 
        PaginatedRequestCommand cmd) {

        var shipments = _shipmentService
            .GetShipments(cmd.Page, cmd.Take, affiliateKey: key);

        return shipments.ToPaginatedDto(
            shipments.Select(sh => sh.ToShipmentDto()));
    }

    [EnsureShipmentOwnership]
    public ShipmentDto GetShipment(
        Guid key, 
        Guid shipmentKey, 
        [BindShipment]Shipment shipment) {

        return shipment.ToShipmentDto();
    }

    [EmptyParameterFilter("requestModel")]
    public HttpResponseMessage PostShipment(
        Guid key, 
        ShipmentByAffiliateRequestModel requestModel) {

        var createdShipmentResult =
            _shipmentService.AddShipment(requestModel.ToShipment(key));

        if (!createdShipmentResult.IsSuccess) {

            return new HttpResponseMessage(HttpStatusCode.Conflict);
        }

        var response = Request.CreateResponse(HttpStatusCode.Created,
            createdShipmentResult.Entity.ToShipmentDto());

        response.Headers.Location = new Uri(
            Url.Link(RouteName, new { 
                key = createdShipmentResult.Entity.AffiliateKey,
                shipmentKey = createdShipmentResult.Entity.Key
            })
        );

        return response;
    }

    [EnsureShipmentOwnership]
    [EmptyParameterFilter("requestModel")]
    public ShipmentDto PutShipment(
        Guid key, 
        Guid shipmentKey,
        ShipmentByAffiliateUpdateRequestModel requestModel,
        [BindShipment]Shipment shipment) {

        var updatedShipment = _shipmentService.UpdateShipment(
            requestModel.ToShipment(shipment));

        return updatedShipment.ToShipmentDto();
    }

    [EnsureShipmentOwnership]
    public HttpResponseMessage DeleteShipment(
        Guid key, 
        Guid shipmentKey,
        [BindShipment]Shipment shipment) {

        var operationResult = _shipmentService.RemoveShipment(shipment);

        if (!operationResult.IsSuccess) {

            return new HttpResponseMessage(HttpStatusCode.Conflict);
        }

        return new HttpResponseMessage(HttpStatusCode.NoContent);
    }
}

As said, I'd love to know how you handle these types of situations in your applications.

Installing hub Extension for Git (by defunkt) on Windows to Work With GitHub More Efficiently

This post walks you through on how you can install hub extension for Git (by defunkt) on Windows to work with GitHub more efficiently.
2013-01-19 20:10
Tugberk Ugurlu


We are all in love with Git but without GitHub, we love Git less. On GitHub, we can maintain our projects very efficiently. Pull Request” and "Issues" features of GitHub are the key factors for that IMO. You can even send yourself a pull request from one branch to another and discuss that particular change with your team. As your discussion flows, your code can flow accordingly, too. This is just one of the many coolest features of GitHub.

There is a cool Git extension for GitHub which is maintained by one of the founders of GitHub: Chris Wanstrath. This cool extension named hub lets us work with GitHub more efficiently from the command line and perform GitHub specific operations easily like sending pull requests, forking repositories, etc. It’s fairly easy to install it on other platforms as far as I can see but it’s not that straight forward for Windows.

You should first go and install msysgit on Windows and I am assuming most of us using this on Windows for Git. Secondly, we should install Ruby on windows. You can install Ruby on windows through RubyInstaller easily.

After installing ruby on our machine successfully, we should add the bin path of Ruby to our system PATH variable. In order to do this, press Windows Key + PAUSE BREAK to open up the Windows System window and click "Advanced system settings" link on the left hand side of the window.

SNAGHTML25551807

A new window should appear. From there, click "Environment Variables..." button to open up the Environment Variables window.

image

From there, you should see "System variables" section. Find the Path variable and concatenate the proper ruby bin path to that semicolon-separated list.

imageSNAGHTML255c49a4

Last step is actually installing the hub. You should grab the standalone file and then rename it to "hub". Then, put it under the Git\bin folder. The full path of my Git\bin folder on my 64x machine is "C:\Program Files (x86)\Git\bin".

Now you should be able to run hub command from Git Bash:

image

Special GitHub commands you get through hub extension is nicely documented on the "Readme" file of the project. I think the coolest feature of hub is the pull-request feature. On GitHub, You can send pull requests to another repository through GitHub web site or GitHub API and hub extension uses GitHub API under the covers to send pull requests. You can even attach your pull request to an existing issue. For example, the following command sends a pull request to master branch of the tugberkugurlu’s repository from the branch that I am currently on and attaches this to an existing issue #1.

hub pull-request -i 1 -b tugberkugurlu:master

Have fun Winking smile

ASP.NET Web API Tracing and IDependencyScope Dispose Issue

If you enabled tracing on your ASP.NET Web API application, you may see a dispose issue for IDependencyScope. Here is why and how you can workaround it.
2013-01-12 16:26
Tugberk Ugurlu


ASP.NET Web API has a very cool built-in tracing mechanism. The coolest part about this feature is that none of the tracing code is being run if you don’t enable it. The mechanism makes use of well-known Facade Pattern and if you enable tracing by providing your custom ITraceWriter implementation and don’t replace the default ITraceManager implementation, several ASP.NET Web API components (Message Handlers, Controllers, Filters, Formatters, etc.) will be wrapped up inside their tracer implementations (these are internal classes inside System.Web.Http assembly). You can learn more about tracing from Tracing in ASP.NET Web API article.

ASP.NET Web API also has this concept of carrying disposable objects inside the request properties bag and two objects are added to this disposable list by the framework as shown below (in the same order):

The DisposeRequestResources extension method for the HttpRequestMessage object is invoked by the hosting layer at the end of each request to dispose the registered disposable objects. The invoker is the internal ConvertResponse method of HttpControllerHandler in case of ASP.NET host. The implementation of the DisposeRequestResources extension method is exactly as shown below:

public static void DisposeRequestResources(this HttpRequestMessage request) {

    if (request == null) {
        throw Error.ArgumentNull("request");
    }

    List<IDisposable> resourcesToDispose;
    if (request.Properties.TryGetValue(HttpPropertyKeys.DisposableRequestResourcesKey, out resourcesToDispose)) {
        foreach (IDisposable resource in resourcesToDispose) {
            try {
                resource.Dispose();
            }
            catch {
                // ignore exceptions
            }
        }
        resourcesToDispose.Clear();
    }
}

It iterates through the list and disposes the registered objects one by one. So far so good. However, there is one slightly problem here depending on your ITraceWriter implementation. I’m not sure if it’s fair to call this a bug, but to me, it really is a bug. Let me explain what it is.

As we know, the IDependencyScope implementation and the selected IHttpController implementation for the request are added to the disposables list in order to be disposed at the end of the request. As we also know, if we enable tracing in ASP.NET Web API, several ASP.NET Web API components wrapped inside their tracer implementations. In case of controllers, this is HttpControllerTracer. Since the IHttpController is also disposable, the HttpControllerTracer overrides the Dispose method to write a begin/end trace record for the dispose action. However, the disposable objects are disposed in order and when the controller’s dispose method is called, the dependency scope is already too far gone and if your custom ITraceWriter implementation tries to use the dependency scope, which is bound to that request, you will get an exception there. This doesn’t effect your application that much as this exception is swollen by the underlying infrastructure but this is not good. I wrote a little application to demonstrate this (actually, I went a little far and used a few more things for this *little* application Smile) and show how to workaround it for now. The code for this project is available on GitHub.

I created a custom tracer and registered through the global HttpConfiguration instance. This tracer tries to reach the ILoggerService implementation through the dependency scope. The code for my ITraceWriter implementation is as shown below:

public class WebApiTracer : ITraceWriter {

    public void Trace(
        HttpRequestMessage request, 
        string category, 
        TraceLevel level, 
        Action<TraceRecord> traceAction) {

        if (level != TraceLevel.Off) {

            TraceRecord record = new TraceRecord(request, category, level);
            traceAction(record);
            Log(record);
        }
    }

    private void Log(TraceRecord traceRecord) {

        IDependencyScope dependencyScope = 
            traceRecord.Request.GetDependencyScope();
            
        ILoggerService loggerService = 
            dependencyScope.GetService(typeof(ILoggerService)) as ILoggerService;
            
        // Log the trace data here using loggerService
        
        // Lines omitted for brevity
    }
}

When we run this application in debug mode and send a request against a valid resource which will eventually go inside the controller pipeline (for this application /api/cars), we will see an exception as below:

1-12-2013 4-41-30 PM

If we are curios enough and decide to dig a little deeper, we will actually see what is causing this exception.

1-12-2013 4-42-58 PM

{"Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed."}

   at Autofac.Core.Lifetime.LifetimeScope.CheckNotDisposed()
   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
   at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)
   at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType)
   at DependencyScopeTracingDisposeBug.Tracing.WebApiTracer.Log(TraceRecord traceRecord) in e:\Apps\DependencyScopeTracingDisposeBug\Tracing\WebApiTracer.cs:line 25
   at DependencyScopeTracingDisposeBug.Tracing.WebApiTracer.Trace(HttpRequestMessage request, String category, TraceLevel level, Action`1 traceAction) in e:\Apps\DependencyScopeTracingDisposeBug\Tracing\WebApiTracer.cs:line 18
   at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)
   at System.Web.Http.Tracing.Tracers.HttpControllerTracer.System.IDisposable.Dispose()
   at System.Net.Http.HttpRequestMessageExtensions.DisposeRequestResources(HttpRequestMessage request)

It wasn’t hard to diagnose the problem and the question was how to workaround it for now as the issue is caused by a code which is deep inside the bowel of the hosting layer. There are several workarounds for this problem which I can come up with quickly such as replacing the HttpControllerTracer but the one I applied was very dirty: adding a message handler as the first message handler (so that it runs last (just in case)) and reordering the disposables on the way out. Here is the message handler which performs this operation:

public class DisposableRequestResourcesReorderHandler : DelegatingHandler {

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken) {

        return base.SendAsync(request, cancellationToken).Finally(() => {

            List<IDisposable> disposableResources = 
                request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey] as List<IDisposable>;
                
            if (disposableResources != null && disposableResources.Count > 1) {

                // 1-) Get the first one (which I know is AutofacWebApiDependencyScope).
                // 2-) Remove it from the list.
                // 3-) Push it at the end of the list.

                IDisposable dependencyScope = disposableResources[0];
                disposableResources.RemoveAt(0);
                disposableResources.Add(dependencyScope);
            }
        }, runSynchronously: true);
    }
}

Notice that I used an extension method for Task object called Finally. This is a method which you can get by installing the TaskHelpers NuGet package. This allows you to run the continuation no matter what the status of the completed Task. Finally method will also propagate the proper Task back to the caller, which is kind of nice and clean in our case here as we want to run this code no matter what the status of the Task is.

When you run the application after registering this message handler, you will see the controller’s dispose trace record being logged successfully.

1-12-2013 7-35-21 PM

If you believe this is a bug and should be fixed, please vote for this issue: http://aspnetwebstack.codeplex.com/workitem/768.

Clean, Better, and Sexier Generic Repository Implementation for Entity Framework

With the new release of the GenericRepository.EntityFramework package, we now have clean, better and sexier generic repository implementation for Entity Framework. Enjoy!
2013-01-10 13:00
Tugberk Ugurlu


I have written a few blog posts about my experience on applying the Generic Repository pattern to Entity Framework and I even made a NuGet package for my naïve implementation. Even if that looked OK at the time for me, I had troubles about my implementation for couple of reasons:

  • The implementations inside the NuGet package didn’t allow the developer to share the DbContext instance between repositories (per-request for example).
  • When the generic repository methods weren’t enough, I was creating new repository interfaces and classes based on the generic ones. This was the biggest failure for me and didn’t scale very well as you can imagine.
  • There were no pagination support.
  • As each repository take a direct dependency on DbContext and it is impossible to entirely fake the DbContext, generic repositories needed to be mocked so that we could test with them. However, it would be just very useful to pass a fake DbContext instance into the repository implementation itself and use it as fake.

With the new release of the GenericRepository.EntityFramework package, the all of the above problems have their solutions. The source code for this release is available under the master branch of the repository and you can also see the ongoing work for the final release under the v0.3.0 branch. The NuGet package is available as pre-release for now. So, you need to use the –pre switch to install it.

PM> Install-Package GenericRepository.EntityFramework -Pre

The old GenericRepository.EF package is still around and I will update it, too but it’s now unlisted and only thing it does is to install the GenericRepository.EntityFramework package.

I also included a sample application which shows the usage briefly. I will complete the sample and extend it further for a better view. Definitely check this out!

Let’s dive right in and see what is new and cool.

IEntity and IEntity<TId> Interfaces

I introduced two new interfaces: IEntity and IEntity<TId> and each of your entity classes needs to implement one of these. As you can see from the implementation, IEntity just implements the IEntity<int> and you can use IEntity if you are using integer based Ids. The reason why I added these is make the GetSingle method work.

Use EntitiesContext Instead of DbContext

Instead of deriving your context class from DbContext, you now need to take the EntitiesContext as the base class for your context. If you have an existing context class based on DbContext, changing it to use EntitiesContext should not break it. The EntitiesContext class has all the same constructors as DbContext. So, you can also use those. Here is the sample:

public class AccommodationEntities : EntitiesContext {

    // NOTE: You have the same constructors as the DbContext here. E.g:
    // public AccommodationEntities() : base("nameOrConnectionString") { }

    public IDbSet<Country> Countries { get; set; }
    public IDbSet<Resort> Resorts { get; set; }
    public IDbSet<Hotel> Hotels { get; set; }
}

Then, through your IoC container, you can register your context as a new instance for IEntitiesContext per a particular scope. The below example uses Autofac to do that for an ASP.NET Web API application:

private static void RegisterDependencies(HttpConfiguration config) {

    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    // Register IEntitiesContext
    builder.Register(_ => new AccommodationEntities())
           .As<IEntitiesContext>().InstancePerApiRequest();

    // TODO: Register repositories here

    config.DependencyResolver = 
        new AutofacWebApiDependencyResolver(builder.Build());
}

IEntityRepository<TEntity> and EntityRepository<TEntity>

Here is the real meat of the package: IEntityRepository and EntityRepository. Same as the IEntity and IEntity<TId>, we have two different IEntityRepository generic interfaces: IEntityRepository<TEntity> and IEntityRepository<TEntity, TId>. They have their implementations under the same generic signature: EntityRepository<TEntity> and EntityRepository<TEntity, TId>. The big improvement now is that EntityRepository generic repository implementation accepts an IEntitiesContext implementation through its constructor. This, for example, enables you to use the same DbContext (IEntitiesContext implementation in our case, which is EntitiesContext by default) instance per-request for your ASP.NET MVC, ASP.NET Web API application and share that across your repositories. Note: don’t ever use singleton DbContext instance throughout your AppDomain. DbContext is not thread safe.

As we have registered our EntitiesContext instance per request above, we can now register the repositories as well. As our repositories accepts an IEntitiesContext implementation through their constructor, our IoC container will use our previous registration for that automatically. Autofac has this ability as nearly all IoC containers do.

private static void RegisterDependencies(HttpConfiguration config) {

    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    // Register IEntitiesContext
    builder.Register(_ => new AccommodationEntities())
           .As<IEntitiesContext>().InstancePerApiRequest();

    // TODO: Register repositories here
    builder.RegisterType<EntityRepository<Country>>()
           .As<IEntityRepository<Country>>().InstancePerApiRequest();
    builder.RegisterType<EntityRepository<Resort>>()
           .As<IEntityRepository<Resort>>().InstancePerApiRequest();
    builder.RegisterType<EntityRepository<Hotel>>()
           .As<IEntityRepository<Hotel>>().InstancePerApiRequest();

    config.DependencyResolver = 
        new AutofacWebApiDependencyResolver(builder.Build());
}

Out of the Box Pagination Support

Best feature with this release is out of the box pagination support with generic repository instances. It doesn’t perform the pagination in-memory; it queries the database accordingly and gets only the parts which are needed which is the whole point Smile Here is an ASP.NET Web API controller which uses the pagination support comes with the EntityRepository:

public class CountriesController : ApiController {

    private readonly IEntityRepository<Country> _countryRepository;
    private readonly IMappingEngine _mapper;
    public CountriesController(
        IEntityRepository<Country> countryRepository, 
        IMappingEngine mapper) {

        _countryRepository = countryRepository;
        _mapper = mapper;
    }

    // GET api/countries?pageindex=1&pagesize=5
    public PaginatedDto<CountryDto> GetCountries(int pageIndex, int pageSize) {

        PaginatedList<Country> countries = 
             _countryRepository.Paginate(pageIndex, pageSize);

        PaginatedDto<CountryDto> countryPaginatedDto = 
           _mapper.Map<PaginatedList<Country>, PaginatedDto<CountryDto>>(countries);

        return countryPaginatedDto;
    }
}

public interface IPaginatedDto<out TDto> where TDto : IDto {

    int PageIndex { get; set; }
    int PageSize { get; set; }
    int TotalCount { get; set; }
    int TotalPageCount { get; set; }

    bool HasNextPage { get; set; }
    bool HasPreviousPage { get; set; }

    IEnumerable<TDto> Items { get; }
}

public class PaginatedDto<TDto> : IPaginatedDto<TDto> where TDto : IDto {

    public int PageIndex { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }
    public int TotalPageCount { get; set; }

    public bool HasNextPage { get; set; }
    public bool HasPreviousPage { get; set; }

    public IEnumerable<TDto> Items { get; set; }
}

Paginate method will return us the PaginatedList<TEntity> object back and we can project that into our own Dto object as you can see above. I used AutoMapper for that. If I send a request to this API endpoint and ask for response in JSON format, I get back the below result:

{
    "PageIndex":1,
    "PageSize":2,
    "TotalCount":6,
    "TotalPageCount":3,
    "HasNextPage":true,
    "HasPreviousPage":false,
    "Items":[
      {
        "Id":1,
        "Name":"Turkey",
        "ISOCode":"TR",
        "CreatedOn":"2013-01-08T21:12:26.5854461+02:00"
      },
      {
        "Id":2,
        "Name":"United Kingdom",
        "ISOCode":"UK",
        "CreatedOn":"2013-01-08T21:12:26.5864465+02:00"
      }
    ]
}

Isn’t this perfect Smile There are other pagination method inside the EntityRepository implementation which supports including child or parent entities and sorting. You also have the ToPaginatedList extension method and you can build your query and call ToPaginatedList on that query to get PaginatedList<TEntity> object back.

Extending the IEntityRepository<TEntity>

In my previous blog posts, I kind of sucked at extending the generic repository. So, I wanted to show here the better approach that I have been taking for a while now. This is not a feature of my generic repository, this is the feature of .NET itself: extension methods! If you need extra methods for your specific repository, you can always extend the IEntityRepository<TEntity, TId> which gives you a better way to extend your repositories. Here is an example:

public static class HotelRepositoryExtensions {

    public static IQueryable<Hotel> GetAllByResortId(
        this IEntityRepository<Hotel, int> hotelRepository, int resortId) {

        return hotelRepository.FindBy(x => x.ResortId == resortId);
    }
}

What is Next?

My first intention is finish writing all the tests for the whole project, fix bugs and inconsistencies for the v0.3.0 release. After that release, I will work on EF6 version for my generic repository implementation which will have sweet asynchronous support. I also plan to release a generic repository implementation for MongoDB.

Stay tuned, install the package, play with it and give feedback Winking smile