4

I am trying to inject my logger as dependency in a .Net Framework 4.7.2 web api project by following these instructions:

https://scottdorman.blog/2016/03/17/integrating-asp-net-core-dependency-injection-in-mvc-4/

This works great for MVC web application but fails on the webapi project with the "parameterless constructor missing" error.

How do I successfully inject using just the default assembly: Microsoft.Extensions.DependencyInjection in framework?

public class Startup
{
    public void Configuration(IAppBuilder app)
    {

        var services = new ServiceCollection();
        ConfigureServices(services);
        var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());
        DependencyResolver.SetResolver(resolver);
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
            .Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
            .Where(t => typeof(IController).IsAssignableFrom(t)
                        || t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
        services.AddSingleton<IMyInterface , MyClass>();
    }
}
public class DefaultDependencyResolver : IDependencyResolver
{
    protected IServiceProvider serviceProvider;

    public DefaultDependencyResolver(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public object GetService(Type serviceType)
    {
        return this.serviceProvider.GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.serviceProvider.GetServices(serviceType);
    }
}

public static class ServiceProviderExtensions
{
    public static IServiceCollection AddControllersAsServices(this IServiceCollection services,
        IEnumerable<Type> controllerTypes)
    {
        foreach (var type in controllerTypes)
        {
            services.AddTransient(type);
        }

        return services;
    }
}

Getting "Parameterless constructor is missing" error with an injection like this:

private IMyInterface _my;
public HomeController(IMyInterface my)
{
    _my= my;
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
user8808262
  • 189
  • 1
  • 2
  • 9

2 Answers2

10

Registration Explanation

One issue is that you are registering your DependencyResolver with the MVC resolver registration API which unfortunately is different from the WebAPI resolver registration API. What you want to do instead is:

public void Configuration(IAppBuilder app)
{    
    var services = new ServiceCollection();
    ConfigureServices(services);
    var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());
    HttpConfiguration config = new HttpConfiguration();
    config.DependencyResolver = resolver;
    app.UseWebApi(config);
}

Also note that the IDependencyResolver interface is defined separately in System.Web.Http, so your DefaultDependencyResolver class needs to be updated to derive from it instead.

One thing that has changed on that interface is that there is a BeginScope API. To implement that, call the CreateScope Extension Method exposed on IServiceProvider in Microsoft.Extensions.DependencyInjection to get a new scope. Then pass the provider from that scope to a new instance of your DefaultDependencyResolver.

    public IDependencyScope BeginScope()
    {
        return new DefaultDependencyResolver(this.serviceProvider.CreateScope().ServiceProvider);
    }

Full Example

The blog example you were following for MVC was using OWIN. When I set out to make a full example, I hit the same error as you, and it was because I hadn't correctly configured OWIN so Startup was never being called. Here is a full working example of Microsoft.Extensions.DependencyInjection being used to inject into both MVC and WebAPI Controllers:

https://github.com/ryandle/MVC_WebApi_DI_Example

RyanY
  • 749
  • 1
  • 6
  • 16
  • Thanks, that helps. Although, I don't seem to get any different results with the above. It's still expecting parameterless contructor on controllers. Anything I need to configure in BeginScope() ?(expected to be implemented with System.Web.Http.Dependencies.IDependencyResolver ) public IDependencyScope BeginScope() { throw new NotImplementedException(); } – user8808262 Oct 10 '19 at 18:42
  • @user8808262 I have added clarification on implementing BeginScope(). Check it out and let me know if you have further questions. – RyanY Oct 11 '19 at 19:22
  • @ RyanY, Thanks for this. I added CreateScope to get the new scope per your suggestion above with no luck. Still getting parameterless constructor missing error. Do you have any further ideas? Thanks! If you have code that's doing this, would you mind sharing it here? Perhaps, that might help me. Thanks – user8808262 Oct 23 '19 at 16:29
  • @user8808262 Added a full example to my answer, hope this helps! – RyanY Oct 25 '19 at 03:01
  • Thank you so much! That was a huge help! I appreciate it. – user8808262 Oct 25 '19 at 19:58
  • @user8808262 no problem. If this fully answers your question, please mark it as such! Otherwise let's keep making the answer better. – RyanY Oct 25 '19 at 20:53
  • Yes it does. Marked! Thanks again! – user8808262 Oct 26 '19 at 17:06
-4

Are you using [Serializable] on your HomeController? If so, when using it you need a constructor without parameters.

Try add this: public HomeController() { } and run again.

More info: parameter less constructor error

Paschoali
  • 91
  • 1
  • 8