问题描述
我正在构建.Net Web API,该API使用带有实体框架的Service + Repository模式。每个控制器的CRUD操作都会中继通过调用服务检索到的数据。
I'm building a .Net Web API which uses a Service+Repository pattern w/ Entity Framework. Each controller's CRUD actions relay data retrieved by calls to a Service.
我有一个SomeContext扩展了DbContext:
I have a SomeContext that extends DbContext:
public class SomeContext : DbContext
{
public SomeContext(string connString) : base(connString) { }
// DbSets
...
}
该服务使用构造函数初始化,该构造函数接受ISomeContext:
The Service is initialized w/ a constructor that accepts an ISomeContext:
public class Service : IService
{
public Service(ISomeContext ctx) : base(ctx)
{
_alpha = new AlphaRepository(ctx);
...
}
GetAllAlpha()
{
return _alpha.Get();
}
...
}
我要使用(统一容器)依赖注入,将SomeContext的实例注入到Service构造函数中。给定SomeContext的生命周期应该是API请求的持续时间。困难之处在于SomeContext的连接字符串是动态的,只有在作为API请求的一部分提供运行时参数 client后才能知道。
I want to use (Unity Container) Dependency Injection to inject an instance of SomeContext into the Service constructor. The life cycle of a given SomeContext should be the duration of the API request. The difficulty is that the connection string for SomeContext is dynamic and cannot be known until a runtime parameter 'client' is provided as part of the API request.
此外,还有不确定数量的客户端,因此由于我的每个租户数据库环境,连接字符串也是如此。因此,我不能仅仅基于'client'参数注册 n 已知的SomeContexts和Resolve()。
Furthermore, there are an indeterminate number of clients and therefore connection strings due to my database-per-tenant environment. As such, I cannot just register n known SomeContexts and Resolve() based on the 'client' parameter.
而是内部开发的NuGet带有暴露的ContextFactory的程序包使我可以为客户端检索适当的SomeContext:
Instead, an internally developed NuGet package w/ exposed ContextFactory lets me retrieve the appropriate SomeContext for a client:
ContextFactory.GetClientContext(client);
如何以及在哪里配置Unity Container来管理此动态SomeContext?
How and where do I configure Unity Container to manage this dynamic SomeContext?
附加说明:
- Unity已经依赖于将IService服务注入到我的控制器的每个
中动作。因此,在我创建的任何Web API ActionFilter之前,必须先执行Service构造函数
。这意味着我在注入之前无法识别客户 ...我想这意味着我需要使用工厂和/或委托...? - 我'我已经阅读了有关将抽象工厂与DbContext的委托,
公共委托IDbContext CreateDbContext(string client);
以及NuGet
包的GetClientContext的适配器结合使用的信息请求,但我无法将
全部整合到一个可行的解决方案中。
- Unity is already dependency injecting the IService Service into eachof my Controller actions. Because of this, the Service constructor isexecuted prior to any of the Web API ActionFilters I have created. This means I can't identify the 'client' prior to the injection...I presume this means I would need to use a factory and/or delegate...?
- I've read about using an abstract factory in conjunction with a delegate for the DbContext,
public delegate IDbContext CreateDbContext(string client);
, and adapter for the NuGetpackage's GetClientContext request, but I haven't been able topiece it all together into a working solution.
感谢您的帮助!
推荐答案
将运行时参数合并到Unity Dependency Injected对象中的技巧是:
The trick to incorporate runtime parameters into a Unity Dependency Injected object is InjectionFactory:
container.RegisterType<ISomeContext>(
new PerRequestLifetimeManager(),
new InjectionFactory(_ => ContextFactoryAdapter.GetSomeContext(new HttpContextWrapper(HttpContext.Current)))
);
在这种情况下,我指定了静态ContextFactoryAdapter.GetSomeContext()根据提供的HttpContextWrapper参数中可用数据返回动态SomeContext的方法:
In this case, I designate the static ContextFactoryAdapter.GetSomeContext() method to return a dynamic SomeContext according to data available in the supplied HttpContextWrapper argument:
public static SomeContext GetSomeContext(HttpContextWrapper requestWrapper)
{
var client = requestWrapper.Request.QueryString["client"];
return ContextFactory.GetClientContext(client);
}
因此,Unity会将ISomeContext类型解析为GetClientContext()返回的SomeContext。
So, Unity will resolve ISomeContext type to the SomeContext returned by GetClientContext().
RegisterType()的 PerRequestLifetimeManager()
参数指示Unity在a的生存期内使用返回的SomeContext实例。单个HTTP请求。为了使Unity自动处理该实例,您还必须:
The PerRequestLifetimeManager()
argument to RegisterType() instructs Unity to use the returned SomeContext instance for the lifetime of a single HTTP request. For Unity to dispose of the instance automatically, you must also also register the UnityPerRequestHttpModule in UnityMvcActivator.cs:
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
有了这些配置,Unity就能解析适当的SomeContext并将该实例提供给Service通过构造函数注入。
With these configurations in place, Unity is able to resolve an appropriate SomeContext and supply this instance to the Service via constructor injection.
这篇关于Unity容器-将动态DbContext依赖注入服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!