Ninject Contextual Binding on MVC Request

2019-07-01 10:34发布

I have an unusual situation injecting a service into an ASP.NET MVC Controller. The Controller provides a single action to render a side-bar menu on the page, and the service injected into the Controller is a factory to create the side-bar content. The action is decorated with the [ChildActionOnly] attribute: the side bar can only be rendered when rendering another action.

The difficulty comes in that I want to inject different instances of the side-bar factory abstraction according to the page (= Controller) being requested. Previously, I was doing this using a sort-of abstract factory, which had the inelegant implementation of using the controller name string to determine which concrete factory implementation to use; I've now moved this to a proper abstract factory, and thus need to move the selection of the factory type elsewhere.

My Ninject bindings are currently defined very simply as:

Kernel.Bind<ISideBarFactory>().To<FooSideBarFactory>().InRequestScope();
Kernel.Bind<ISideBarFactory>().To<DefaultSideBarFactory>().InRequestScope();

and as I add more controllers, I will add more instances of the first line. The way I would like to see this working is:

  • /foo/action request received
    • Ninject binds ISideBarFactory to FooSideBarFactory and injects into SideBarController
  • /bar/action request received
    • Ninject binds ISideBarFactory to BarSideBarFactory and injects into SideBarController
  • /baz/action request received
    • No BazSideBarFactory exists, so Ninject binds ISideBarFactory to the default implementation, DefaultSideBarFactory, and injects into SideBarController

I've consulted the Ninject wiki page on Contextual Binding, which appears to be what I want in principle, but I haven't found anything documented there which obviously achieves my goal.

1条回答
成全新的幸福
2楼-- · 2019-07-01 11:22

You can combine reading the route data with Contextual-Binding

Binding

// default binding - used if none of the conditions is met
kernel.Bind<IService>()
    .To<DefaultService>()

kernel.Bind<IService>()
    .To<BasicService>()
    .When(x=> IsRouteValueDefined("controller", "Service"));

kernel.Bind<IService>()
    .To<ExtraService>()
    .When(x=> IsRouteValueDefined("controller", "ExtraService"));

IsRouteValueDefined() method

Returns true when route key is defined and specified routeValue equals route value for route key or is null.

public static bool IsRouteValueDefined(string routeKey, string routeValue)
{
    var mvcHanlder = (MvcHandler)HttpContext.Current.Handler;
    var routeValues = mvcHanlder.RequestContext.RouteData.Values;
    var containsRouteKey = routeValues.ContainsKey(routeKey);
    if (routeValue == null)
        return containsRouteKey;
    return containsRouteKey && routeValues[routeKey].ToString().ToUpper() == routeValue.ToUpper();
}
查看更多
登录 后发表回答