如何使用asp.net mvc3和nhibernate增加web应用程序的性能

pan*_*njo 3 c# nhibernate asp.net-mvc

我正在使用mvc3 nhibernate orm层和mssql db开发我的第一个应用程序.

这是我使用nhibernate创建的第一个应用程序,除了intiial responsn time,一切都很好.经过一些调查,我实现了每个Web请求的会话,这绝对是一个升级,我的实体在第一次调用后加载得更快,但我的问题仍然是一样的.

初始响应时间非常慢,当我键入domainname.com并按下enter等待时间约为.10-15秒 并且这不是内容的实际加载时间,在那之后10-15秒.我的网站开始加载,几秒钟.

是时候会话工厂必须初始化所有需要的"东西",但我认为它必须是别的东西.这是无法接受的.

我的应用程序在站点内存分配200 MB的winhost上运行,所以我认为这不是问题.

任何提示都是受欢迎的.如果您需要更多详细信息,请询问.

谢谢

更新: 在使用nhibernate profiler检查应用程序会话使用情况后,我发现了一些有趣的东西.由于我真的是使用探查器的初学者,我想我发现了昂贵的会话.在一般统计中,67个实体以36.571的持续时间加载,以秒为单位.这个秒值真的很奇怪,因为我有10-max 15秒加载.

第二次更新: global.asax

public class MvcApplication : System.Web.HttpApplication{     

public static ISessionFactory SessionFactory =
        MyDomain.Infrastructure.SessionProvider.CreateSessionFactory();

//My session factory is open in Application_Start() like this 
SessionFactory.OpenSession();

}
Run Code Online (Sandbox Code Playgroud)

我正在使用流畅的方法来映射我的对象.所以我在域项目中的会话提供程序看起来像这样

//This should be used from web app, global.asax.cs calls
        public static ISessionFactory CreateSessionFactory()
        {
            string conStringName = "ConnectionString";
            var cfg = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                .ConnectionString(c => c.FromConnectionStringWithKey(conStringName)))
                .Mappings(m => m.FluentMappings.Add<Entity1>())
                .Mappings(m => m.FluentMappings.Add<Entity2>())
                .Mappings(m => m.FluentMappings.Add<Entity3>())
                .ExposeConfiguration(p => p.SetProperty("current_session_context_class", "web"))
                .BuildConfiguration();

            return cfg.BuildSessionFactory();            
        }
Run Code Online (Sandbox Code Playgroud)

更新3 仍然没有解决此问题的方法

更新4和最后 我的问题在sessionFactory中定义.我认为我的配置对象应该被序列化.如果有人能够表达如何使用我的代码显示如何做到这一点与流利conf.我很乐意接受他/她的回答.谢谢.

Rau*_*ess 12

很多细节都缺失了,但既然你说这是你的第一个NHibernate应用程序,我将推荐可能要检查的东西:

  • 在应用程序启动时创建一次NH SessionFactory(正如@Rippo所见).SessionFactory 创建起来昂贵.在Application_Start()中执行
  • 为每个Web请求打开一个新的NH会话.请求结束后,将其丢弃.NH ISession便宜/快速创建.通常,长时间重用或缓存ISession是不好的做法.对于一个简单的实现,如果您愿意,可以在Controller中执行此操作,因为它仅适用于每个请求.
  • 查询时(NH LINQ?QueryOver?您使用什么),请务必限制返回的记录.不要.ToList()整个表,只显示20.使用Skip/Take.
  • 注意SELECT N + 1问题.这可能会破坏您在任何OR/M上的表现.

这些将是我的建议,代码看不见.

更新:所以主要问题似乎是10-15秒启动,这可能是Application_Start期间的SessionFactory初始化时间.

我还没有尝试过,但是快速启动时的一般建议是将NH Configuration对象序列化为磁盘(包含映射),并在每次启动时加载(原始缓存).如果映射发生更改,则需要检测该映射,否则执行手动加载(删除序列化配置文件).

在您的代码中,您使用Fluent NHibernate构建FluentNHibernate.Cfg.FluentConfiguration实例,并在其上调用cfg.BuildSessionFactory()以返回新的ISessionFactory.您需要序列化的配置是NHibernate.Cfg.Configuration.所以你可能会修改你的代码:

    public static ISessionFactory CreateSessionFactory()
    {
        string conStringName = "ConnectionString";

        // http://weblogs.asp.net/ricardoperes/archive/2010/03/31/speeding-up-nhibernate-startup-time.aspx
        System.Runtime.Serialization.IFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

        NHibernate.Cfg.Configuration cfg = null;

        if (File.Exists("Configuration.serialized"))
        {
            using (Stream stream = File.OpenRead("Configuration.serialized"))
            {
                cfg = serializer.Deserialize(stream) as Configuration;
            }
        }
        else
        {
            // file not exists, configure normally, and serialize NH configuration to disk
            cfg = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                .ConnectionString(c => c.FromConnectionStringWithKey(conStringName)))
                .Mappings(m => m.FluentMappings.Add<Entity1>())
                .Mappings(m => m.FluentMappings.Add<Entity2>())
                .Mappings(m => m.FluentMappings.Add<Entity3>())
                .ExposeConfiguration(p => p.SetProperty("current_session_context_class", "web"))
                .BuildConfiguration();

            using (Stream stream = File.OpenWrite("Configuration.serialized"))
            {
                serializer.Serialize(stream, cfg);
            }
        }

        return cfg.BuildSessionFactory();
    }
Run Code Online (Sandbox Code Playgroud)

这会将配置缓存到磁盘,因此您的应用初创公司将会很快.当然,当您更改NH映射时,您必须检测并重新加载Fluent配置,否则手动删除缓存文件.

其他一些调整评论:

  • 你有.Mappings(m => m.FluentMappings.Add()).映射(m => m.FluentMappings.Add())等.只是猜测一下,但是逐个添加可能会创建多个HBM文件引擎盖下.您可以尝试从外部程序集添加映射,并使用.Mappings(M => M.FluentMappings.AddFromAssemblyOf())
  • 实际上你不应该在Application_Start()中做SessionFactory.OpenSession().只需在那里创建SessionFactory,并在代码中访问SessionFactory.GetCurrentSession().你的global.asax应该有:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        // we open one NH session for every web request, 
        var nhsession = SessionFactory.OpenSession();
        // and bind it to the SessionFactory current session
        CurrentSessionContext.Bind(nhsession);
    }
    
    protected void Application_EndRequest(object sender, EventArgs e)
    {
        // close/unbind at EndRequest
        if (SessionFactory != null)
        {
            var nhsession = CurrentSessionContext.Unbind(SessionFactory);
            nhsession.Dispose();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

这将是按请求进行会话的方式.