Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you Inject into a web api IHttpRouteConstraint?

As the title states, i need to be able to inject a service into a web api constraint class. I am using SimpleInjector in my c# webApi project.

In my webApiConfig.cs i have this

// add constraint resolvers
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("dynamicName", typeof(DynamicRouteConstraint));

// routing
config.MapHttpAttributeRoutes(constraintResolver);

My custom contraint looks like this

public class DynamicRouteConstraint : IHttpRouteConstraint
{
    private IDynamicRouteService _service;

    public DynamicRouteConstraint(IDynamicRouteService service)
    {
        _service = service;
    }

    public bool Match(System.Net.Http.HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        return _service.Match(values[parameterName].ToString());
    }
}

As you can see, i need to inject the IDynamicRouteService into my constraint. Currently my application is throwing an error saying

No parameterless constructor defined for this object.

But i do not want a parameterless constructor as i need the service injected.

I have already added this line into my SimpleInjectorConfig file, where i register all my classes to inject

container.RegisterWebApiRequest<IDynamicRouteService, DynamicRouteService>();

And i have created the actual service which implements the interface, here it is (cut down version)

public class DynamicRouteService : IDynamicRouteService
{
    private IModuleService _service;

    public DynamicRouteService(IModuleService service)
    {
        _service = service;
    }

    public ICollection<DynamicRouteModel> GetRoutes()
    {
        var list = new List<DynamicRouteModel>();

        // custom code usually here

        return list;
    }

    public void Clear()
    {
        // custom code usually here
    }

    public bool Match(string name)
    {
        // custom code usually here
        return false;
    }

}

There is nothing wrong with my IModuleService service being injected as that is working fine, i just need to be able to inject IDynamicRouteService into my constraint.

Any help appreciated

EDIT

Here is my current SimpleInjector Register method

public static Container Register(HttpConfiguration apiConfig)
{
    var container = new Container();

    container.RegisterPerWebRequest<HttpContextBase>(() => new HttpContextWrapper(HttpContext.Current));
    container.RegisterPerWebRequest<HttpConfiguration>(() => apiConfig);

    // EnableHttpRequest and IDynamicNameService are needed to get the name of the module
    // that is requested via the DynamicDataController
    container.EnableHttpRequestMessageTracking(apiConfig);
    container.RegisterWebApiRequest<IDynamicModuleService, DynamicRouteService>();

    // service for dynamicRoute checking
    container.Register<IDynamicRouteService, DynamicRouteService>();

    // This is an extension method from the integration package.
    container.RegisterWebApiControllers(apiConfig);

    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

    container.Verify();

    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

    apiConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);

    return container;
}

And my startup.cs file

public void Configuration(IAppBuilder app)
{
    // This is a self hosted webapi project..
    HttpConfiguration apiConfig = new HttpConfiguration();

    // confgi oauth
    OAuthConfig.Register(app);

    // simple injector
    var container = SimpleInjectorConfig.Register(apiConfig);

    AutoMapperConfig.RegisterMappings();
    AreaRegistration.RegisterAllAreas();
    WebApiConfig.Register(apiConfig, container);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    app.UseWebApi(apiConfig);
}
like image 285
Gillardo Avatar asked May 29 '15 08:05

Gillardo


1 Answers

Update:

So I looked at the implementation of DefaultInlineConstraintResolver class and found that this class doesn't use the Container resolver, but the Activator class to create the instance which might be causing you the issue of Default constructor instance.

IMO you might need to create a custom implementation for IInlineConstraintResolver or remove the parameter IDynamicRouteService from DynamicRouteConstraint constructor and initialize the instance via other means.

like image 167
vendettamit Avatar answered Sep 28 '22 06:09

vendettamit