2012-05-26 16 views
18

Tengo aplicación de prueba de implementación. que utiliza un mapeo de nhibernate fluido a un objeto db dentro de mssql db. Dado que quiero aprender a tocar bien nhib. aplicaciones mvc3, estoy usando esta aplicación. para propósitos de prueba que tienen solo una entidad simple con 10 propiedades de enumeración y una propiedad de cadena. Por lo tanto, es realmente una onda de luz, pero el tiempo de inicio según el generador de perfiles de nhibernate es de 4.37 segundos. Lo cual es realmente lento para renderizar una entidad con pocas líneas marcadas/sin marcar.Optimización de la fábrica de sesiones de nhibernate, tiempo de inicio de webApp realmente lento

El código es el siguiente. Domain.SessionProvider.cs

public static ISessionFactory CreateSessionFactory() 
{ 
    var config = Fluently.Configure() 
      .Database(MsSqlConfiguration.MsSql2008 
      .ConnectionString(c => c.FromConnectionStringWithKey("myConnection"))) 
      .Mappings(m => m.FluentMappings.Add<FeaturesMap>()) 
      .ExposeConfiguration(p => p.SetProperty("current_session_context_class", "web")) 
      .BuildConfiguration(); 

      return config.BuildSessionFactory();    
} 

Global.asax

public class MvcApplication : System.Web.HttpApplication 
{ 
    //SessionPerWebRequest is ommited here as well as other content 
    public static ISessionFactory SessionFactory = 
       SessionProvider.CreateSessionFactory(); 

    protected void Application_Start() 
    { 
     SessionFactory.OpenSession(); 
    } 
} 

Dentro myController He siguiente:

public ActionResult Index() 
{ 
    return View(GetData()); 
} 

private IList<FeaturesViewModel> GetData() 
{ 
    List<Features> data; 
    using (ISession session = MvcApplication.SessionFactory.GetCurrentSession()) 
    { 
      using (ITransaction tx = session.BeginTransaction()) 
      { 
       data = session.Query<Features>().Take(5).ToList(); 
       tx.Commit(); 

       var viewModelData = FeaturesViewModel.FromDomainModel(data); 
       return viewModelData; 
      } 
     } 
} 
+1

¿El tiempo de inicio es realmente tan importante? En una implementación adecuada, este costo no debería ocurrir a menudo. – Lucero

+0

con respecto a las aplicaciones web. Creo que este tiempo de inicio con esta entidad lightwave es "algo". ¿Estás diciendo que verifico la implementación? – BobRock

+0

Lo que estoy diciendo es que si esto ocurre una vez al día o cada varios días en un entorno implementado (siempre que su grupo de aplicaciones se recicla), ese costo no es un obstáculo. – Lucero

Respuesta

19

Puede mejorar el tiempo de inicio (de las aplicaciones web y de Windows) guardando en caché las configuraciones. La clase siguiente hará este trabajo:

using System.IO; 
using System.Reflection; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Web; 
using NHibernate.Cfg; 

namespace NH32AutoMap.Core 
{ 
    public class ConfigurationFileCache 
    { 
     private readonly string _cacheFile; 
     private readonly Assembly _definitionsAssembly; 

     public ConfigurationFileCache(Assembly definitionsAssembly) 
     { 
      _definitionsAssembly = definitionsAssembly; 
      _cacheFile = "nh.cfg"; 
      if (HttpContext.Current != null) //for the web apps 
       _cacheFile = HttpContext.Current.Server.MapPath(
           string.Format("~/App_Data/{0}", _cacheFile) 
           ); 
     } 

     public void DeleteCacheFile() 
     { 
      if (File.Exists(_cacheFile)) 
       File.Delete(_cacheFile); 
     } 

     public bool IsConfigurationFileValid 
     { 
      get 
      { 
       if (!File.Exists(_cacheFile)) 
        return false; 
       var configInfo = new FileInfo(_cacheFile); 
       var asmInfo = new FileInfo(_definitionsAssembly.Location); 

       if (configInfo.Length < 5 * 1024) 
        return false; 

       return configInfo.LastWriteTime >= asmInfo.LastWriteTime; 
      } 
     } 

     public void SaveConfigurationToFile(Configuration configuration) 
     { 
      using (var file = File.Open(_cacheFile, FileMode.Create)) 
      { 
       var bf = new BinaryFormatter(); 
       bf.Serialize(file, configuration); 
      } 
     } 

     public Configuration LoadConfigurationFromFile() 
     { 
      if (!IsConfigurationFileValid) 
       return null; 

      using (var file = File.Open(_cacheFile, FileMode.Open, FileAccess.Read)) 
      { 
       var bf = new BinaryFormatter(); 
       return bf.Deserialize(file) as Configuration; 
      } 
     } 
    } 
} 

usar que,

private Configuration readConfigFromCacheFileOrBuildIt() 
{ 
    Configuration nhConfigurationCache; 
    var nhCfgCache = new ConfigurationFileCache(MappingsAssembly); 
    var cachedCfg = nhCfgCache.LoadConfigurationFromFile(); 
    if (cachedCfg == null) 
    { 
     nhConfigurationCache = buildConfiguration(); 
     nhCfgCache.SaveConfigurationToFile(nhConfigurationCache); 
    } 
    else 
    { 
     nhConfigurationCache = cachedCfg; 
    } 
    return nhConfigurationCache; 
} 

Y a continuación, antes de llamar al BuildSessionFactory, podemos leer el archivo de configuración de la memoria caché o si las asignaciones han cambiado, construirlo y hacer caché de nuevo:

public ISessionFactory SetUpSessionFactory() 
{ 
    var config = readConfigFromCacheFileOrBuildIt(); 
    var sessionFactory = config.BuildSessionFactory(); 

Aquí usted puede encontrar una muestra completa: (^). + Si desea que funcione, separe las clases de dominio y los ensamblados de definiciones de asignaciones del ensamblado de la aplicación principal (porque la clase ConfigurationFileCache eliminará el archivo de caché si el ensamblado de definiciones de asignaciones es más reciente que LastWriteTime del archivo de caché).

+0

FYI: He probado esto en 3.3 y no hace la diferencia. Tal vez mi ssd es más rápido que los discos duros más antiguos, pero el problema de inicio sigue en pie. – Candide

2

IIRC correctamente, no es una buena idea crear objetos en el contructor de HttpApplication (o sus subclases como MvcApplication) . Es mejor crear la fábrica de sesiones en el controlador Application_Start.

Debe eliminar el perfilador NHibernate (ya que todos los perfiladores pueden afectar las mediciones). En su lugar, ponga la llamada a CreateSessionFactory() y rodéelo con el uso de la clase Stopwatch para obtener una medición precisa.

¿El servidor de la base de datos tarda en responder? Debido a la agrupación de conexiones, esto solo se notará en la primera ocasión.

NHibernate toma un tiempo para inicializarse, pero 4 segundos con una entidad ligera parecen demasiado. Sin embargo, esto está afectado por el rendimiento general del sistema de prueba.

+0

teniendo este código arriba en mente, puedo pedirle que me muestre cómo debe verse el método Application_Start. Gracias – BobRock

+0

En relación con su código original, simplemente mueva la llamada a CreateSessionFactory() en Application_Start(), y la llamada a OpenSession() en Application_BeginRequest(). Agregue el código adecuado para cerrar la sesión en Application_EndRequest(). El uso de Begin | EndRequest corresponde al patrón de sesión por solicitud. –

Cuestiones relacionadas