我有一个使用多个数据库的应用程序。
我发现我可以通过使用连接构建器来改变它。像这样:
var configNameEf = "ProjectConnection";
var cs = System.Configuration.ConfigurationManager.ConnectionStrings[configNameEf].ConnectionString;
var sqlcnxstringbuilder = new SqlConnectionStringBuilder(cs);
sqlcnxstringbuilder.InitialCatalog = _Database;
然后我需要更改UnitOfWork的autofac Lifescope,以便它现在将请求重定向到良好的数据库实例。
我在很长一段时间后发现的是,我可以从DelegatedHandler那样做:
HttpConfiguration config = GlobalConfiguration.Configuration;
DependencyConfig.Register(config, sqlcnxstringbuilder.ToString());
request.Properties["MS_DependencyScope"] = config.DependencyResolver.GetRequestLifetimeScope();
问题是,还有其他方法可以改变请求的MS_DependencyScope参数。这个解决方案有效,但我觉得它有点阴暗。
这是DependencyConfig中的注册表:
public static void Register(HttpConfiguration config, String bdContext = null)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.Register(_ => new ProjectContext(bdContext)).As<ProjectContext>().InstancePerApiRequest();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
// Register IMappingEngine
builder.Register(_ => Mapper.Engine).As<IMappingEngine>().SingleInstance();
config.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build());
config.DependencyResolver.BeginScope();
}
答案 0 :(得分:2)
描述问题的方式以及我的评论的答案听起来的方式,您有以下情况:
假设我已正确理解这个问题......
如果应用程序设置在web.config中(如图所示),则更改web.config中的字符串实际上会重新启动应用程序。此问题更详细地讨论了这个问题: How to prevent an ASP.NET application restarting when the web.config is modified?
如果是这样的话,你就没有任何工作要做 - 只需将数据库注册为单例,当web.config发生变化时,应用程序重新启动,重新运行应用启动逻辑,获取新数据库,并发生魔术。
如果应用设置不在web.config中,那么您应该创建一个项目上下文工厂类。
工厂将作为读取配置和构建与数据库连接的逻辑的封装。它还可以作为在设置未发生变化时缓存连接的地方。
界面看起来像这样:
public interface IProjectContextFactory
{
ProjectContext GetContext();
}
一个简单的实现(没有锁定,错误处理,日志记录以及你应该放入的所有好东西)可能是:
public class ProjectContextFactory : IProjectContextFactory
{
private ProjectContext _currentContext = null;
private string _currentConnectionString = null;
private const string ConnectionKey = "ProjectConnection";
public ProjectContext GetContext()
{
// Seriously, don't forget the locking, etc. in here
// to make this thread-safe! I'm omitting it for simplicity.
var cs = ConfigurationManager.ConnectionStrings[ConnectionKey].ConnectionString;
if(this._currentConnectionString != cs)
{
this._currentConnectionString = cs;
var builder = new SqlConnectionStringBuilder(cs);
builder.InitialCatalog = _Database;
this._currentContext = new ProjectContext(builder.ToString());
}
return this._currentContext;
}
}
好的,现在您有一个工厂可以缓存已构建的项目上下文,并且仅在配置更改时才更改它。 (如果您没有缓存ProjectContext
而是缓存数据库连接字符串或其他内容,原则仍然存在 - 您需要一个管理缓存和检查配置的类,以便更改可以根据需要发生。)
现在你有了一个缓存/工厂,你可以在Autofac注册中使用它而不是原始连接字符串。
builder.RegisterType<ProjectContextFactory>()
.As<IProjectContextFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<IProjectContextFactory>().GetContext())
.As<ProjectContext>()
.InstancePerRequest();
当配置的连接字符串发生更改时,ProjectContext
现在将根据请求进行更改。
除此之外:我发现请求生命周期范围内存在奇怪的事情。我在您的注册中看到您正在创建自己的请求生命周期范围。使用这种方法你不应该这样做。但是,如果您发现仍然需要(或想要),则需要确保原始创建的生命周期范围和您创建的范围都已处理完毕。生命周期范围不会自动生成处置并挂在物件参考上,以便处理。很有可能如果你没有正确处理这个问题,那么你就会有一个微妙的内存泄漏。 Autofac Web API集成将负责为您创建和处理请求生命周期,但如果您更改请求生命周期,则会发生奇怪的事情。