pondělí 3. března 2014

Context lifetime


In previous blog post we described an architecture when an unit of work is used at the service level to access the database using entity framework (EF). EF has a DbContext that has a connection to a database, how is it witch the lifecycle of this connection in our case? We use DI, our DI injects an instance of uow to AuditService during the creation of the service. The service has no control over the instantiation of uow, the uow dies when the service dies. This happens after the service is picked up by garbage collector. This is not really nice. The recommended way is to have the connection open only for needed minimum. This is usually done in using blocks. Using works with IDisposable interface, our unit of work should implement the IDisposable interface. Ok, this is easy, but should the AuditService control the lifetime of Uow? (= using block on uow?). If yes, we cannot use DI for putting together the AuditService, instead a Service Locator pattern should be used, when the AuditService asks the DI container for an instance of uow explicitly, puts it to using blocks, this way the uow is disposed after each call. Great for connection savings, but we lose the positive effects of orm. I mean that having the uow live during the whole lifetime of the service gives us caching (EF is not going back to database for an entity which it had already read to its context), tracks back the IDs of newly inserted records after calling SaveChanges on context, theoretically we can combine more calls on the service and call the SaveChanges only once = one trip to Db – our example is not prepared for it, we don’t have SaveChanges exposed on the service layer. Closing the uow in every call of the service prevents this.

What are the alternatives? If we have a web application, we can explicitly dispose in some page lifecycle event every instance created on the page during the request. This is extra work (we need to implement some mechanism that tracks which instance to dispose after the request finishes – a registration class that tracks disposable instances and is somehow integrated to DI mechanism?). In case of web applications after the request goes out of scope, the GC collects every instance created during this request (GC is not calling dispose, so if we let it to GC probably we don’t need to implement IDisposable).  Problem is that this takes some time. If this is a highly loaded site, this could be problem. EF has 100 concurrent connections, the 101 will wait for a connection to be disposed. We can also implement IDisposable on AuditService (it will call Dispose on its uow) and let the client use the AuditService in using blocks – I like this better compared to disposing uow inside every call of the AuditService, but imagine a http request inside a web application, imagine that for some reason multiple instances of AuditService are used in a request, each of  them have a private instance of uow with dbcontext. Logging in this case (even inside of one http request which is usually perceived as a business transaction boundary) is done independently at each instance of AuditService (they have separate dbcontext, what one AuditService saves, the other one is not seeing etc.). Wouldn’t it be nicer if they can share one instance of uow inside a http request which is their business transaction boundary? If yes, we cannot use the dispose approach at the level of AuditService. (it will dispose the shared instance of uow and dbcontext). How to share an instance of uow in one http request is described here.(http://coder21.blogspot.cz/2014/03/sharing-instance-of-uow-inside-one-http.html).

Wrap up:
  •   If you don’t plan in future to encapsulate multiple calls on service level into a business transaction (= each call to a method of service is a business transaction) and you don’t need a context sharing between multiple instances of services than use the service locator pattern to get an instance of uow inside a service and dispose the uow in each method of the service. This is the simplest solution, equivalent to the current implementation with ADO.NET DAL as described at the first blog post of this series (http://coder21.blogspot.cz/2014/03/entity-framework-repositories-unit-of.html).
  •   If encapsulating multiple calls on service to one business transaction is required but sharing of context is not important, implement IDisposable on the Service layer to (AuditService) and let the client explicitly dispose the service after it is not required. In this case you don’t need to implement service locator inside the service, classical DI is what you want (DI container will inject automatically the uow to service).
  • If you want to share context (mainly web applications http request) look for your DI options that can support objects scoping to a web request (most of them does have such a capability), don’t implement (or use) Dispose at the service level, don’t use service locator at service level (let the DI container inject the uow). You need to find a way how to dispose the instances of uow after the request finishes (web apps), you can let it to GC or implement something that tracks the disposable instances created during the request. (this is custom implementation dependent on the particular DI container, the way how you obtain the instances from the DI, the web framework you use etc.  – you would need this definetly if you have a highly loaded site).
I prefer the third approach, the DI container puts the instances together, not using service locator for this, using a DI configuration option to share the context in one http request and let the GC do the dispose the context (the last thing is not my favorite, but currently it fits my requirements, later I can write an implementation of explicitly releasing the disposable objects in a request).


Žádné komentáře:

Okomentovat