c# - 如何使用 asp.net mvc3 和 nhibernate 提高 Web 应用程序性能

标签 c# asp.net-mvc nhibernate

我正在使用带有 mssql 数据库的 mvc3 nhibernate orm 层开发我的第一个应用程序。

这是我使用 nhibernate 创建的第一个应用程序,除了初始响应时间外,一切都很好。经过一些调查后,我实现了每个 Web 请求的 session ,这绝对是一次升级,我的实体在第一次调用后加载得更快,但我的问题仍然存在。

初始响应时间真的很慢,当我输入 domainname.com 并按下回车键时,等待时间大约为 10 分钟。 10-15 秒。这不是内容的实际加载时间,在该时间之后 10-15 秒。我的网站开始加载,几秒钟。

那个时候 session 工厂必须初始化所有需要的“东西”,但我认为它一定是别的东西。这是 Not Acceptable 。

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

欢迎任何提示。如果您需要更多详细信息,请询问。

谢谢

更新: 在使用 nhibernate 分析器检查应用程序 session 使用后,我发现了一些有趣的东西。由于我真的是使用探查器的初学者,我认为我发现了昂贵的 session 。 在一般统计中,67 个实体在 36.571 秒内加载。这个秒值真的很奇怪,因为我有 10-max 15 秒的加载时间。

第二次更新: 全局.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();

}

我正在使用流畅的方法来映射我的对象。所以我在域项目中的 session 提供者看起来像这样

//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();            
        }

更新 3 这个问题仍然没有解决方案

更新 4 和最终版本 我的问题肯定在 sessionFactory 中。我认为我的配置对象应该被序列化。如果有人能友好地展示如何使用我在此处显示的代码和流利的 conf 来做到这一点。我会很乐意接受他/她的回答。谢谢。

最佳答案

缺少很多细节,但既然您说这是您的第一个 NHibernate 应用程序,我将推荐可能需要检查的内容:

  • 在应用程序启动时创建一次 NH SessionFactory(如@Rippo 所说)。 SessionFactory 是 expensive to create .在 Application_Start() 中执行
  • 为每个网络请求打开一个新的 NH session 。请求结束后,将其丢弃。 NH ISession 便宜/快速创建。通常,长时间重用或缓存 ISession 是不好的做法。对于一个简单的实现,如果你愿意,你可以在你的 Controller 中完成,因为它只存在于每个请求中。
  • 查询时(NH LINQ?QueryOver?你用什么),一定要限制返回的记录。不要 .ToList() 整个表格,只显示 20。使用 Skip/Take。
  • 注意 SELECT N+1 problem .这会降低您在任何 OR/M 上的表现。

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

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

我还没有尝试过,但要获得快速启动时间的一般建议是将 NH 配置对象序列化到磁盘(其中包含映射),并在每次启动时加载它(原始缓存)。如果映射发生变化,您需要检测到它,或者进行手动加载(删除序列化配置文件)。

在您的代码中,您正在使用 Fluent NHibernate 构建 FluentNHibernate.Cfg.FluentConfiguration 实例,并对其调用 cfg.BuildSessionFactory() 以返回新的 ISessionFactory。您需要序列化的 Configuration 是 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();
    }

这会将配置缓存到磁盘,因此您的应用程序启动速度会很快。当然,当您更改 NH 映射时,您必须检测到并重新加载 Fluent Configuration,或者手动删除缓存文件。

一些其他调整意见:

  • 你有 .Mappings(m => m.FluentMappings.Add()).Mappings(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();
        }
    }
    

这就是按请求进行 session 的方式。

关于c# - 如何使用 asp.net mvc3 和 nhibernate 提高 Web 应用程序性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10759317/

相关文章:

c# - 为什么锁定我们要更改的对象是一种不好的做法?

C# 获取 SQL 查询返回的数据大小

c# - REST Api 服务器挂起大量请求(使用 c# HttpClient)

c# - 如何在 ASP.Net MVC 5 的 AspNetUsers 表中获取 ApplicationUser 的数量?

c# - 使用 NHibernate 在 MVC3 中处理异常和回滚

c# - 如何附加到 Visual Studio Code 中的特定进程

c# - 具有键 'XXX' 的 ViewData 项的类型为 'System.Int32' 但必须为 'IEnumerable<SelectListItem>' 类型

asp.net-mvc - ModelState.AddModelError 不显示任何消息

c# - 无法使用 QueryOver 解析复合属性

linq - NHibernate.Linq赞