I have a repository that needs to be created per request. Now there is a singleton caching object that needs to use that repository to fill itself with data, but this object is initialized in the Application_Start event, therefore there is not request context.

Which would be the best way of accomplish this with Ninject?

Thanks.

有帮助吗?

解决方案

As current HttpContext is missing on app startup (in IIS7 integration mode) Ninject will definitely treat object binded InRequestScope as it would be in InTransientScope when you try to inject dependency on app startup. As we can see in Ninject's (2.2) source code:

/// <summary>
/// Scope callbacks for standard scopes.
/// </summary>
public class StandardScopeCallbacks
{
    /// <summary>
    /// Gets the callback for transient scope.
    /// </summary>
    public static readonly Func<IContext, object> Transient = ctx => null;

    #if !NO_WEB
    /// <summary>
    /// Gets the callback for request scope.
    /// </summary>
    public static readonly Func<IContext, object> Request = ctx => HttpContext.Current;
    #endif
}

HttpContext.Current will be null at app startup, so the InRequestScope binded object will be treated on app startup the same way as it would be binded InTransientScope.

So you can have in your global.asax:

protected override Ninject.IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Bind<RequestScopeObject>().ToSelf().InRequestScope();
    kernel.Bind<SingletonScopeObject>().ToSelf().InSingletonScope();
    return kernel;
}

protected override void OnApplicationStarted()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    // init cache
    this.Kernel.Get<SingletonScopeObject>().Init();
}

But you will have to do cleanup after use of RequestScopeObject (e.g. Dispose() it, if it implements IDisposable).

public class SingletonScopeObject
{
    private string cache;
    private RequestScopeObject requestScopeObject;
    public SingletonScopeObject(RequestScopeObject requestScopeObject)
    {
        this.requestScopeObject = requestScopeObject;
    }

    public void Init()
    {
        cache = this.requestScopeObject.GetData();
        // do cleanup
        this.requestScopeObject.Dispose();
        this.requestScopeObject = null;
    }

    public string GetCache()
    {
        return cache;
    }
}

Another approach

Bind your RequestScopeObject both InRequestScope and InSingletonScope utilizing the conditional binding like this:

kernel.Bind<SingletonScopeObject>()
      .ToSelf()
      .InSingletonScope()
      .Named("singletonCache");
// as singleton for initialization
kernel.Bind<RequestScopeObject>()
      .ToSelf()
      .WhenParentNamed("singletonCache")
      .InSingletonScope();
// per request scope binding
kernel.Bind<RequestScopeObject>()
      .ToSelf()
      .InRequestScope();

The cleanup after initialization remains the same.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top