Injection in web api controller not using Single Instance - c#

I have a service that is registered in my container as a single instance
public class MyModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<MyService>()
.As<IMyService>()
.SingleInstance();
}
}
The container is created as below
public static IContainer SetupContainer()
{
var builder = new ContainerBuilder();
var moduleTypes = TypeCache.GetTypes(x => x.IsClassEx() && !x.IsAbstractEx() && x.ImplementsInterfaceEx<IModule>());
foreach (var moduleType in moduleTypes)
{
if (Activator.CreateInstance(moduleType) is IModule module)
builder.RegisterModule(module);
}
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyModules(assemblies);
var result = builder.Build();
return result;
}
This all works perfectly within normal code - I can inject my service and its resolved as I expect
However, when I try to inject my service into a web api controller, the service is again resolved, but Autofac gives me a NEW instance of my service
How can I prevent this behaviour so that the originally created instance is injected?

I think that what are you missing here is that you are not actually resolving your container in the right place and so depending on what type of integration you are using you could do one of the following.
//For OWIN you could do something like the following.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = YourObject.SetupContainer();
// Register the Autofac middleware FIRST. This also adds
// Autofac-injected middleware registered with the container.
app.UseAutofacMiddleware(container);
// ...then register your other middleware not registered
// with Autofac.
}
}
//In your Global.asax.cs
protected void Application_Start()
{
var container = YourObject.SetupContainer();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
MVC Example
OWIN Implementation

Related

How do I inject dependency in webapi in .net framework using Microsoft.Extensions.DependencyInjection?

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;
}
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
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

ASP.NET Dependency Injection Scoped life time

I am using ASP.Net Core Dependency Injection in an MVC App (not .Net Core app, but classic ASP.NET MVC Applicatio) I am using DI by adding the Microsoft.Extensions.DependencyInjection Nuget package. I am trying to create scoped life time for my controllers so I have a new scope whenever I create my controllers but I am getting the same instance always for my requests and there is an error as below
"A single instance of controller 'X.Controllers.HomeController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request"
I have used a custom factory to create my controllers
and used new scope to create the controllers .
and the scope is disposed in the ReleaseController method
public class MyServiceFactory : DefaultControllerFactory
{
private readonly IServiceContainer _dependencyManager;
public MyServiceFactory (IServiceContainer dependencyManager)
{
this._dependencyManager = dependencyManager;
}
public override void ReleaseController(IController controller)
{
_dependencyManager.Release(((ServiceEndPoint)controller).Context.RuntimeContext.Scope);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
var scope = _dependencyManager.GetNewScope();
var service=(ServiceEndPoint)_dependencyManager.Resolve(scope, controllerType);
service.Context.RuntimeContext.SetScope(scope);
return service;
}
}
The ServiceEndpoint is just a base class derived from Controller and I am using it as the base for all my controllers which contains some common logic.
I am setting a Context for my controllers which also contain the newly created scope and I am disposing my scope in Releasecontroller by getting it from the Context.
_dependencyManager.GetNewScope() create a New scope as below
return _container.CreateScope();
where _container is an Instance of IServiceProvider
The code _dependencyManager.Resolve(scope, type) is as below
public object Resolve(IServiceScope scope,Type type)
{
return scope.ServiceProvider.GetService(type);
}
You are doing something wrong, but as you hid the use of the Microsoft.Extensions.DependencyInjection (MS.DI) container behind your own abstraction, it is impossible to see what is going on.
However, the following is an example of a working sample application that integrates ASP.NET MVC with MS.DI.
MS.DI-specific controller factory:
public class MsDiControllerFactory : DefaultControllerFactory
{
private readonly ServiceProvider container;
public MsDiControllerFactory(ServiceProvider container) => this.container = container;
protected override IController GetControllerInstance(RequestContext c, Type type) =>
(IController)this.GetScope().ServiceProvider.GetRequiredService(type);
public override void ReleaseController(IController c) => this.GetScope().Dispose();
private IServiceScope GetScope() =>
(IServiceScope)HttpContext.Current.Items["scope"] ??
(IServiceScope)(HttpContext.Current.Items["scope"] = this.container.CreateScope());
}
MVC application configuring the container and replacing the default controller factory:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Default MVC stuff
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// create container builder to register dependencies in
var services = new ServiceCollection();
// register controller in the controller
services.AddScoped<HomeController>();
// Build the container while ensuring scopes are validated
ServiceProvider container = services.BuildServiceProvider(true);
// Replace default controller factory
ControllerBuilder.Current.SetControllerFactory(
new MsDiControllerFactory(container));
}
}
When you apply the above code to an MVC application created using the default MVC template for Visual Studio, you'll get a working MVC application that uses MS.DI as its application container.
(MVC 5, .NET Framework 4.8, not .NET Core or ASP.NET Core)
I was able to get Singleton / Scoped / Transient service lifecycles by creating an HttpContext-bound scope from within the dependency resolver, and did not need to modify the default controller factory:
private void ConfigureDependencyInjection(IAppBuilder app)
{
var services = new ServiceCollection();
AddControllersAsServices(services);
var provider = services.BuildServiceProvider();
var resolver = new DefaultDependencyResolver(provider);
DependencyResolver.SetResolver(resolver);
}
private void AddControllersAsServices(IServiceCollection services)
{
var controllers = typeof(Startup).Assembly.GetExportedTypes()
.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition && typeof(IController).IsAssignableFrom(t));
foreach(var controller in controllers)
{
services.AddTransient(controller);
}
}
class DefaultDependencyResolver : IDependencyResolver
{
private readonly IServiceProvider serviceProvider;
public DefaultDependencyResolver(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public object GetService(Type serviceType)
{
var scope = this.GetHttpContextScope();
if (scope == null)
{
return this.serviceProvider.GetService(serviceType);
}
else
{
return scope.ServiceProvider.GetService(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.serviceProvider.GetServices(serviceType);
}
private IServiceScope GetHttpContextScope()
{
var context = HttpContext.Current;
if (context == null)
{
return null;
}
var scope = context.Items[this] as IServiceScope;
if (scope != null)
{
return scope;
}
scope = this.serviceProvider.CreateScope();
context.Items[this] = scope;
context.AddOnRequestCompleted(_ => scope.Dispose());
return scope;
}
}
The code works as follows: if a service is requested and there is a current HttpContext check if there is an IServiceScope associated with it, otherwise create a new Scope instance and bind it to the context. When the request is completed, dispose of the scope instance.
If there is no HttpContext simply resolve the service from the root ServiceProvider instance. I am not sure what that means for scoped services, but I assume they will behave like singletons in that case.

How to fake declared services in Startup.cs during testing?

I would like to write integration tests for my Asp .net core application, but I don't want my tests to use real implemetation of some services.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IExternalService,ExternalService>();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
}
}
public interface IExternalService
{
bool Verify(int id);
}
public class ExternalService : IExternalService
{
public bool Verify(int id)
{
//Implemetation is here.
//I want to fake this implemetation during testing.
}
}
[Fact]
public void TestCase()
{
//Stub out service
var myExtService = new Mock<IExternalService>();
//Setup response by stub
myExtService
.Setup(p => p.Verify(It.IsAny<int>()))
.Returns(false);
var host = new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureServices((services) =>
{
//Setup injection
services.AddTransient<IExternalService>((a) =>
{
return myExtService.Object;
});
});
var server = new TestServer(host);
var client = server.CreateClient();
var response = client.GetAsync("/").Result;
var responseString = response.Content.ReadAsStringAsync().Result;
Assert.Contains("Your service returned: False", responseString);
}
Current injection setup in test case does not work, because ExternalService is injected over the mock.
However the test will pass when I remove services.AddTransient<IExternalService,ExternalService>; from Startup.
Most likely the one in Startup is called later and all the setup in that class is preferred by application.
What options do I have to setup some dependecies in tests, but use everything else as they are declared in Startup?
UPDATE
Application code should be unaware of tests.
Tests should be aware of:
(weakly typed) Endpoint - if this changes then test should fail
IExternalService interface
Tests should not care if application has razor pages or uses mvc or how the application is wired between endpoint and IExternalService.
Tests should not have to setup or configure application (apart from stubbing IExternalService) in order to make it work.
I understand that WebHostBuilder still has to be created, but my point is that configuration should be bare minimum in test case and majority of configuration should still be described on application side.
The only option I know of is to setup WebHostBuilder with UseEnvironment:
var host = new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureServices(services =>
{
//Setup injection
services.AddTransient<IExternalService>(provider =>
{
return myExtService.Object;
});
})
.UseEnvironment("IntegrationTest");
And then add a condition in the ConfigureServices method in the Startup:
public void ConfigureServices(IServiceCollection services)
{
if (Configuration["Environment"] != "IntegrationTest")
{
services.AddTransient<IExternalService, ExternalService>();
}
services.AddMvc();
// ...
}
UPDATE:
I did some more poking around and another option is to not use UseStartup extension method but rather configure the WebHostBuilder directly. You can do this a number of ways but I thought that you could possibly create your own extension method to create a template in your tests:
public static class WebHostBuilderExt
{
public static WebHostBuilder ConfigureServicesTest(this WebHostBuilder #this, Action<IServiceCollection> configureServices)
{
#this.ConfigureServices(services =>
{
configureServices(services);
services.AddMvc();
})
.Configure(builder =>
{
builder.UseMvc();
});
return #this;
}
}
Now your tests can be setup like the following:
var host = new WebHostBuilder()
.ConfigureServicesTest(services =>
{
//Setup injection
services.AddTransient<IInternalService>(provider =>
{
return myExtService.Object;
});
});
var server = new TestServer(host);
This means that you will have to explicitly setup all the implementations that the container will resolve for the specific endpoint you are calling. You can choose to mock or use the the concrete implementations.
The only thing yo need to change is to use ConfigureTestServices instead of ConfigureServices. ConfigureTestServices runs after your Startup, therefor you can override real implementations with mocks/stubs. ConfigureServices was newer intended for that purpose, rather, it configures "host services", which are used during the host-building phase of the application, and copied into the application's DI container.
ConfigureTestServices is available in ASP Core version 2.1 and higher.
var host = new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureTestServices((services) =>
{
//Setup injection
services.AddTransient<IExternalService>((a) =>
{
return myExtService.Object;
});
});
So after hours of research I found a solution.
I could not find a way to solely use built-in dependency injection solution, so I opted to choose 3rd party DI solution - Autofac
Idea is to use WebHostBuilder (declared Main Program) and add necessary options so I can fake some services during testing.
Something that I learned:
If you use Startup as host.UseStartup<Startup> it will be created after host.ConfigureServices()
You cannot inject something to Startup like host.UseStartup<Startup>(new Dependency())
However if you have registred dependency in host.ConfigureServices(services => services.AddTransient<IDependency, MyDependency>()), then it will be resolved before Startup is created and constructor public Startup(IDependency dependency) is used to create Startup.
My application side:
public class Program
{
public static void Main(string[] args)
{
CreateWebHost(args)
.Build()
.Run();
}
public static IWebHostBuilder CreateWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureServices((services) =>
{
//Setup autofac.
services.AddAutofac();
//Register module dependency that Startup requires.
services.AddTransient<Module, MyAutofacModule>();
////It would a bit cleaner to use autofac to setup Startup dependency,
////but dependency did not get resolved for Startup.
//services.AddAutofac((builder) =>
//{
// builder.RegisterModule(new AutofacModule());
//});
})
.UseStartup<Startup>();
}
public class MyAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//Register all application dependencies in this module.
builder.Register((c) => new ExternalService()).As<IExternalService>();
}
}
public class Startup
{
private Module applicationDIModule;
public Startup(Module applicationDIModule)
{
this.applicationDIModule = applicationDIModule;
}
public void ConfigureServices(IServiceCollection services)
{
//We can add build-in services such as mvc and authorization,
//but I would not use Add(Transient/Scoped/Singleton) here.
//You should register domain specific dependecies in MyAutofacModule,
//since it will be added after this method call.
services.AddMvc();
}
//This method is called after ConfigureServices (refer to Autofac link).
public void ConfigureContainer(ContainerBuilder builder)
{
//We will register injected module.
builder.RegisterModule(applicationDIModule);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvcWithDefaultRoute();
}
}
Test case:
public class IntegrationTests
{
[Fact]
public void TestCase()
{
//Create and setup moq object as usual.
var service = new Mock<IExternalService>();
service
.Setup(p => p.Verify(It.IsAny<int>()))
.Returns(false);
//Bundle moq objects together for registration.
var attachFakes = new Action<ContainerBuilder>((builder) =>
{
builder.Register(c => service.Object);
});
//Use host builder that application uses.
var host = Program.CreateWebHost(new string[] { })
.UseContentRoot(GetContentRoot()) //Adjust content root since testproject.csproj is not in same folder as application.csproj
.ConfigureServices((services) =>
{
//We re-configure Module registration,
//so Startup is injected with our TestModule.
services.AddTransient<Module>((a) =>
{
return new TestModule(attachFakes);
});
});
//Create server to use our host and continue to test.
var server = new TestServer(host);
var client = server.CreateClient();
var response = client.GetAsync("/").Result;
var responseString = response.Content.ReadAsStringAsync().Result;
Assert.Contains("External service result: False", responseString);
}
private static string GetContentRoot()
{
var current = Directory.GetCurrentDirectory();
var parent = Directory.GetParent(current).Parent.Parent.Parent;
return Path.Combine(parent.FullName, "src");
}
}
public class TestModule : MyAutofacModule
{
private Action<ContainerBuilder> attachFakes;
public TestModule(Action<ContainerBuilder> attachFakes)
{
this.attachFakes = attachFakes;
}
protected override void Load(ContainerBuilder builder)
{
//We register everything in MyAutoFacModule before adding our fakes.
base.Load(builder);
//We add fakes and everything that is re-registered here will be used instead.
attachFakes.Invoke(builder);
}
}
Although it feels a bit brittle, but I still prefer this solution over what #ODawg suggested. His solution would work, but I see it would cause troubles in future when new test cases are added.

.net Simple Injector. register webApiControllers no parameterless public constructor

I have an error after I am trying to call my webApi controller,
An error occurred when trying to create a controller of type 'DrinkController'. Make sure that the controller has a parameterless public constructor.
Here is my Bootstrapper.cs
public class Bootstrapper
{
public Container Start(HttpConfiguration configuration)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle();
var conString = ConfigurationManager.ConnectionStrings["DrinksContext"].ConnectionString;
container.Register(() => new DrinksContext(conString), Lifestyle.Scoped);
container.Register<IUserManager, UserManager>();
container.Register<IDrinkManager, DrinkManager>();
container.Register<IOrderManager, OrderManager>();
container.Register<IUnitOfWork, UnitOfWork>();
container.RegisterWebApiControllers(configuration);
container.Verify();
return container;
}
}
and here how I call him in Global.asax.cs
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
var container = new Bootstrapper().Start(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}
Controller ->
private readonly IOrderManager _orderManager;
private readonly IDrinkManager _drinkManager;
public DrinkController(IOrderManager orderManager, IDrinkManager drinkManager)
{
_orderManager = orderManager;
_drinkManager = drinkManager;
}
UnitiOfWork constructor depended from DrinksContext;
Postman response - here
I am injecting UnitOfWork into my managers. DrinksContext should reinitialize per each request. When line
container.RegisterWebApiControllers(configuration) executes controller constructor fired, but when just a call from Postman - no. How I can resolve it? Thanks.
If you look into the inner exception of the thrown exception, you will see the following information:
The Object is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope.
This is because a lifetime scope needs to be started explicitly. The lifetime scope however is unsuited to work with both MVC and Web API due to the asynchronous behavior of both frameworks. Since you are running inside IIS, you should use WebRequestLifestyle as the default scoped lifestyle.
i think the problem is in your Unity config file.. maybe try to do this:
public Container Start(HttpConfiguration configuration)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle();
var conString = ConfigurationManager.ConnectionStrings["DrinksContext"].ConnectionString;
container.Register(() => new DrinksContext(conString), Lifestyle.Scoped);
container.Register<IUserManager, UserManager>();
container.Register<IDrinkManager, DrinkManager>(new InjectionConstructor());
container.Register<IOrderManager, OrderManager>(new InjectionConstructor());
container.Register<IUnitOfWork, UnitOfWork>();
container.RegisterWebApiControllers(configuration);
container.Verify();
return container;
}
To call the dafult empty contructor of your class implementation (if you have more than one contructor.. Unityt choose the one with more parameter..so if you want to choose the empty one you can use new InjectionConstructor() or put in the constructor of your class the decoration [InjectionConstructor])
Hope it help

Autofac RegisterGeneric works in unit test but not in application

I've got an ASP.NET MVC 6 (Framework 4.6.1) application with Autofac version 4.0.0-rc1-177.
In my Startup.cs, I call an AutofacLoader I've made:
var container = Core.DI.AutofacLoader.Configure(services).Build();
The AutofacLoader class:
public class AutofacLoader
{
public static IContainer Container { get; set; }
/// <summary>
/// Register the DI modules through AutoFac
/// </summary>
/// <param name="services">IServiceCollection to register the modules on</param>
/// <returns></returns>
public static ContainerBuilder Configure(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.RegisterModule<LogRequestsModule>();
//Core
builder.RegisterModule(new Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Core.ServiceModules.ServicesModule());
builder.RegisterModule(new DAL.ServicesModules.IBSRepositoriesModule());
//Dieet
builder.RegisterModule(new Dieet.Core.ServiceModules.AutoMapperModule());
builder.RegisterModule(new Dieet.Core.ServiceModules.ServicesModule());
builder.RegisterModule(new Dieet.DAL.ServicesModules.DieetRepositoriesModule());
//builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
if (services == null)
{
Container = builder.Build();
}
else
{
builder.Populate(services);
}
return builder;
}
}
My IBS.Core.ServicesModules.ServiceModule class (which when I put a breakpoint in this class, gets called when launching my app, so by the AutofacLoader class):
namespace IBS.Core.ServiceModules
{
public class ServicesModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();
builder.RegisterGeneric(typeof(PaginatedSearchViewModel<>)).As(typeof(IPaginatedSearchViewModel<>)).InstancePerLifetimeScope();
}
}
}
My xunit test (with FluentAssertions) that passes:
public class ServiceModulesTest
{
[Fact]
public void ShouldBeInstantiatable()
{
AutofacLoader.Configure(null);
var container = AutofacLoader.Container;
var instance = container.Resolve<IPaginatedSearchViewModel<PatientViewModel>>();
instance.Should().BeOfType<PaginatedSearchViewModel<PatientViewModel>>();
}
}
But when I run the application, in one of my API controllers, I've got for example, this method:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(IPaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
This fails in the browser with the response: Cannot resolve the Interface.
When I change the IPaginatedSearchViewModel to the concrete class in the parameters myself:
[HttpGet("patienten")]
public async Task<PagedResult<PatientViewModel>> GetPatientsAsync(PaginatedSearchViewModel<PatientFilters> vm)
{
return await _infohosService.GetAllPatientsWithDossiersAndVerpleegperiodesAsync(vm);
}
The API works.
So my questions:
Why does my unit test pass? (I'm new to unit testing, so maybe I've done something wrong here?)
How can I make Autofac resolve this Interface too, because it works fine for all my Services, Repositories, IDbContext, ...?
I'm not sure if asp.net mvc 6 uses DI container on model binding stage
This is indeed the problem. I've Google'd some more and didn't find that MVC 6 uses the DI container in the model binding stage.
Solved by using the concrete class in the method.

Categories