Masanori Nakazato
Masanori Nakazato

Reputation: 33

DbContext Injection into WCF Service

I'd like to ask you if my idea will work well.

I've recently started using Entity Framework and WCF. In my current project, I want every service atomic, that is to say one service is in one transaction. But I don't want to write the same transaction related code many times for all service operations. Then I hit the idea that the transaction and its error handling are done at one place IOperationInvoker like in the code snippet shown below.

The advantage of this trick is I can instantiate DbContext or create transaction in using block so that they are surely disposed whatever happens in the service. and I only have to handle the db related exception once.

It seems to work. but I'm worried if this is a legitimate way to use IOperationInvoker and EF.

Are there any drawbacks?

// service base class
public abstract MyBaseService
{
    DbContext database {get; set;}
}

[ServiceContract]
public interface IMyService {...}

// concrete service class
public class MyService : MyBaseService, IMyService {...}

public class MyOperationInvoker : IOperationInvoker
{
    IOperationInvoker originalOperationInvoker; // to be set at construction

    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        using (var dbContext = new MyDbContext())
        {
            // inject DbContext into my service to be used in it.
            (MyServiceBase)instance.database = dbContext;

            // invoke a service within db transaction.
            using (var transaction = dbContext.Database.BeginTransaction())
            {
                try
                {
                    objct ret = originalOperationInvoker.invoke(instance, inputs, outputs);
                    transaction.Commit();
                    return ret;
                }
                catch (Exception e)
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }
    }
    ...
}

Upvotes: 2

Views: 1792

Answers (2)

Wiktor Zychla
Wiktor Zychla

Reputation: 48230

Another idea is to have a custom instance provider. The instance provider lets you control the lifetime of wcf service instances by providing an explicit points where instance is created and released.

By combining this with an ioc container you can have your context injected automatically into the service and then disposed when request completes.

I've blogged on this recently, consult my blog entry for technical details.

http://www.wiktorzychla.com/2014/02/lifetime-management-of-wcf-services.html

Upvotes: 2

usr
usr

Reputation: 171168

On using an operation invoker: Yes, you can do this. This is the main place to add "wrapping logic" around incoming calls in WCF. Note, that for async methods you'll need to implement a different set of interface methods.

On automatic transaction management: I found implicit transactions to be insufficient because you need to control the isolation level and timeout settings. Also, sometimes you need multiple transactions. Maybe not in the first version but eventually you'll outgrow this scheme.

What I recently did successfully, was to create a class that wraps a DbContext and a transaction in one unit. Most of my WCF methods look like this:

void SomeMethod() {
 using (var db = new MyDatabaseContext(isolationLevel, timeout, connectionString, ...)) {
  //custom body that uses the wrapped DbContext
  db.CompleteTransaction();
 }
}

There's a little code duplication here, but it is not too bad and I still have total control over how I use the database. I could use multiple transactions per method, nest them or use a runtime calculated timeout value. There's no magic going on (like an implicitly called operation invoker). It is exception safe as well.

Upvotes: 2

Related Questions