Temporarily set DbContext CommandTimeout

I know that I can set the DbContext CommandTimeout for all requests with something like this:

public class YourContext : DbContext { public YourContext() : base("YourConnectionString") { // Get the ObjectContext related to this DbContext var objectContext = (this as IObjectContextAdapter).ObjectContext; // Sets the command timeout for all the commands // to 2 min instead of the default 30 sec objectContext.CommandTimeout = 120; } } 

However, I want to keep the default value of 30 seconds, with the exception of one single method, which takes a little longer.

How do I change this for this single request?

I tried using:

 public void doSomething(){ // The using had another reason, but in this case it also // automatically disposes of the DbContext using(IMyDbContext = delegateDbContext()){ ((IObjectContextAdapter)usingDb).ObjectContext.CommandTimeout = 120; ... // myQuery } } 

Everything worked fine until I ran my UnitTest using Mock-DbContext (and yes, I really set my delegate to this Mock-DbContext). This gives me an InvalidCastException :

 System.InvalidCastException: Unable to cast object of type 'Castle.Proxies.FakeMyDbContextProxy' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'. 
+7
c # unit-testing asp.net-mvc entity-framework mocking
source share
2 answers

This is because you rely on an implementation detail (the fact that your IMyDbContext also implements IObjectContextAdapter ), which you should not be aware of. In unit test, an instance of IMyDbContext is actually a proxy server generated by a fake framework, and does not implement IObjectContextAdapter .

Since CommandTimeout does not make sense for this fake DbContext , I suggest you try to make and install CommandTimeout only if the pursuit is CommandTimeout :

 var objectContextAdapter = usingDb as IObjectContextAdapter; if (objectContextAdapter != null) objectContextAdapter.ObjectContext.CommandTimeout = 120; 

Thus, the CommandTimeout will be installed in the real runtime, but not in the unit test (which does not matter, since the layout does not actually query the database)


EDIT: in fact, the best and cleanest option would be to modify IMyDbContext to show a way to set CommandTimeout :

 interface IMyDbContext { ... int CommandTimeout { get; set; } } class MyDbContext : IMyDbContext { ... public int CommandTimeout { get { return ((IObjectContextAdapter)this).ObjectContext.CommandTimeout; } set { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = value; } } } 

And now you can just do:

 usingDb.CommandTimeout = 120; 

without worrying about the real type of context. The mocking structure will simply create a dummy implementation for this property.

+5
source share

And touch on the initial question of setting a timeout for one operator. A straightforward approach is sometimes the best. Assuming you expanded CommandTimeout as suggested above (great idea), then in your function:

 var originalTimeout = _dbContext.CommandTimeout; _dbContext.CommandTimeout = 120; // do something relevant _dbContext.CommandTimeout = originalTimeout; 
+1
source share

All Articles