0

我创建了一个示例项目来尝试一些新模式,即 Dao 和 IoC。

My Dao 定义如下:

public class Dao<T> : IDao<T>
{
    protected NHibernate.ISessionFactory _sessionFactory;

    public Dao(NHibernate.ISessionFactory sessionFactory)
    {
        this._sessionFactory = sessionFactory;
    }

    protected NHibernate.ISession Session
    {
        get { return _sessionFactory.GetCurrentSession(); }
    }

    public T GetById(object id)
    {
        return Session.Get<T>(id);
    }

    ...
}

我有一个相应的安装程序:

public class DaoInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For(typeof(Data.IDao<>))
            .ImplementedBy(typeof(Data.Dao<>))
            .ServiceOverrides(ServiceOverride.ForKey("SessionFactory").Eq("FirstSessionFactory"))
            .Named("FirstDao"));
    }
}

使用 MVC 模式,我可以定义一个带有构造函数的控制器,该构造函数将接受IDao<MyClass> myClass作为参数,Windsor 将为我完成所有使用正确 SessionFactory 实例化 Dao 的魔法。我的问题是,如何在非 MVC 环境中实现相同的行为?那么在任何特定页面上,我如何获取 myClass 的实例?

4

2 回答 2

2

在 MVC 之前,ASP.Net 不是为使用 IoC 模式而构建的。MVC 是 IoC 感知的,并且有一些扩展点,Windsor 和其他 IoC 实现可以插入到 MVC 框架中,以接管从 MVC 的默认工厂实例化完全配置的控制器的任务。Web 表单站点中没有这样的工具可以为您实例化页面类。

在 Web 表单项目中使用 NHibernate 需要使用 HttpRequest 的 Items 集合,通常还有一个 HttpModule,它将在 Page 类处理请求之前和之后执行代码。在请求开始时,该模块会创建一个 NHibernate 会话并将其放入请求的 Items 集合(您可以将它放在 ASP.Net 上的唯一一个地方)。然后页面上的代码就可以进入会话。页面类将根据需要实例化一个 IDao 实现,并将会话传递给它。在请求结束时,模块中的代码将刷新并关闭会话。这样,所有会话管理都对页面处理程序中的代码透明地处理。(这是我在切换到 MVC 和 Sharp 架构框架之前所做的。这是很多基础架构代码,很难做到恰到好处;我 我很高兴现在改用 Sharp Architecture。它经过深思熟虑,而且比我的眼睛还多。)

您仍然可以在 Web 表单项目中使用 IoC 容器,但它不是完全透明的。您可以明确地向您的容器询问 IDao 的实现。您必须配置 IoC 容器以向 IDao 实现提供 ISession 实现,并将其配置为使用每个 Web 请求语义来管理会话生命周期。但它不像在 MVC 中那样干净,在控制器中没有用于此的代码。

于 2011-06-20T22:08:04.587 回答
0

谢谢您的回答。不幸的是,因为我对这个领域太陌生(我手头的时间非常有限),我现在比以前更加困惑。据我了解,网络表单并不意味着与 IoC 一起使用,尽管存在变通方法,但它们相当复杂。我想我会放弃 Windsor,直到我将项目迁移到 MVC,因为现在我使用了一个简单的静态SessionManager类。

然后SessionManager负责SessionFactoriesContainer在App_Init期间进行实例化,定义为:

public static readonly Dictionary<string, ISessionFactory> SessionFactoriesContainer = new Dictionary<string, ISessionFactory>();

SessionsContainer定义为:

public static Dictionary<string, ISession> SessionsContainer
    {
        get
        {
            Dictionary<string, ISession> sessionContainer = (Dictionary<string, ISession>)HttpContext.Current.Items[SESSION_CONTAINER_KEY] ?? new Dictionary<string, ISession>();
            foreach (FactoryType type in Enum.GetValues(typeof(FactoryType)))
            {
                if (!sessionContainer.ContainsKey(type.ToString()))
                    sessionContainer.Add(type.ToString(), null);
            }
            HttpContext.Current.Items[SESSION_CONTAINER_KEY] = sessionContainer;
            return sessionContainer;
        }
    }

虽然SessionsContainer是静态的,但由于它存储在 HttpContext 我的理解是每个用户都有自己的容器,我假设这个错误吗?

SessionManager 还有一个类GetSessionFor定义为:

public static ISession GetSessionFor(FactoryType type)
    {
        ISession session = SessionsContainer[type.ToString()] ?? SessionFactoriesContainer[type.ToString()].OpenSession();
        session.BeginTransaction();
        SessionsContainer[type.ToString()] = session;

        return session;
    }

每当需要新的存储库时都会调用此方法,然后将 ISession 传递给构造函数。在请求结束时,每个打开的会话都将被提交或事务将在出现错误时回滚。

我意识到这是一个非常粗略的实现,但我认为它应该可以工作。如果我在项目结束时有时间,我的目标是重新审视会话管理并希望实施安装程序。同时,如果有人有更多的想法,请随时添加。

于 2011-06-22T13:17:11.430 回答