Nhibernate Lazy Load-Ausnahme nach einer Ansichtsausnahme

Ich bekomme ein seltsames Verhalten mit NHibernate mit Fluent Configuration.

Wenn eine generische Ausnahme auftritt, die nichts mit dem NHibernate zu tun hat, d. H. In der Ansicht aDivideByZeroException jede Anfrage nach dem Auslösen der Ausnahme.

An exception of type 'NHibernate.LazyInitializationException' occurred in NHibernate.dll but was not handled in user code. Additional information: Initializing[Entity]-Could not initialize proxy - no Session.

Aufgrund der Art des Fehlers ist der Fehler kritisch, da 1 Benutzer die gesamte Website zum Absturz bringen kann, wenn er eine Ausnahme generiert.

Folgend kümmert sich mein HttpModule für Nhibernate mit Asp.Net MVC 5 um die Sitzungen.

NHibernateSessionPerRequest.cs
public class NHibernateSessionPerRequest : IHttpModule
{
    private static readonly ISessionFactory SessionFactory;

    // Constructs our HTTP module
    static NHibernateSessionPerRequest()
    {
        SessionFactory = CreateSessionFactory();
    }

    // Initializes the HTTP module
    public void Init(HttpApplication context)
    {
        context.BeginRequest += BeginRequest;
        context.EndRequest += EndRequest;
    }

    // Disposes the HTTP module
    public void Dispose() { }

    // Returns the current session
    public static ISession GetCurrentSession()
    {
        return SessionFactory.GetCurrentSession();
    }

    // Opens the session, begins the transaction, and binds the session
    private static void BeginRequest(object sender, EventArgs e)
    {
        ISession session = SessionFactory.OpenSession();

        session.BeginTransaction();

        CurrentSessionContext.Bind(session);
    }

    // Unbinds the session, commits the transaction, and closes the session
    private static void EndRequest(object sender, EventArgs e)
    {
        ISession session = CurrentSessionContext.Unbind(SessionFactory);

        if (session == null) return;

        try
        {
            session.Transaction.Commit();
        }
        catch (Exception)
        {
            session.Transaction.Rollback();
            throw;
        }
        finally
        {
            session.Close();
            session.Dispose();
        }
    }

    // Returns our session factory
    private static ISessionFactory CreateSessionFactory()
    {
        if (HttpContext.Current != null) //for the web apps
            _configFile = HttpContext.Current.Server.MapPath(
                            string.Format("~/App_Data/{0}", CacheFile)
                            );

        _configuration = LoadConfigurationFromFile();
        if (_configuration == null)
        {
            FluentlyConfigure();
            SaveConfigurationToFile(_configuration);
        }
        if (_configuration != null) return _configuration.BuildSessionFactory();
        return null;
    }



    // Returns our database configuration
    private static MsSqlConfiguration CreateDbConfigDebug2()
    {
        return MsSqlConfiguration
            .MsSql2008
            .ConnectionString(c => c.FromConnectionStringWithKey("MyConnection"));
    }

    // Updates the database schema if there are any changes to the model,
    // or drops and creates it if it doesn't exist
    private static void UpdateSchema(Configuration cfg)
    {
        new SchemaUpdate(cfg)
            .Execute(false, true);
    }
    private static void SaveConfigurationToFile(Configuration configuration)
    {
        using (var file = File.Open(_configFile, FileMode.Create))
        {
            var bf = new BinaryFormatter();
            bf.Serialize(file, configuration);
        }
    }

    private static Configuration LoadConfigurationFromFile()
    {
        if (IsConfigurationFileValid == false)
            return null;
        try
        {
            using (var file = File.Open(_configFile, FileMode.Open))
            {
                var bf = new BinaryFormatter();
                return bf.Deserialize(file) as Configuration;
            }
        }
        catch (Exception)
        {
            return null;
        }

    }
    private static void FluentlyConfigure()
    {
        if (_configuration == null)
        {
            _configuration = Fluently.Configure()
            .Database(CreateDbConfigDebug2)
            .CurrentSessionContext<WebSessionContext>()
            .Cache(c => c.ProviderClass<SysCacheProvider>().UseQueryCache())
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<EntityMap>()
                .Conventions.Add(DefaultCascade.All(), DefaultLazy.Always()))
            .ExposeConfiguration(UpdateSchema)
            .ExposeConfiguration(c => c.Properties.Add("cache.use_second_level_cache", "true"))
            .BuildConfiguration();
        }
    }
    private static bool IsConfigurationFileValid
    {
        get
        {
            var ass = Assembly.GetAssembly(typeof(EntityMap));
            var configInfo = new FileInfo(_configFile);
            var assInfo = new FileInfo(ass.Location);
            return configInfo.LastWriteTime >= assInfo.LastWriteTime;
        }
    }

    private static Configuration _configuration;
    private static string _configFile;
    private const string CacheFile = "hibernate.cfg.xml";

}
Bearbeite

Die Repository-Implementierung, die ich benutze

public class Repository<T> : IIntKeyedRepository<T> where T : class
{
    private readonly ISession _session;

    public Repository()
    {
        _session = NHibernateSessionPerRequest.GetCurrentSession();
    }

    #region IRepository<T> Members

    public bool Add(T entity)
    {
        _session.Save(entity);
        return true;
    }

    public bool Add(System.Collections.Generic.IEnumerable<T> items)
    {
        foreach (T item in items)
        {
            _session.Save(item);
        }
        return true;
    }

    public bool Update(T entity)
    {
        _session.Update(entity);
        return true;
    }

    public bool Delete(T entity)
    {
        _session.Delete(entity);
        return true;
    }

    public bool Delete(System.Collections.Generic.IEnumerable<T> entities)
    {
        foreach (T entity in entities)
        {
            _session.Delete(entity);
        }
        return true;
    }

    #endregion

    #region IIntKeyedRepository<T> Members

    public T FindBy(int id)
    {
        return _session.Get<T>(id);
    }

    #endregion

    #region IReadOnlyRepository<T> Members

    public IQueryable<T> All()
    {
        return _session.Query<T>();
    }

    public T FindBy(System.Linq.Expressions.Expression<System.Func<T, bool>> expression)
    {
        return FilterBy(expression).Single();
    }

    public IQueryable<T> FilterBy(System.Linq.Expressions.Expression<System.Func<T, bool>> expression)
    {
        return All().Where(expression).AsQueryable();
    }

    #endregion

}
Edit 2

Die Basis-Controller-Klasse, die ich verwende

public class BaseController : Controller
{
    private readonly IRepository<UserEntity> _userRepository;

    public BaseController()
    {
        _userRepository = new Repository<UserEntity>();
        BaseModel = new LayoutModel {Modals = new List<string>()};
    }

    public UserEntity LoggedUser { get; set; }
    public LayoutModel BaseModel { get; set; }

    protected override void OnActionExecuting(ActionExecutingContext ctx)
    {
        base.OnActionExecuting(ctx);

        if (HttpContext.User.Identity.IsAuthenticated)
        {
            if (Session != null && Session["User"] != null)
            {
                LoggedUser = (User) Session["User"];
            }
            var curUsername = HttpContext.User.Identity.Name;
            if (LoggedUser == null || LoggedUser.Entity2.un!= curUsername)
            {
                LoggedUser = _userRepository.FindBy(u => u.Entity2.un== curUsername);
                Session["User"] = LoggedUser;
            }
            BaseModel.LoggedUser = LoggedUser;
            BaseModel.Authenticated = true;
        }
        else
        {
            LoggedUser = new UserEntity
            {
                Entity= new Entity{un= "Guest"},
            };
            BaseModel.LoggedUser = LoggedUser;
        }
    }      
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage