How to use Ninject to inject services into MVC 3 FilterAttributes? - asp.net-mvc-3

I'm writing a custom ErrorHandler attribute for my MVC project. I would like to inject an implementation of EventViewerLogger into that attribute.
I'm using Ninject 2.2 and it works fine for other features, such as injection repositories and aggregate services through controller constructors.
I understand that I can't inject an implementation of some class into attribute through constructor, therefore I have to inject it into the attribute's property.
Interface is below:
namespace Foo.WebUI.Infrastructure
{
public interface ILogger
{
void Log(Exception e);
}
}
Event viewer logger implementation
namespace Foo.WebUI.Infrastructure
{
/// <summary>
/// Logs exceptions into the Windows Event Viewer
/// </summary>
public class EventViewerLogger: ILogger
{
private EventViewerLogger _logger = null;
EventViewerLogger()
{
_logger = new EventViewerLogger();
}
public void Log(Exception e)
{
_logger.Log(e);
}
}
}
Below is code for error handler:
namespace Foo.WebUI.Handlers
{
/// <summary>
/// Custom error handler with an interface to log exceptions
/// </summary>
public class CustomHandleErrorAttribute: HandleErrorAttribute
{
[Inject]
public ILogger Logger { get; set; }
// Default constructor
public CustomHandleErrorAttribute():base() { }
public override void OnException(ExceptionContext filterContext)
{
Logger.Log(filterContext.Exception);
base.OnException(filterContext);
}
}
}
In global.asax I register the handler and Ninject.
protected void Application_Start()
{
IKernel kernel = new StandardKernel(new NinjectInfrastructureModule());
}
Finally, I have a custom filter provider
namespace Foo.WebUI.Infrastructure
{
public class NinjectFilterProvider: FilterAttributeFilterProvider
{
private readonly IKernel kernel;
public NinjectFilterProvider(IKernel kernel)
{
this.kernel = kernel;
}
public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(controllerContext, actionDescriptor);
// Iterate through all the filters and use Ninject kernel to serve concrete implementations
foreach (var filter in filters)
{
kernel.Inject(filter.Instance);
}
return filters;
}
}
}
When I start the application I get the following exception:
Activation path:
2) Injection of dependency ILogger into property Logger of type CustomHandleErrorAttribute
1) Request for CustomHandleErrorAttribute
Suggestions:
1) Ensure that the implementation type has a public constructor.
2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
Source Error:
Line 27: foreach (var filter in filters)
Line 28: {
Line 29: kernel.Inject(filter.Instance);
Line 30: }
Spent a day on this, learnt a lot about dependecy injection which is great, but what am I doing wrong here?

Ninject.Web.Mvc has this functionality built in called "BindFilter" which lets you map an attribute (that takes some or no constructor args) to a filter (which has its constructor args injected). Additionally, you can use it to copy values from the attribute and inject them as constructor args to the filter if you want. It also lets you change scope on your filters to be per action or per controller etc so that they actually get re-instantiated (normal action filters don't get re-instantiated per request).
Here's an example of how I've used it to do a UoW action filter.

Related

MVC: Invoking overloaded constructors conditionally

I have an MVC application where I am implementing CQRS where I have seperated saving data from reading data into seperate interfaces. I am using constructor injection for injecting the concrete instances of these interfaces into the Controller. For constructor injection I am using Unity container. See below example
//The Employee controller
public class EmployeeController : Controller
{
IEmployeeRepository _Writer;
IEmployeeQuery _Reader;
//constructor injection
public EmployeeController(IEmployeeRepository writer, IEmployeeQuery reader)
{
this._Writer = writer;
this._Reader = reader;
}
//To Do: constructor injection for write operations only
public EmployeeController(IEmployeeRepository writer)
{
this._Writer = writer;
}
//To Do: constructor injection for read operations only
public EmployeeController(IEmployeeQuery reader)
{
this._Reader = reader;
}
}
//Registration of the concrete types in the unity container.
public static class Bootstrapper
{
public static void ConfigureUnityContainer()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IEmployeeRepository, EmployeeRepository>(new HttpContextLifetimeManager<IEmployeeRepository>());
container.RegisterType<IEmployeeQuery, EmployeeQueries>(new HttpContextLifetimeManager<IEmployeeQuery>());
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
}
}
//The derived Controller Factory for injection dependencies in the Controller constructor
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
{
throw new ArgumentNullException("controllerType");
}
if (!typeof(IController).IsAssignableFrom(controllerType))
{
throw new ArgumentException(String.Format("Type requested is not a controller: {0}", controllerType.Name), "controllerType");
}
return container.Resolve(controllerType) as IController;
}
catch (Exception)
{
return null;
}
}
}
I have figured out that for any action I will either be fetching data or writing data but not both. In that case I need to invoke the controller constructors conditionally depending on which of "_Writer" or "_Reader" I need to initialize.
How can this be done ?
Looks like you have one controller where you should use two? If you never need to be able to both read and write I would consider to refactor that component towards single responsibility.
If you don't want to do that I would consider injecting a NullObject instead of not injecting that dependency at all. See this thread.
The TecX project contains an extension that mimics NInject's contextual binding. That would allow you to specify when to inject what dependency. The code can be found inside the TecX.Unity project (folder ContextualBinding). The tests that show how to use it are inside the TecX.Unity.ContextualBinding.Test project).
What about lazy loading components? You resolve both dependencies but only one that is really used is initialized.
Sample here: http://pwlodek.blogspot.com/2010/05/lazy-and-ienumerable-support-comes-to.html

How do I inject into some generic asp.net http handler using Ninject?

I'm a newbie using Ninject and I can't figure out how to inject into my generic http handler. I have a MVC3 project and I'm injecting my services into controllers with no problem at all.
This is what I got in my Ninject App_start class for registering services:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<NLSubscriber.Core.Service.Repository.INLUserRepository>().To<NLSubscriber.Core.Service.Repository.EFDAL.EFNLUserRepository>().InRequestScope();
kernel.Bind<Neticon.Mvc.Helpers.IConfigHelper>().To<Neticon.Mvc.Helpers.AzureEnabledConfigHelper>().InSingletonScope();
kernel.Bind<Neticon.Security.Service.IAuthenticationService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateAuthenticationService()).InRequestScope();
kernel.Bind<Neticon.Security.Service.IMembershipService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateMembershipService()).InRequestScope();
kernel.Bind<Neticon.Security.Service.IRoleManagerService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateRoleManagerService()).InRequestScope();
When I try to get some service from my generic handler by using property injection (with [inject] attribute) I always get null. This is how my handler looks like:
public class SubscriberHandler : IHttpHandler
{
[Inject]
public INLUserRepository userRep { get; set;}
public void ProcessRequest(HttpContext context)
{
var users = userRep.GetUsers(); //userRep is always null here
}
public bool IsReusable
{
get
{
return false;
}
}
}
I have also tried doing it like this:
readonly INLUserRepository userRep;
public SubscriberHandler()
{
using (IKernel kernel = new StandardKernel(new App_Start.NJRepositoryModule()))
{
userRep = kernel.Get<INLUserRepository>();
}
}
but I'm getting an exception: "Error loading Ninject component ICache. No such component has been registered in the kernel's component container.
Suggestions:
1) If you have created a custom subclass for KernelBase, ensure that you have properly
implemented the AddComponents() method.
2) Ensure that you have not removed the component from the container via a call to RemoveAll().
3) Ensure you have not accidentally created more than one kernel."
That's suggesting me that I'm not supposed to instantiate more than one kernel in my application, right?
What am I doing wrong?
Thanks
You could use the dependency resolver:
public class SubscriberHandler : IHttpHandler
{
public INLUserRepository userRep { get; private set; }
public SubscriberHandler()
{
userRep = DependencyResolver.Current.GetService<INLUserRepository>();
}
public void ProcessRequest(HttpContext context)
{
var users = userRep.GetUsers(); //userRep is always null here
}
public bool IsReusable
{
get
{
return false;
}
}
}
I am expecting to get negative feedback from this answer because the service locator pattern is considered by many as an anti-pattern.
But I am not sure whether NInject allows you to use constructor injection for HTTP handlers because they are instantiated by the ASP.NET runtime.
The composition root for IHttpHandlers is the IHttpHandlerFactory. You can create a custom IHttpHandlerFactory that uses Ninject to create an instance of your IHttpHandler. That way you can use constructor injection.
I see you have a "RegisterServices" method in your snippet which suggests you're already using Ninject.Web.Common. What you might not know about NinjectWebCommon.cs is it uses a Bootstrapper class which contains a singleton instance of the Ninject kernel.
As Remo mentioned above, IHttpHandlerFactory is the composition root for IHttpHandler instances and as such you will need to create an implementation of this interface and add the necessary configuration elements to your web.config.
MyHandlerFactory.cs:
public class MyHandlerFactory : IHttpHandlerFactory
{
public bool IsReusable => false;
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
// the bootstrapper class uses the singleton pattern to share the Ninject Kernel across your web app's ApplicationDomain
var kernel = new Bootstrapper().Kernel;
// assuming you have only one IHttpHandler binding in your NinjectWebCommon.cs
return kernel.Get<IHttpHandler>();
}
public void ReleaseHandler(IHttpHandler handler)
{
// nothing to release
}
}
Now, add the necessary config elements for your new handler factory...
Web.config:
<system.web>
<httpHandlers>
<add verb="GET" path="*.customThingImade" type="MyNamespace.MyHandlerFactory, MyAssemblyWhereIPutMyHandlerFactory, Version=1.0.0.0, Culture=neutral" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="MyHandlerFactory" verb="GET" path="*.customThingImade" type="MyNamespace.MyHandlerFactory, MyAssemblyWhereIPutMyHandlerFactory, Version=1.0.0.0, Culture=neutral" preCondition="integratedMode" />
</handlers>
</system.webServer>
Finally, add a binding for your IHttpHandler implementation...
NinjectWebCommon.cs:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<NLSubscriber.Core.Service.Repository.INLUserRepository>().To<NLSubscriber.Core.Service.Repository.EFDAL.EFNLUserRepository>().InRequestScope();
kernel.Bind<Neticon.Mvc.Helpers.IConfigHelper>().To<Neticon.Mvc.Helpers.AzureEnabledConfigHelper>().InSingletonScope();
kernel.Bind<Neticon.Security.Service.IAuthenticationService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateAuthenticationService()).InRequestScope();
kernel.Bind<Neticon.Security.Service.IMembershipService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateMembershipService()).InRequestScope();
kernel.Bind<Neticon.Security.Service.IRoleManagerService>().ToMethod(m => Neticon.Security.Service.SecurityServiceFactory.CreateRoleManagerService()).InRequestScope();
// the binding for your handler factory
Bind<IHttpHandler>().To<SubscriberHandler>();
}

ASP.NET Web API Ninject constructor injected custom filter and attributes

I'm struggling with getting a custom attribute / filter working with ninject, constructor injection on the ASP.NET Web API.
Here's a few snippets to give some context...
//controller
[ApiAuthorise]
public IEnumerable<Thing> Get()
// Attribute definition with no body
public class ApiAuthoriseAttribute : FilterAttribute {}
// Custom Filter definition
public class ApiAuthoriseFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{ throw new NotImplementedException(); }
}
//Ninject module for my API authorisation
public class ApiAuthoriseModule : NinjectModule
{
public override void Load()
{
this.BindFilter<ApiAuthoriseFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<ApiAuthoriseAttribute>()
}}
//The registerServices(IKernel kernel) method in NinjectMVC3.cs
kernel.Load(new ApiAuthoriseModule());
That's literally all the code I have concerning this filter and attribute.
From what I understand I don't have to explicitly add the filter to the global filter collection as ninject takes care of that, is that correct?
If I place a constructor inside my attribute and throw an exception from within there I can see that the attribute is firing.
My suspicion is something I'm doing wrong within the Ninject side of things but after spending an afternoon reading others examples that appear to be identical to mine I'm know asking for help :)
TIA
There are different classes that you need to work with in Web API, not the standard System.Web.Mvc.FilterAttribute and System.Web.Mvc.IAuthorizationFilter that are used in normal controllers:
public class ApiAuthoriseAttribute : System.Web.Http.Filters.FilterAttribute
{
}
public class ApiAuthoriseFilter : System.Web.Http.Filters.IAuthorizationFilter
{
public System.Threading.Tasks.Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<System.Threading.Tasks.Task<HttpResponseMessage>> continuation)
{
throw new NotImplementedException();
}
public bool AllowMultiple
{
get { return false; }
}
}
Then you will obviously have to modify Ninject and the filter binding syntax (BindFilter extension method) to be able to register this new classes. Or wait for Ninject.MVC4 which will include this functionality.

Accessing ninject kernel in Application_Start

I am using Ninject and the MVC3 extension installed with nuget. My kernel setup code is in the App_Start/NinjectMVC3.cs file. Everything works great in controllers, but I can't figure out how to (properly) bind interfaces in the Global.asax.cs MvcApplication code.
I ended up using a hack (creating a public NinjectMVC3.GetKernel() method that returns bootstrap.kernel). However, that will be deprecated, and there must be a proper way to do this that I am not seeing.
Here is my code:
public class LogFilterAttribute : ActionFilterAttribute
{
private IReportingService ReportingService { get; set; }
public LogFilterAttribute( IReportingService reportingService )
{
this.ReportingService = reportingService;
}
...
}
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters( GlobalFilterCollection filters )
{
filters.Add( new HandleErrorAttribute() );
filters.Add( new LogFilterAttribute() );
}
...
protected void Application_Start()
{
...
RegisterGlobalFilters( GlobalFilters.Filters );
// NOTE hack:
var kernel = NinjectMVC3.GetKernel();
var logger = kernel.Get<ILogger>();
var bw = new BackgroundWork(logger);
Application["BackgroundWork"] = bw;
bw.Start();
}
}
There are two interfaces I am interested in. The first is just binding an object to a Global variable (the ILogger for the BackgroundWork).
And the second is for an ActionFilter. I read http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/, but I don't see how it plugs into the actual registration (filter.Add).
I don't want to use the Property Inject if I can avoid it.
Any thoughts on the proper way to do this?
Thanks
MVC 3 introduces the DependencyResolver which is populated into a singleton, and the Ninject extension supports it. You could use that in your MvcApplication class if you need it:
protected void Application_Start()
{
// ...
var logger = DependencyResolver.Current.GetService<ILogger>();
}
Now I should point out that it is unnecessary to do this with action filters. In Ninject.MVC3 you are supposed to use the BindFilter syntax, like so:
// Declare empty attribute
public class MyFilterAttribute : FilterAttribute { }
// Dependency module
public class MyModule : NinjectModule
{
public override void Load()
{
// Other bindings
// ...
this.BindFilter<MyActionFilter>(FilterScope.Action, 1)
.WhenControllerHas<MyFilterAttribute>();
}
}
Note that you have to use this because BindFilter is an extension method, and you also have to reference the Ninject.Web.Mvc.FilterBindingSyntax namespace.

Issues with my MVC repository pattern and StructureMap

I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:
IEntityRepository where TEntity : class
Defines basic CRUD members
MyEntityRepository : IEntityRepository
Implements CRUD members
IEntityService where TEntity : class
Defines CRUD members which return common types for each member.
MyEntityService : IEntityService
Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)
The problem appears to be with my Service layer. More specifically with the constructors.
public PostService(IValidationDictionary validationDictionary)
: this(validationDictionary, new PostRepository())
{ }
public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.
This is what the controller constructors look like (the first one creates an instance of the validation object):
public PostController()
{
_service = new PostService(new ModelStateWrapper(this.ModelState));
}
public PostController(IEntityService<Post> service)
{
_service = service;
}
Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.
I appreciate any help with this :) Thanks.
It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.
I had to rewrite my validation layer to get this to work. Here is what i did.
Define generic validator interface like below:
public interface IValidator<TEntity>
{
ValidationState Validate(TEntity entity);
}
We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.
public class ValidationState
{
private readonly ValidationErrorCollection _errors;
public ValidationErrorCollection Errors
{
get
{
return _errors;
}
}
public bool IsValid
{
get
{
return Errors.Count == 0;
}
}
public ValidationState()
{
_errors = new ValidationErrorCollection();
}
}
Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.
public class ValidationErrorCollection : Collection<ValidationError>
{
public void Add(string property, string message)
{
Add(new ValidationError(property, message));
}
}
And here is what the ValidationError looks like:
public class ValidationError
{
private string _property;
private string _message;
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
public string Message
{
get
{
return _message;
}
private set
{
_message = value;
}
}
public ValidationError(string property, string message)
{
Property = property;
Message = message;
}
}
The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:
public interface IValidationService
{
ValidationState Validate<TEntity>(TEntity entity);
}
And we finally implement it:
public class ValidationService : IValidationService
{
#region IValidationService Members
public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
{
return ObjectFactory.GetInstance<IValidator<TEntity>>();
}
public ValidationState Validate<TEntity>(TEntity entity)
{
IValidator<TEntity> validator = GetValidatorFor(entity);
if (validator == null)
{
throw new Exception("Cannot locate validator");
}
return validator.Validate(entity);
}
#endregion
}
I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:
public class PostController : Controller
{
private IEntityService<Post> _service = null;
private IValidationService _validationService = null;
public PostController(IEntityService<Post> service, IValidationService validationService)
{
_service = service;
_validationService = validationService;
}
}
Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:
ForRequestedType<IValidationService>()
.TheDefaultIsConcreteType<ValidationService>();
ForRequestedType<IValidator<Post>>()
.TheDefaultIsConcreteType<PostValidator>();
That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "PostId")] Post post)
{
ValidationState vst = _validationService.Validate<Post>(post);
if (!vst.IsValid)
{
foreach (ValidationError error in vst.Errors)
{
this.ModelState.AddModelError(error.Property, error.Message);
}
return View(post);
}
...
}
Hope i helped somebody out with this :)
I used a similar solution involving a generic implementor of IValidationDictionary uses a StringDictionary and then copied the errors from this back into the model state in the controller.
Interface for validationdictionary
public interface IValidationDictionary
{
bool IsValid{get;}
void AddError(string Key, string errorMessage);
StringDictionary errors { get; }
}
Implementation of validation dictionary with no reference to model state or anything else so structuremap can create it easily
public class ValidationDictionary : IValidationDictionary
{
private StringDictionary _errors = new StringDictionary();
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_errors.Add(key, errorMessage);
}
public bool IsValid
{
get { return (_errors.Count == 0); }
}
public StringDictionary errors
{
get { return _errors; }
}
#endregion
}
Code in the controller to copy the errors from the dictionary into the model state. This would probably be best as an extension function of Controller.
protected void copyValidationDictionaryToModelState()
{
// this copies the errors into viewstate
foreach (DictionaryEntry error in _service.validationdictionary.errors)
{
ModelState.AddModelError((string)error.Key, (string)error.Value);
}
}
thus bootstrapping code is like this
public static void BootstrapStructureMap()
{
// Initialize the static ObjectFactory container
ObjectFactory.Initialize(x =>
{
x.For<IContactRepository>().Use<EntityContactManagerRepository>();
x.For<IValidationDictionary>().Use<ValidationDictionary>();
x.For<IContactManagerService>().Use<ContactManagerService>();
});
}
and code to create controllers is like this
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Just a quick query on this. It's helped me out quite a lot so thanks for putting the answer up, but I wondered which namespace TEntity exists in? I see Colletion(TEntity) needs System.Collections.ObjectModel. My file compiles without anything further but I see your TEntity reference highlighted in Blue which suggests it has a class type, mine is Black in Visual Studio. Hope you can help. I'm pretty keen to get this working.
Have you found any way to seperate validation into the service layer at all? My gut tells me that validating in the Controller is a bit smelly but I've looked high and low to find a way to pass validation error messages back to the controller without tightly coupling the service layer to the controller and can't find anything. :(
Again, thanks for the great post!
Lloyd

Resources