Ton*_*onE 7 structuremap nhibernate asp.net-mvc inversion-of-control
我正在使用Fluent NHibernate开发Asp.Net MVC 3应用程序.我只是尝试使用StructureMap添加IoC容器.
我已经实现了一个自定义控制器工厂,它使用StructureMap来创建控制器并注入依赖项.每个控制器构造函数都接受一个或多个服务,而这些服务又将DAO作为构造函数参数.每个DAO构造函数都使用一个ISessionFactory.
对于我的StructureMap NHibernate注册表,我有以下内容:
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
For<ISessionFactory>()
.Singleton()
.Use(x => new AppSessionFactory().GetSessionFactory(connectionString));
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Use(x => x.GetInstance<ISessionFactory>().OpenSession());
}
}
public class AppSessionFactory
{
public ISessionFactory GetSessionFactory(string connectionString)
{
return GetConfig(connectionString)
.BuildSessionFactory();
}
public static FluentConfiguration GetConfig(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
.Mappings(
x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
}
}
Run Code Online (Sandbox Code Playgroud)
这一切都适用于单个数据库和单个会话工厂.但是应用程序使用多个数据库.
处理这个问题的最佳方法是什么?
注册多个会话工厂很容易 - 问题是在需要时选择正确的工厂.例如,假设我们有某种具有多个数据库的实验室.每个实验室都有一个位置和该位置的多个样本.我们可以有一个SampleRepository来模拟它.每个位置都有一个唯一的密钥来识别它(例如"LabX","LabY","BlackMesa").我们可以使用该唯一键作为app.config文件中数据库连接字符串的名称.在这个例子中,我们在app.config文件中有三个连接字符串.这是一个示例connectionStrings部分:
<connectionStrings>
<add name="LabX" connectionString="Data Source=labx;User ID=someuser;Password=somepassword"/>
<add name="LabY" connectionString="Data Source=laby;User ID=someuser;Password=somepassword"/>
<add name="BlackMesa" connectionString="Data Source=blackmesa;User ID=freemang;Password=crowbar"/>
</connectionStrings>
Run Code Online (Sandbox Code Playgroud)
因此,我们需要为每个连接字符串建立一个唯一的会话工厂.让我们创建一个包装ISessionFactory的NamedSessionFactory:
public interface INamedSessionFactory
{
public string Name { get; } // The name from the config file (e.g. "BlackMesa")
public ISessionFactory SessionFactory { get; }
}
public class NamedSessionFactory : INamedSessionFactory
{
public string Name { get; private set; }
public ISessionFactory SessionFactory { get; private set; }
public NamedSessionFactory(string name, ISessionFactory sessionFactory)
{
Name = name;
SessionFactory = sessionFactory;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们需要稍微修改你的AppSessionFactory.首先,你创建的是一个会议工厂工厂 - 这不是我们想要的.我们希望为我们的工厂提供一个位置并从中获取会话,而不是会话工厂.流畅的NHibernate为我们提供了会话工厂.
public interface IAppSessionFactory
{
ISession GetSessionForLocation(string locationKey);
}
Run Code Online (Sandbox Code Playgroud)
这里的技巧是接受构造函数中的INamedSessionFactory对象列表.StructureMap应该为我们提供已注册的所有INamedSessionFactory对象.我们将在一秒钟内完成注册.
public class AppSessionFactory : IAppSessionFactory
{
private readonly IList<INamedSessionFactory> _factories;
public AppSessionFactory(IEnumerable<INamedSessionFactory factories)
{
_factories = new List<INamedSessionFactory>(factories);
}
Run Code Online (Sandbox Code Playgroud)
这就是魔术发生的地方.给定一个位置键,我们运行我们的工厂列表,寻找一个与locationKey同名的工厂,然后让它打开一个会话并将其返回给调用者.
public ISession GetSessionForLocation(string locationKey)
{
var sessionFactory = _factories.Where(x => x.Name == locationKey).Single();
return sessionFactory.OpenSession();
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们把它们连在一起.
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
Run Code Online (Sandbox Code Playgroud)
我们将遍历app.config文件中的所有连接字符串(在此示例中将有三个连接字符串)并为每个连接字符串注册一个INamedSessionFactory对象.
foreach (ConnectionStringSettings location in ConfigurationManager.ConnectionStrings)
{
For<INamedSessionFactory>()
.Singleton()
.Use(x => new NamedSessionFactory(
location.Name,
GetSessionFactory(location.ConnectionString));
}
Run Code Online (Sandbox Code Playgroud)
我们还需要注册IAppSessionFactory.
For<IAppSessionFactory>()
.Singleton()
.Use<AppSessionFactory>();
}
Run Code Online (Sandbox Code Playgroud)
您会注意到我们已将此逻辑移出工厂类......这些是从Fluent NHibernate创建会话工厂的辅助方法.
private static ISessionFactory GetSessionFactory(string connectionString)
{
return GetConfig(connectionString)
.BuildSessionFactory();
}
public static FluentConfiguration GetConfig(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
.Mappings(
x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
}
}
Run Code Online (Sandbox Code Playgroud)
应该这样做!让我们创建一个存储库来获取我们的样本......
public class SampleRepository
{
private readonly IAppSessionFactory _factory;
public SampleRepository(IAppSessionFactory factory)
{
_factory = factory;
}
public IEnumerable<Sample> GetSamplesForLocation(Location location)
{
using (ISession session = _factory.GetSessionForLocation(location.Key)
{
foreach (Sample sample in session.Query<Sample>())
yield return sample;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您可以获取SampleRepository的单个实例,并使用GetSamplesForLocation方法从我们在app.config中注册的三个数据库中的任何一个中提取样本.可能想要避免使用BlackMesa.我知道那里有问题.
| 归档时间: |
|
| 查看次数: |
3227 次 |
| 最近记录: |