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

时间:2014-07-18 22:44:23

标签: asp.net entity-framework asp.net-web-api routing

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

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

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

1 个答案:

答案 0 :(得分:0)

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

  1. 在负责根据url参数创建上下文的工厂后面创建上下文
  2. 创建一个删除处理程序以检查请求并使用上下文工厂基于当前URL实例化新上下文
  3. 使用生存范围限定为当前api请求的缓存对象缓存上下文
  4. 使用上下文缓存对象检索api请求的生命周期范围内存在的所有类型的url特定上下文
  5. 以下是使用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());
    }