如何在基于 HTTP header 的 OWIN 环境中配置动态连接字符串?
How to configure a dynamic connection string on a OWIN enviroment based on HTTP header?
我是 OWIN 和 IoC 的新手,现在我需要实现一个动态上下文,该上下文由基于 HTTP header 的 Simple Injector 解析,该 HTTP header 标识谁在调用我的 API .这种方法可能不是最好的方法,所以我也愿意接受另一种可能的解决方案。
这是我的 OWIN 启动 class:
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
var container = new Container();
string connectionString = string.Empty;
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.Use(async (context, next) =>
{
var customHeader = context.Request.Headers.Get("customHeader");
connectionString = "conStr";//get con based on the header, from a remote DB here
await next.Invoke();
});
app.UseOwinContextInjector(container);
container.Register<DbContext>(() => new MyDynamicContext(connectionString),
Lifestyle.Scoped);
//container.Register ...;
container.Verify();
httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
}
我遇到的问题是DI框架创建实例时连接字符串总是空的。
任何帮助将不胜感激。
在您的例子中,MyDynamicContext
和连接字符串都是运行时值。如 here 所述,不应将运行时数据注入组件。相反,您应该定义一个抽象,允许在构建对象图后检索运行时值。
在你的情况下,最好有一个允许检索 DbContext
的抽象,例如:
public interface IDbContextProvider {
DbContext Context { get; }
}
DbContext
的使用者可以使用 IDbContextProvider
抽象来获取当前上下文。实现可能如下所示:
class DbContextProvider : IDbContextProvider {
private readonly Func<DbContext> provider;
public DbContextProvider(Func<DbContext> provider) { this.provider = provider; }
public DbContext Context { get { return this.provider(); } }
}
而这个DbContextProvider
的注册可以如下所示:
var provider = new DbContextProvider(() => GetScopedItem(CreateContext));
container.RegisterSingleton<IDbContextProvider>(provider);
static T GetScopedItem<T>(Func<T> valueFactory) where T : class {
T val = (T)HttpContext.Current.Items[typeof(T).Name];
if (val == null) HttpContext.Current.Items[typeof(T).Name] = val = valueFactory();
return val;
}
static DbContext CreateContext() {
var header = HttpContext.Request.Headers.Get("custHeader");
string connectionString = "conStr";//get con based on the header, from a remote DB here
return new MyDynamicContext(connectionString);
}
我是 OWIN 和 IoC 的新手,现在我需要实现一个动态上下文,该上下文由基于 HTTP header 的 Simple Injector 解析,该 HTTP header 标识谁在调用我的 API .这种方法可能不是最好的方法,所以我也愿意接受另一种可能的解决方案。
这是我的 OWIN 启动 class:
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
var container = new Container();
string connectionString = string.Empty;
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.Use(async (context, next) =>
{
var customHeader = context.Request.Headers.Get("customHeader");
connectionString = "conStr";//get con based on the header, from a remote DB here
await next.Invoke();
});
app.UseOwinContextInjector(container);
container.Register<DbContext>(() => new MyDynamicContext(connectionString),
Lifestyle.Scoped);
//container.Register ...;
container.Verify();
httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
}
我遇到的问题是DI框架创建实例时连接字符串总是空的。
任何帮助将不胜感激。
在您的例子中,MyDynamicContext
和连接字符串都是运行时值。如 here 所述,不应将运行时数据注入组件。相反,您应该定义一个抽象,允许在构建对象图后检索运行时值。
在你的情况下,最好有一个允许检索 DbContext
的抽象,例如:
public interface IDbContextProvider {
DbContext Context { get; }
}
DbContext
的使用者可以使用 IDbContextProvider
抽象来获取当前上下文。实现可能如下所示:
class DbContextProvider : IDbContextProvider {
private readonly Func<DbContext> provider;
public DbContextProvider(Func<DbContext> provider) { this.provider = provider; }
public DbContext Context { get { return this.provider(); } }
}
而这个DbContextProvider
的注册可以如下所示:
var provider = new DbContextProvider(() => GetScopedItem(CreateContext));
container.RegisterSingleton<IDbContextProvider>(provider);
static T GetScopedItem<T>(Func<T> valueFactory) where T : class {
T val = (T)HttpContext.Current.Items[typeof(T).Name];
if (val == null) HttpContext.Current.Items[typeof(T).Name] = val = valueFactory();
return val;
}
static DbContext CreateContext() {
var header = HttpContext.Request.Headers.Get("custHeader");
string connectionString = "conStr";//get con based on the header, from a remote DB here
return new MyDynamicContext(connectionString);
}