2

I use Ninject:

public static class NinjectWebCommon
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start()
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        var resolver = new NinjectSignalRDependencyResolver(kernel);
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(kernel);

            RegisterServices(kernel);

            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<TMS.Entities.AssetContext>().ToSelf().InRequestScope();
        kernel.Bind<TMS.Data.IDbContext>().To<TMS.Entities.AssetContext>().InRequestScope();
        kernel.Bind(typeof(TMS.Data.IRepository<>)).To(typeof(TMS.Data.EfRepository<>));

        kernel.Bind<IExportManager>().To<ExportManager>().InRequestScope();
        kernel.Bind<IDriverService>().To<Services.Drivers.DriverService>().InRequestScope();
        .....
    }
}

It works fine for Mvc and Api controller. But right now I'm writing ActionFilter:

public class AccessLoadApiAttribute : ActionFilterAttribute
{
    public AccessLoadApiAttribute()
    {

    }

    private readonly ILoadServiceEntity _loadServiceEntity;
    public AccessLoadApiAttribute(ILoadServiceEntity loadServiceEntity)
    {
        _loadServiceEntity = loadServiceEntity ?? throw new ArgumentNullException(nameof(loadServiceEntity));
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var loadId = Convert.ToInt32(actionContext.RequestContext.RouteData.Values["Id"]);
        _loadServiceEntity.GetLoadById(loadId);

        base.OnActionExecuting(actionContext);
    }
}

and _loadServiceEntity is null. What is wrong in configuring?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Oleg Sh
  • 8,496
  • 17
  • 89
  • 159
  • Why do you need zero argument constructor for `AccessLoadApiAttribute`, also can you show the binding for the `ILoadServiceEntity`, also Dependency injection happens when ASP.Net as a host injects in a class – Mrinal Kamboj Sep 12 '18 at 12:31
  • @MrinalKamboj I need because I can't use it `[AccessLoadApi]` without parameters – Oleg Sh Sep 12 '18 at 12:41
  • 1
    In the `WebApiConfig.cs` or `Ninject.Web.Common.cs` can you explicitly add the action filter using a code similar to `GlobalConfiguration.Configuration.Filters.Add(new AccessLoadApiAttribute())`, here you can even specify which constructor to call and what binding shall fill in the `ILoadServiceEntity` – Mrinal Kamboj Sep 12 '18 at 12:43

1 Answers1

3

In Asp.Net Web API 2.x, Attributes do not allow dependency injection via constructor if you want to use them on individual actions.

You would have to use the service locator anti pattern via the IDependencyResolver which can be accessed via the HttpConfiguration

For example

public class AccessLoadApiAttribute : ActionFilterAttribute {

    public override void OnActionExecuting(HttpActionContext actionContext) {
        //get the resolver via the request context
        var resolver = actionContext.RequestContext.Configuration.DependencyResolver;
        //use resolver to get dependency
        ILoadServiceEntity _loadServiceEntity = (ILoadServiceEntity)resolver.GetService(typeof(ILoadServiceEntity));
        var loadId = Convert.ToInt32(actionContext.RequestContext.RouteData.Values["Id"]);
        _loadServiceEntity.GetLoadById(loadId);
        base.OnActionExecuting(actionContext);
    }
}

The attribute can now be used as needed

[AccessLoadApi]
[HttpGet]
public IHttpActionResult SomeGetAction() {
    return Ok();    
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Isn't the similar injection suggested in solution by you [here](https://stackoverflow.com/questions/36109052/inject-service-into-action-filter/36109690) – Mrinal Kamboj Sep 12 '18 at 12:58
  • @MrinalKamboj that is for asp.net-core. The framework was completely rewritten to improve on the short comings of the previous version. `GlobalConfiguration.Configuration.DependencyResolver` is from asp.net-web-api-2 – Nkosi Sep 12 '18 at 13:00