Question

Update: I think is down to a Windsor configuration, does any one have any idea as to what I have not configured correctly with Windsor?

I am currently using Envers within a C# WebApi project. Windsor is used for IoC. I have a custom RevisionEntity which add a User property to audit the user who has made the data change.

To ensure all configurations were correct I started off with a "simple string here" being added in the NewRevision method;

public class AuditRevisionListener : IRevisionListener
{
    public void NewRevision(object revisionEntity)
    {
        ((AuditRevision)revisionEntity).User = "Simple string here";
    }
}

and all persisted as expected.

Next step is to achieve a full User object to which I need to obtain the UserService;

public class AuditRevisionListener : IRevisionListener
{
    public void NewRevision(object revisionEntity)
    {
        var userServices = (IUserServices)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUserServices));
        var user = userServices.GetRequestingUser();

        ((AuditRevision)revisionEntity).User = user;
    }
}

However, the DependencyResolver.GetService is throwing the error; "Cannot access a disposed object. Object name: 'Scope cache was already disposed. This is most likely a bug in the calling code.'. "

UPDATE I have now created a demo project available at https://github.com/ScottFindlater/WindsorEnversIssue

On first setting up the solution all will run fine because the custom Envers RevisionListener is not performing any dependency resolving.

Run the solution which performs a GET to the HomeController, which simply loads one User and modifies another;

  • Dependency resolving is shown to be working as there is an ActionFilter called DependencyResolverDoesWork which successfully resolves the UserServices.
  • Envers is shown to be working as the UserAudit table is populated.

To “turn on” the dependency resolving in the customer RevisionListener navigate to; Domain NHibernate project, Auditing folder, AuditRevisionListener class, NewRevision method and uncomment the 2 lines of code.

Full rebuild and then run the solution again and the project will run time exception in the WindsorDependencyResolver class, GetService method with “Cannot access a disposed object”, and clicking the View Detail Action expands this message to “{"Cannot access a disposed object.\r\nObject name: 'Scope cache was already disposed. This is most likely a bug in the calling code.'."}”.

The comment posted by Roger, thank you so much, which suggests changing the LifeStyle to Singleton does work. However, this demo has been purposefully kept simple and the use of PerWebRequest LifeStyle is needed because the ApplicationServices in the real project has contextual related data injected such as requesting user which is used to enforce security.

I am so stuck now and any pointers/ answers as to what I have setup wrong will be gratefully received. In addition, I know this has been posted at SO and Envers forum, I WILL update an answer on both.

I think is down to a Windsor configuration, does any one have any idea as to what I have not configured correctly with Windsor?

Was it helpful?

Solution

I haven't tried to run your sample, but I think this is down to an interplay between the two http modules defined in your web.config (https://github.com/ScottFindlater/WindsorEnversIssue/blob/master/API%20Endpoints/Web.config)

  • Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule - Controls the lifetime of "per web request" components

  • APIEndpoints.HttpModules.NHibernateSessionCoordinator - Opens a session and begins a transaction at the beginning of each web request, then commits the transaction and disposes the session at the end of the web request

It is at the point where you commit your transaction - at the end of the request, triggered by NHibernateSessionCoordinator, that any changes you've made to objects within your NHibernate ISession actually get written to the database. This is the point at which Envers does its stuff and, in turn, at which you attempt to resolve IUserService from your Windsor container. The exception is thrown because IUserService is registered with the "per web request" lifestyle and Windsor is treating the current web request as complete and has disposed any objects tied to the request.

Have you tried reversing the order in which the HttpModules are defined, e.g. NHibernateSessionCoordinator before PerWebRequestLifestyleModule? This will result in your NHibernate transaction being committed before per web request components are disposed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top