I have an ASP.Net webforms app, that uses Ninject 2.2.0.0
I have a HTTPHandler that inherits from the Microsoft.Web.ImageHandler class.
Within it i need to access an instance of a service class that i created.
because i cannot inherit from Ninject.Web.HttpHandlerBase i thought i would just expose the Kernel as a property on the Global.asax class...
protected override IKernel CreateKernel()
{
IKernel kernel = new StandardKernel(new DefaultModule());
var sms = kernel.Get<SiteMapService>();
SiteMapSvc = sms;
Kernel = kernel;
return kernel;
}
public IKernel Kernel
{
get; set;
}
and use the kernel.Get method to obtain the service..
var global = (Global) HttpContext.Current.ApplicationInstance;
var service = global.Kernel.Get<PhotoService>();
This fails with the following...
[ArgumentNullException: Cannot be null
Parameter name: root]
Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:258
Ninject.ResolutionExtensions.Get(IResolutionRoot root, Type service, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:151
Thumb.GenerateImage(NameValueCollection parameters) in \Thumb.ashx.cs:40
UPDATE:
I managed to fix this by modifying the Global.Kernel property to this, but now im getting into anti pattern territory...
public IKernel Kernel
{
get { return this.CreateKernel(); }
}
Will now read up and see what this means..
This is using the Service-Locator anti-pattern. It will work, but you lose the flexibility of IoC and add a dependency everywhere that is difficult to test.
This simple answer is that you can add "KernelContainer.Inject(this)" to your HttpHandler. Or you can create a custom module (or modify the existing Ninject.Web one) to do injection before handler execution.
Related
Using Web API 2 and OWIN hosting with Ninject.
I would like to inject the current IOwinContext into certain services (so I can get at the Request to get the principal to do some data filtering).
With Web Hosting I would, in the old days, simply have used HttpContext.Current but that is not an option with OWIN hosting (and good riddance).
This SO question explains how to do it with Autofac. Essentially, you create a Dependency Scope and then, on each request, calls Autofac's Registerinstance to register the current IOwinContext into that dependency scope like so:
app.Use(async (ctx, next) =>
{
// this creates a per-request, disposable scope
using (var scope = container.BeginLifetimeScope(b =>
{
// this makes owin context resolvable in the scope
b.RegisterInstance(ctx).As<IOwinContext>();
}))
{
// this makes scope available for downstream frameworks
ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
await next();
}
});
That is very elegant. With Ninject and the Ninject.Web.WebApi.OwinHosting I already get a named scope for each request so that plumbing is taken care of. However, I haven't been able to find any way in ninject to mirror AutoFac's RegisterInstance method: The key here is that this binding is only valid within this particular dependency scope.
I have read up on the various options around Scope but everything I have found relies on being able to declare constants or ToMethod. What I am looking to do here is to say, "okay, I now have a ninject dependency scope and if anyone asks for an IOwinContext from this scope, give them this instance that I already have.
Note
I do understand that I can get the current context from within my controller and pass it on, but that rather defeats the purpose of what I am trying to do; I want my DbContext to understand who the user is so it can filter the data. And, of course, once I can get the IOwinContext I won't actually pass that to the DbContext, rather I will use a ToMethod or similar to extract the ClaimsPrincipal but that is out of scope of this question.
DISCLAIMER: This is a hack. It works, but it feels very unclean. Use at your peril.
In essence, you can create an OwinContextHolder class, bind it InRequestScope and use a DelegatingHandler to populate it on each request. Something like this:
public class OwinContextHolder
{
public IOwinContext OwinContext { get; set; }
}
public class OwinContextHolderModule : NinjectModule
{
public override void Load()
{
// Instead of a NinjectModule you can of course just register the service
this.Kernel.Bind<OwinContextHolder>().ToSelf().InRequestScope();
}
}
Your delegating handler:
public class SetOwinContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var holder = request.GetDependencyScope().GetService(typeof(OwinContextHolder)) as OwinContextHolder;
if (holder != null)
{
holder.OwinContext = request.GetOwinContext();
}
return base.SendAsync(request, cancellationToken);
}
}
Finally add the DelegatingHandler to your Startup class:
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
webApiConfiguration.Routes.MapHttpRoute(...);
webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler());
app.UseNinjectMiddleware(CreateKernel);
app.UseNinjectWebApi(webApiConfiguration);
}
You can now inject OwinContextHolder into your classes.
Note that if you have your API in a separate assembly from your host, you may have problems with InRequestScope silently not working (as in, you get a different object every time you request one and no errors). If you do, see https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8.
I'm using Castle Windsor and DynamicProxy to implement persistence Lazy Loading from scratch (I know NHibernate could be an option etc.) I have implemented a custom component activator to always instantiate my business classes as proxies. I found that the default mixin proxies automatically created when using interceptors were not being used when class methods are called from inside the class itself, which was a problem. So I inherited DefaultComponentActivator and overriding CreateInstance() I'm calling CreateClassProxy() to get a proxy that inherits from the business class, which in that respect works fine.
Now I was expecting this 'ProxyComponentActivator' activator of mine to be instantiated by Castle only once, but a new instance is being created for each class type. Is that correct?
Current registration is like this:
public void Install(
IWindsorContainer container,
Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store) {
container.Register(
Classes
.FromAssemblyContaining(typeof(OneOfMyBusinessClasses))
.InNamespace(typeof(OneOfMyBusinessClasses).Namespace)
.WithService.DefaultInterfaces()
.Configure(reg => reg.Activator<ProxyComponentActivator>())
.LifestyleTransient(),
etc.
);
);
The activator implementation is the following:
public class ProxyComponentActivator : DefaultComponentActivator
{
protected Castle.DynamicProxy.ProxyGenerator ProxyGenerator { get; set; }
protected PersistenceInterceptor PersistenceInterceptor { get; set; }
public ProxyComponentActivator(ComponentModel model, Castle.MicroKernel.IKernelInternal kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
: base(model, kernel, onCreation, onDestruction)
{
this.ProxyGenerator = kernel.Resolve<Castle.DynamicProxy.ProxyGenerator>();
this.PersistenceInterceptor = kernel.Resolve<PersistenceInterceptor>();
}
protected override object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments) //, Type[] signature)
{
object instance;
Type implType = this.Model.Implementation;
ProxyGenerationOptions p = new ProxyGenerationOptions();
IPersistent ip = new Persistent();
p.AddMixinInstance(ip);
try
{
instance = this.ProxyGenerator.CreateClassProxy(implType, null, p, arguments, this.PersistenceInterceptor);
}
catch
{
throw new ComponentActivatorException("ComponentActivator: could not proxy " + implType.FullName, Model);
}
return instance;
}
}
I have also tried to register the activator like this, to no avail...
Component.For<ProxyComponentActivator>()
.ImplementedBy<ProxyComponentActivator>()
.LifestyleSingleton()
Thanks in advance for any help,
Luis
Every component in Windsor will get its own activator instance
I have some very odd behaviour in my Windsor Container.
I have configured my container like this.
Container = new WindsorContainer();
Container.Kernel.ComponentModelCreated += KernelComponentModelCreated;
Container.Install(FromAssembly.This());
private static void KernelComponentModelCreated(ComponentModel model)
{
if (model.LifestyleType == LifestyleType.Undefined)
model.LifestyleType = LifestyleType.Transient;
}
So I was supposing all my components where I don't specify the lifestyle would get a transient lifestyle and it seemed to don't give any issues until now.
I start multiple asynchronous task which all resolve some components. (So you would expect every task gets a new instance of the component)
However now I know the tasks don't get new instances, because my tasks fail because of crossthreading issues with the component. (so it is being used in multiple tasks)
When I replace the Container.Resolve(somecomponent); With just creating the new component in place everything works like it should.
var contextProvider = MvcApplication.Container.Resolve<IDbContextProvider>();
replaced with
var contextProvider = new DbContextProvider();
So my question is what am I missing here.
The tasks are started in transient configured MVC3 controllers, because of explicitly configured.
The DbContextProvider is resolved in all repositories also configured transient, because of above code.
Another thing I found in the documentation is. You have to release transient components. I implemented all components with IDisposable. But because of auto contructor injection in my controllers I am not completely sure if I have to release them manually and if so how can I do this. (Yes I know I have to call the Release method on the container)
UPDATE
Code below is responsible for releasing and resolving my controllers:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)_kernel.Resolve(controllerType);
}
}
Is there some example available for testing if all dependencies are resolved and released the way they should be? (LifeStyle tests)
I'm not sure if this is what is causing your issues, but you should modify ComponentModel in an implementation of IContributeComponentModelConstruction only.
Check out the documentation of the component model construction contributors for help on how to effectively change the default lifestyle of the container.
Regarding disposal of IDisposables - if you release your controller like you should everything will just work with Windsor :)
Where is the recommended place to perform property injection into action filter attributes in an ASP.NET web api project? In MVC 3 land, we could set our own implementation for ControllerActionInvoker at the point of resolving our controllers from our IoC container, and override its GetFilters() method to inject components resolved from the container.
Is there a similar place to do this in an ASP.NET Web API project? I have a controller factory that resolves controllers from the container, with the CreateController method as so:
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
var controller = _kernel.Resolve<IHttpController>(controllerName);
controllerContext.Controller = controller;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(_configuration, controllerName, controller.GetType());
return controllerContext.Controller;
}
I've had a look at HttpControllerDescriptor to see if there is somewhere to do the injection, but I can't see a suitable place. Any pointers in the right direction?
You need to implement IHttpControllerSelector and register your selector in the (Services property) DefaultServices of the HttpConfiguration.
Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.
You need to Implement your own IFilterProvider. Have a look at the source for ActionDescriptorFilterProvider. This is where you can inject properties.
Here is ActionDescriptorFilterProvider implementation:
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
if (actionDescriptor == null)
{
throw Error.ArgumentNull("actionDescriptor");
}
IEnumerable<FilterInfo> controllerFilters = actionDescriptor.ControllerDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Controller));
IEnumerable<FilterInfo> actionFilters = actionDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Action));
return controllerFilters.Concat(actionFilters);
}
All you have to do is to use instance lambda parameter and inject properties.
Registration As you have figured out, the filter provider needs to be registered against the HttpConfiguration. Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.
I am fairly new to Ninject as well and DI in general. I use NHibernate as my ORM for my MVC app and have been quite happy with my results. That is, until I upgraded from Ninject 2.1 to 2.2.
Now, I get errors within my NinjectWebsiteApplication class due to using Ninject’s Kernel as a resource locator.
Example:
void NinjectWebsiteApplication_BeginRequest(object sender, System.EventArgs e)
{
ILogger logger = Kernel.Get<ILogger>();
logger.Debug(“**********REQUEST BEGIN****************”);
logger.Debug(“**** URL = ” + Request.Url.AbsolutePath);
}
Example 2:
protected override void OnApplicationStarted()
{
var bootstrapper = Kernel.Get<Bootstrapper>();
bootstrapper.RegisterAllAreas();
AreaRegistration.RegisterAllAreas();
......
(More stuff here, like AutoMapper mappings, etc.)
......
}
*The Bootstrapper class is a class I created where I register my routes, global filters, etc.
In both of the above examples, I receive a warning about the Kernel.Get() functions that states the following:
'Ninject.Web.Mvc.NinjectHttpApplication.Kernel' is obsolete: "Do not use Ninject as Service Locator"
After conducting several searches on this, the general consensus is that this is true.
I am trying to work around this, but am at a bit of a loss as to what to do.
I loaded the newest Ninject.Web.Mvc NuGet package which creates the NinjectMVC3 static class under the App_Start folder. I see that they're referencing Microsoft.Web.Infrastructure.DynamicModuleHelper, but I don't see where that fits in to what I'm trying to do.
If anyone has any hints that will help me fix my little mess, I would greatly appreciate it!
The way to deal with the first is not to use the NinjectWebsiteApplication_BeginRequest event but to write a custom global action filter:
public class LogActionFilterAttribute : ActionFilterAttribute
{
private readonly ILogger _logger;
public LogActionFilterAttribute(ILogger logger)
{
_logger = logger;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_logger.Debug("**********REQUEST BEGIN****************");
_logger.Debug("**** URL = " + filterContext.HttpContext.Request.Url.AbsolutePath);
}
}
and then in your App_Start/NinjectMVC3.cs:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<Logger>();
kernel.BindFilter<LogActionFilterAttribute>(FilterScope.Global, 1);
}
Don't forget to add using Ninject.Web.Mvc.FilterBindingSyntax; in order to bring the BindFilter<> extension method into scope.
And since you have access to the kernel inside the RegisterServices method which happens at application startup you could wire up everything else including your bootstrapper, ...
As far as your Global.asax is concerned you no longer use any Ninject specific stuff in it. You should not derive from NinjectApplication.
The WebActivator infrastructure allows you to have a separate initialization method.