一个架构问题。我有一个很好的去耦合MVC3解决方案,有一些项目运作得相当好。
Proj.Core - interfaces for data classes and services Proj.Services - interfaces for model services Proj.Data.NH - implementations of the data interfaces Proj.Services.NH - implementations of the data / model services Proj.Infrastructure - setting up Ninject and NHibernate Proj.Tests - unit tests Proj.Web - the MVC project
我已经将NHibernate设置为基础架构项目中的每个请求的会话,因此Proj.Web不需要引用NHibernate(或者Ninject)。我现在正在介绍SignalR,它非常适合快速聊天应用程序。我在网络项目中放置了一个SignalR集线器。我现在想在数据库中保留聊天消息,这让我有些困惑。
我想使用服务(让我们称之为PostService
),因此SignalR中心不依赖于NHibernate。我的其他服务被注入到控制器的构造函数中,会话被注入到服务的构造函数中。
当SignalR集线器挂起时,与控制器不同,PostService
(作为IPostService
注入到构造函数中)不能将会话注入其构造函数中,因为不存在会话。如果有,它将永远存在,这对于交易来说将是太长的时间。
我可以将会话工厂注入PostService
,每个方法都可以使用一个事务,例如
private void WithTransaction(Action<ISession> action)
{
using (var session = _sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
action(session);
tx.Commit();
}
}
public IPost Post(string message)
{
WithTransaction(session =>
{
session.Save(new Post(message));
});
}
然后,集线器将调用_postService.Post(message);
然而,一旦Post
方法做了更多的事情,我就会想要使用我现有的一些服务来做这些事情,因为它们已经被编写并经过单元测试。由于会话是在方法中创建的,因此我无法将服务注入PostService
构造函数,因为它们接受了构造函数中的会话。
所以,我想我有以下选项,但我不确定a)这是一个完整的清单,还是b)哪个是最好的选择:
予。将IDependencyResolver
注入PostService
构造函数,并在Post
方法中创建我需要的服务,并将会话传递给构造函数。 System.Web.Mvc和SignalR中有一个IDependencyResolver
,所以这会(取决于哪个项目PostService
驻留)对这两个库引入依赖。
II。修改服务,以便使用会话的每个方法都作为参数传入。在没有session参数的情况下重载此函数,并调用新参数。 MVC服务调用将使用第一个,而PostService
将使用第二个例如。
public void SaveUser(IUser user)
{
Save(_session, user);
}
public void SaveUser(ISession session, IUser user)
{
session.Save(user);
}
III。不要使用现有服务。让PostService
做自己的事情,即使有一些重复(例如获取用户详细信息等)。
IV。从服务的构造函数中删除ISession,并将其传递给每个方法(并相应地处理Controller
s。
诉别的。
我想我倾向于第一个,但我不确定PostService
将在哪里生活。如果它进入Proj.Services.NH,那么我必须在System.Web.Mvc或SignalR上引入依赖,我不想这样做。如果它存在于Proj.Web中,那么我必须引入对NHibernate的依赖,我也不想这样做。它不属于Proj.Infrastructure,因为它是应用程序代码。它应该拥有自己的项目,依赖于一切,还是有更好的方法?
答案 0 :(得分:3)
我会使用某种汽车工厂来提供您需要的其他服务。因此,您可以将PostService
构造函数编写为:
public PostService( Func<INeededService1> factory1,Func<INeededService2> factory2 ...)
{
...
}
然后使用this extension让这些工厂自动工作(通过查询容器)。