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.