Web API,Light Inject 并将静态字典传递到数据层
Web API, Light Inject and Passing a Static Dictionary to the data layer
我们有一个多数据库解决方案,并将连接字符串传递给工厂函数,如下所示:
container.Register<IDbContextFactory>(
f => new DynamicDbContextFactory(ClientConfig.GetConnectionString()),
new PerScopeLifetime());
ClientConfig
包含一个静态字典,该字典在应用程序启动时填充,将子域映射到连接字符串。似乎这种方法会导致内存泄漏(不是 100% 确定会导致泄漏,但确实存在泄漏)。
public class ClientConfig
{
private static ConcurrentDictionary<string, string> ConnectionStringManager
{
get;
set;
}
// etc.
}
我的问题是在 MVC 中保存连接字符串列表的最佳方法是什么,可以在每个请求中轻松查找这些连接字符串以便将其传递到链中。
编辑:问题最初被标记为 Autofac
使用 Autofac,您不必使用 字典 和类似的东西来做您想要的。您可以使用自定义参数:
public class ConnectionStringParameter : Parameter
{
public override Boolean CanSupplyValue(ParameterInfo pi,
IComponentContext context,
out Func<Object> valueProvider)
{
valueProvider = null;
if (pi.ParameterType == typeof(String)
&& String.Equals(pi.Name, "connectionString",
StringComparison.OrdinalIgnoreCase))
{
valueProvider = () =>
{
// get connectionstring based on HttpContext.Current.Request.Url.Host
return String.Empty;
};
}
return valueProvider != null;
}
}
然后使用模块
注册您的参数
public class ConnectionStringModule : Autofac.Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += registration_Preparing;
}
private void registration_Preparing(Object sender, PreparingEventArgs e)
{
Parameter[] parameters = new Parameter[] { new ConnectionStringParameter() };
e.Parameters = e.Parameters.Concat(parameters);
}
}
您必须使用
在您的容器中注册的模块
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
每次 Autofac 必须解析名为 connectionString 的类型 String
的参数时,它将使用自定义参数并获取你的连接字符串基于你想要的。
顺便说一句,此代码示例使用 HttpContext.Current
。在多线程进程的情况下,它可能 return 为空。我不建议对此类事情使用 HttpContext.Current
。您可以使用中间 class 而不是访问它,例如 IConnectionstringProvider
接口。
public interface IConnectionstringProvider
{
String ConnectionString { get; }
}
public class ConnectionStringProvider : IConnectionstringProvider
{
public ConnectionStringProvider(Strong host)
{
// get connectionstring based on host
this._connectionString = String.Empty;
}
private readonly String _connectionString;
public String ConnectionString
{
get { return this._connectionString; }
}
}
在您的 Parameter 中,您必须将 valueProvider 更改为
valueProvider = () =>
{
return context.Resolve<IConnectionstringProvider>().ConnectionString;
};
最后,您必须在请求 lifetimescope 的开头注册您的 IConnectionstringProvider
:
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
IContainer container = builder.Build();
container.ChildLifetimeScopeBeginning += container_ChildLifetimeScopeBeginning;
}
private static void container_ChildLifetimeScopeBeginning(
Object sender, LifetimeScopeBeginningEventArgs e)
{
String host = HttpContext.Current.Request.Url.Host;
ContainerBuilder childLifetimeScopeBuilder = new ContainerBuilder();
childLifetimeScopeBuilder.RegisterInstance(new ConnectionStringProvider(host))
.As<IConnectionstringProvider>()
.SingleInstance();
childLifetimeScopeBuilder.Update(e.LifetimeScope.ComponentRegistry);
}
}
当然有很多方法可以做到,但你有想法
我们有一个多数据库解决方案,并将连接字符串传递给工厂函数,如下所示:
container.Register<IDbContextFactory>(
f => new DynamicDbContextFactory(ClientConfig.GetConnectionString()),
new PerScopeLifetime());
ClientConfig
包含一个静态字典,该字典在应用程序启动时填充,将子域映射到连接字符串。似乎这种方法会导致内存泄漏(不是 100% 确定会导致泄漏,但确实存在泄漏)。
public class ClientConfig
{
private static ConcurrentDictionary<string, string> ConnectionStringManager
{
get;
set;
}
// etc.
}
我的问题是在 MVC 中保存连接字符串列表的最佳方法是什么,可以在每个请求中轻松查找这些连接字符串以便将其传递到链中。
编辑:问题最初被标记为 Autofac
使用 Autofac,您不必使用 字典 和类似的东西来做您想要的。您可以使用自定义参数:
public class ConnectionStringParameter : Parameter
{
public override Boolean CanSupplyValue(ParameterInfo pi,
IComponentContext context,
out Func<Object> valueProvider)
{
valueProvider = null;
if (pi.ParameterType == typeof(String)
&& String.Equals(pi.Name, "connectionString",
StringComparison.OrdinalIgnoreCase))
{
valueProvider = () =>
{
// get connectionstring based on HttpContext.Current.Request.Url.Host
return String.Empty;
};
}
return valueProvider != null;
}
}
然后使用模块
注册您的参数public class ConnectionStringModule : Autofac.Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += registration_Preparing;
}
private void registration_Preparing(Object sender, PreparingEventArgs e)
{
Parameter[] parameters = new Parameter[] { new ConnectionStringParameter() };
e.Parameters = e.Parameters.Concat(parameters);
}
}
您必须使用
在您的容器中注册的模块ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
每次 Autofac 必须解析名为 connectionString 的类型 String
的参数时,它将使用自定义参数并获取你的连接字符串基于你想要的。
顺便说一句,此代码示例使用 HttpContext.Current
。在多线程进程的情况下,它可能 return 为空。我不建议对此类事情使用 HttpContext.Current
。您可以使用中间 class 而不是访问它,例如 IConnectionstringProvider
接口。
public interface IConnectionstringProvider
{
String ConnectionString { get; }
}
public class ConnectionStringProvider : IConnectionstringProvider
{
public ConnectionStringProvider(Strong host)
{
// get connectionstring based on host
this._connectionString = String.Empty;
}
private readonly String _connectionString;
public String ConnectionString
{
get { return this._connectionString; }
}
}
在您的 Parameter 中,您必须将 valueProvider 更改为
valueProvider = () =>
{
return context.Resolve<IConnectionstringProvider>().ConnectionString;
};
最后,您必须在请求 lifetimescope 的开头注册您的 IConnectionstringProvider
:
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
IContainer container = builder.Build();
container.ChildLifetimeScopeBeginning += container_ChildLifetimeScopeBeginning;
}
private static void container_ChildLifetimeScopeBeginning(
Object sender, LifetimeScopeBeginningEventArgs e)
{
String host = HttpContext.Current.Request.Url.Host;
ContainerBuilder childLifetimeScopeBuilder = new ContainerBuilder();
childLifetimeScopeBuilder.RegisterInstance(new ConnectionStringProvider(host))
.As<IConnectionstringProvider>()
.SingleInstance();
childLifetimeScopeBuilder.Update(e.LifetimeScope.ComponentRegistry);
}
}
当然有很多方法可以做到,但你有想法