根据请求url动态设置实体上下文



我的web api 2应该为客户端提供两个url: test.mydomain.com和production.mydomain.com当客户端访问测试时,我想为生产url实例化测试数据库上下文和生产数据库。

目前我可以手动实例化两者:在控制器内的每个动作上,我可以检查url并确定是否这个,加载这个,如果那个加载那个。但是,我想自动设置db,而不检查每个动作的请求url。我试着在控制器构造函数中读取请求上下文,但在那个阶段它不存在。

操作过滤器吗?OnActionExecuting吗?但是我如何在过滤器中实例化它并在控制器动作中使用它呢?还有其他建议吗?

正如Erik所指出的那样,使用依赖注入可以相当容易地解决这个问题。

  1. 将上下文的创建封装在工厂后面,工厂负责基于url参数创建上下文
  2. 创建一个删除处理程序来检查请求,并使用上下文工厂基于当前url实例化一个新的上下文
  3. 将上下文缓存到缓存对象中,其生存期范围为当前api请求
  4. 使用上下文缓存对象来检索存在于api请求生命周期范围内的所有类型的url特定上下文

下面是一个使用AutoFac的例子:

public interface IContextCache
{
    DbContext CurrentContext { get; set; }
}
// This will be wired as instance per api request
// and hence return the same context across the entire
// request from handler to controller
public class ContextCache : IContextCache
{
    public DbContext CurrentContext { get; set; }
}
public interface IContextFactory
{
    DbContext Create(Uri requestUri);
}
public class ContextFactory : IContextFactory
{
    public DbContext Create(Uri requestUri)
    {
        return CreateContextBasedOnUri(requestUri);
    }
}
// This is fired before the controller and creates and caches
// as per url context
public class ContextHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 
        CancellationToken cancellationToken)
    {
        var dependencyScope = request.GetDependencyScope();
        var contextFactory = (IContextFactory)dependencyScope.GetService(typeof(IContextFactory));       
        var contextCache = (IContextFache)dependencyScope.GetService(typeof(IContextCache));
        var context = contextFactory.Create(request.RequestUri);
        contextCache.CurrentContext = context;
        return base.SendAsync(request, cancellationToken);
    }
}
// Uses the per api request scoped cache to retrieve the 
// correct context
public class MyController : ApiController
{
    public MyController(IContextCache contextCache)
    {
        var context = contextCache.CurrentContext;
    }
}
// AutoFac wiring
// Perform boiler plate AutoFac registration for WebApi
// (See AutoFac documentation)
// Custom registrations
builder.RegisterType<ContextCache>()
    .As<IContextCache>()
    .InstancePerApiRequest();
builder.RegisterType<ContextFactoy>()
    .As<IContextFactory>()
    .InstancePerDependency();
// Handler registration
public static void Register(HttpConfiguration config)
{
    config.MessageHandlers.Add(new ContextHandler());
}

最新更新