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);
    }
}

当然有很多方法可以做到,但你有想法