I am experimenting with a throwaway vNext application. What I'm trying to do is create a dummy class called 'DataService' which will return some data, and then create objects which use DI to take an IDataService parameter as the constructor.
So my IDataService/DataService definitions are:
public interface IDataService
{
DateTime Created { get; }
}
public class DataService : IDataService
{
private DateTime created = DateTime.Now;
public DateTime Created
{
get { return created; }
}
}
In my startup class I register this as a singleton:
public void Configure(IApplicationBuilder app)
{
app.UseServices(services =>
{
services.AddSingleton<Data.IDataService, Data.DataService>();
});
And in a class I created, I add the IDataService interface as a constructor dependency:
internal class Constraint : IRouteConstraint
{
private readonly IDataService _dataService;
public Constraint (IDataService dataService)
{
_dataService = dataService;
}
public bool Match(....)
{
//call dataservice for match
}
}
The class here with the constructor dependency is an IRouteConstraint which I'm trying to use to get dynamic routes in MVC - the final part of the startup class code is this:
app.UseMvc(routes => {
routes.MapRoute(name: "TestRoute", template: "{*constraints}", defaults: new { controller = "Test", action = "Index" }, constraints: new { constraint = new Constraint() }); //<--- how to construct using DI?
});
The issue is that the Constraint() class can't be created because it is missing the constructor. All the examples show a Controller using DI and the instantiation of the Controller classes are handled by MVC so that is part of the 'automagic' we don't see at first glance.
So my question is:
How do I instantiate the 'Constraint' object so that DI provides the implementation of the DataService singleton?
Is my issue because I'm trying this in the Configure method in the UseMvc method, or is my problem more fundamental than that?
I figure I'm missing some way of getting DI to act as an object factory to provide my objects instead of trying to declaratively creating them.
If you're wanting to resolve your Constraint through the Dependency Injection, you'll need to register it, first:
services.AddTransient<Constraint>();
Once you have the IApplicationBuilder, you can access the services directly:
app.ApplicationServices.GetRequiredService<Constraint>();
Of course, if you don't want to add your Constraint type to the services list, you can still access the IDataService the same way.
This assumes you have using Microsoft.Framework.DependencyInjection; declared at the top of your Startup; given your other syntax, I believe that you do.
Related
I have three types of users in my application, let's say Type1, Type2 and Type3.
Then i want to create one service implementation for each type, let's say i have a service to get photos, i would have three services : Type1PhotosService, Type2PhotosService and Type3PhotosService, each of them implementing IPhotosService.
In the web api, i would inject IPhotosService :
IPhotosService _service;
public PhotosController(IPhotosService service){
_service = service;
}
The web api uses token authentication with claims. So what i want to achieve, is for each user, depending on the claim he has : type1 or type2 or type3, the correct implementation of the service will be automatically injected rather than injecting a single service in the startup file.
What i want to avoid, is having one service, with a bunch of switch and if statements to return the correct data depending on user type and the roles he has.
EDIT:
some comments were wondering what's the point of three implementations, so here are more details to give it a little more sense.
The service is a job finder service, and the application has three different profiles : candidate, employer and administration. Each of these profiles need a proper implementation. So rather than having three methods GetCandidateJobs, GetEmployerJobs and GetAdministrationJobs inside the same service and switch on the user type, i preferred to have one implementation per profile type, then depending on the profile type, use the correct implementation.
Without Using a Separate IoC Container
Here's an approach that's way easier than configuring your app to use another IoC container and then configuring that container. After working through this with Windsor this solution seems a whole lot easier.
This approach is simplest if you can use a singleton instance of each service implementation.
We'll start with an interface, some implementations, and the factory we can inject which will return an implementation selected at runtime based on some input.
public interface ICustomService { }
public class CustomServiceOne : ICustomService { }
public class CustomServiceTwo : ICustomService { }
public class CustomServiceThree : ICustomService { }
public interface ICustomServiceFactory
{
ICustomService Create(string input);
}
Here's a really crude implementation of the factory. (Didn't use string constants, or polish it at all.)
public class CustomServiceFactory : ICustomServiceFactory
{
private readonly Dictionary<string, ICustomService> _services
= new Dictionary<string, ICustomService>(StringComparer.OrdinalIgnoreCase);
public CustomServiceFactory(IServiceProvider serviceProvider)
{
_services.Add("TypeOne", serviceProvider.GetService<CustomServiceOne>());
_services.Add("TypeTwo", serviceProvider.GetService<CustomServiceTwo>());
_services.Add("TypeThree", serviceProvider.GetService<CustomServiceThree>());
}
public ICustomService Create(string input)
{
return _services.ContainsKey(input) ? _services[input] : _services["TypeOne"];
}
}
This assumes that you've already registered CustomServiceOne, CustomServiceTwo, etc. with the IServiceCollection. They would not be registered as interface implementations, since that's not how we're resolving them. This class will simply resolve each one and put them in a dictionary so that you can retrieve them by name.
In this case the factory method takes a string, but you could inspect any type or multiple arguments to determine which implementation to return. Even the use of a string as the dictionary key is arbitrary. And, just as an example, I provided fallback behavior to return some default implementation. It might make more sense to throw an exception instead if you can't determine the right implementation to return.
Another alternative, depending on your needs, would be to resolve the implementation within the factory when it's requested. To the extent possible I try to keep most classes stateless so that I can resolve and reuse a single instance.
To register the factory with the IServiceCollection at startup we would do this:
services.AddSingleton<ICustomServiceFactory>(provider =>
new CustomServiceFactory(provider));
The IServiceProvider will be injected into the factory when the factory is resolved, and then the factory will use it to resolve the service.
Here's the corresponding unit tests. The test method is the identical to the one used in the Windsor answer, which "proves" that we can transparently replace one factory implementation with another and change other stuff in the composition root without breaking stuff.
public class Tests
{
private IServiceProvider _serviceProvider;
[SetUp]
public void Setup()
{
var services = new ServiceCollection();
services.AddSingleton<CustomServiceOne>();
services.AddSingleton<CustomServiceTwo>();
services.AddSingleton<CustomServiceThree>();
services.AddSingleton<ICustomServiceFactory>(provider =>
new CustomServiceFactory(provider));
_serviceProvider = services.BuildServiceProvider();
}
[TestCase("TypeOne", typeof(CustomServiceOne))]
[TestCase("TypeTwo", typeof(CustomServiceTwo))]
[TestCase("TYPEThree", typeof(CustomServiceThree))]
[TestCase("unknown", typeof(CustomServiceOne))]
public void FactoryReturnsExpectedService(string input, Type expectedType)
{
var factory = _serviceProvider.GetService<ICustomServiceFactory>();
var service = factory.Create(input);
Assert.IsInstanceOf(expectedType, service);
}
}
As in the Windsor example, this is written to avoid any reference to the container outside of the composition root. If a class depends on ICustomServiceFactory and ICustomService you could switch between this implementation, the Windsor implementation, or any other implementation of the factory.
Using Windsor
I'm going to sidestep the questions about whether or not this makes sense in this case and just attempt to answer the question as asked:
.NET Core's IoC container isn't built particularly well for this sort of scenario. (They acknowledge this in their documentation.) You can work around it by adding another IoC container like Windsor.
The implementation ended up looking way more complicated than I would have liked, but once you get past the setup it's not bad and you get access to Windsor's features. I'm going to provide another answer that doesn't include Windsor. I had to do all of this work to see that I probably like the other approach better.
In your project, add the Castle.Windsor.MsDependencyInjection NuGet package.
Interfaces and Implementations for Testing
For testing, I added some interfaces and implementations:
public interface ICustomService { }
public interface IRegisteredWithServiceCollection { }
public class CustomServiceOne : ICustomService { }
public class CustomServiceTwo : ICustomService { }
public class CustomServiceThree : ICustomService { }
public class RegisteredWithServiceCollection : IRegisteredWithServiceCollection { }
The intent is to create a factory that will select and return an implementation of ICustomService using some runtime input.
Here's an interface which will serve as a factory. This is what we can inject into a class and call at runtime to get an implementation of ICustomService:
public interface ICustomServiceFactory
{
ICustomService Create(string input);
}
Configure the Windsor Container
Next is a class which will configure an IWindsorContainer to resolve dependencies:
public class WindsorConfiguration : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<ICustomService, CustomServiceOne>().Named("TypeOne"),
Component.For<ICustomService, CustomServiceTwo>().Named("TypeTwo"),
Component.For<ICustomService, CustomServiceThree>().Named("TypeThree"),
Component.For<ICustomService, CustomServiceOne>().IsDefault(),
Component.For<ICustomServiceFactory>().AsFactory(new CustomServiceSelector())
);
}
}
public class CustomServiceSelector : DefaultTypedFactoryComponentSelector
{
public CustomServiceSelector()
: base(fallbackToResolveByTypeIfNameNotFound: true) { }
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return (string) arguments[0];
}
}
Here's what's going on in here:
The TypedFactoryFacility will enable us to use Windsor's typed factories. It will create an implementation of our factory interface for us.
We're registering three implementations of ICustomService. Because we're registering more than one implementation, each must have a name. When we resolve ICustomService we can specify a name, and it will resolve the type according to that string.
For illustration I registered another implementation of ICustomService without a name. That will enable us to resolve a default implementation if we try to resolve using an unrecognized name. (Some alternatives are just throwing an exception, or returning a "null" instance of ICustomService or creating a class like UnknownCustomService that throws an exception.)
Component.For<ICustomServiceFactory>().AsFactory(new CustomServiceSelector()) tells the container to create a proxy class to implement ICustomServiceFactory. (More on that in their documentation.)
CustomServiceSelector is what takes the argument passed to the factory's Create method and returns the component name (TypeOne, TypeTwo, etc.) that will be used to select a component. In this case we're expecting that the argument passed to the factory will be the same as the registration name we've used. But we could replace this with other logic. Our factory could even take arguments of other types which we could inspect and determine which string to return.
Configure Your App To Use the Windsor Container
Now, in StartUp, modify ConfigureServices to return IServiceProvider instead of void and create an IServiceProvider that combines services registered directly with the IServiceCollection with those registered with the Windsor container:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var container = new WindsorContainer();
container.Install(new WindsorConfiguration());
return WindsorRegistrationHelper.CreateServiceProvider(container, services);
}
container.Install(new WindsorConfiguration()) allows WindsorConfiguration to configure our container. We could just configure the container right in this method, but this is a nice way to keep our container configurations organized. We can create numerous IWindsorInstaller implementations or our own custom classes to configure the Windsor container.
WindsorRegistrationHelper.CreateServiceProvider(container, services) creates the IServiceProvider that uses container and services.
Does It Work?
I wouldn't post all this without finding out first. Here's some NUnit tests. (I usually write some basic tests for DI configuration.)
The setup creates an IServiceProvider similar to what would happen in the application startup. It creates a container and applies the WindsorConfiguration. I'm also registering a service directly with the ServiceCollection to make sure that the two play well together. Then I'm combining the two into an IServiceProvider.
Then I'm resolving an ICustomerServiceFactory from the IServiceProvider and verifying that it returns the correct implementation of ICustomService for each input string, including the fallback when the string isn't a recognized dependency name.
I'm also verifying that the service registered directly with ServiceCollection is resolved.
public class Tests
{
private IServiceProvider _serviceProvider;
[SetUp]
public void Setup()
{
var services = new ServiceCollection();
services.AddSingleton<IRegisteredWithServiceCollection, RegisteredWithServiceCollection>();
var container = new WindsorContainer();
container.Install(new WindsorConfiguration());
_serviceProvider = WindsorRegistrationHelper.CreateServiceProvider(container, services);
}
[TestCase("TypeOne", typeof(CustomServiceOne))]
[TestCase("TypeTwo", typeof(CustomServiceTwo))]
[TestCase("TYPEThree", typeof(CustomServiceThree))]
[TestCase("unknown", typeof(CustomServiceOne))]
public void FactoryReturnsExpectedService(string input, Type expectedType)
{
var factory = _serviceProvider.GetService<ICustomServiceFactory>();
var service = factory.Create(input);
Assert.IsInstanceOf(expectedType, service);
}
[Test]
public void ServiceProviderReturnsServiceRegisteredWithServiceCollection()
{
var service = _serviceProvider.GetService<IRegisteredWithServiceCollection>();
Assert.IsInstanceOf<RegisteredWithServiceCollection>(service);
}
}
Is All of This Worth It?
Now that I've figured it out, I'd probably use it if I really needed this sort of functionality. It looks worse if you're trying to assimilate both using Windsor with .NET Core and seeing it's abstract factory implementation for the first time. Here's another article with some more information on Windsor's abstract factory without all the noise about .NET Core.
I am going to go out on a limb here and say that the attempt to utilize dependency injection for this purpose is sub-optimal. Normally this would be handled by a Factory pattern that produces service implementations using the dreaded if and switch statements. A simple example is:
public interface IPhotoService {
Photo CreatePhoto(params);
}
public class PhotoServiceFactory {
private readonly IPhotoService _type1;
private readonly IPhotoService _type2;
private readonly IPhotoService _type3;
public PhotoServiceFactory(IDependency1 d1, IDependency2 d2, ...etc) {
_type1 = new ConcreteServiceA(d1);
_type2 = new ConcreteServiceB(d2);
_type3 = new ConcreteServiceC(etc);
}
public IPhotoService Create(User user) {
switch(user.Claim) {
case ClaimEnum.Type1:
return _type1;
case ClaimEnum.Type2:
return _type2;
case ClaimEnum.Type3:
return _type3;
default:
throw new NotImplementedException
}
}
}
Then in your controller:
public class PhotosController {
IPhotoServiceFactory _factory;
public PhotosController(IPhotoServiceFactory factory){
_factory = factory;
}
public IHttpActionResult GetPhoto() {
var photoServiceToUse = _factory.Create(User);
var photo = photoServiceToUse.CreatePhoto(params);
return Ok(photo);
}
}
Alternately just use the concrete classes as arguments in the constructor and follow a similar logic as to the above.
Here is one solution, i have created inside asp.net core console application.
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
namespace CreationalPattern
{
class Program
{
static void Main(string[] args)
{
// Add dependency into service collection
var services = new ServiceCollection()
.AddTransient<FordFigoFactory>()
.AddTransient<AudiQ7Factory>();
/* Create CarServiceFactory as singleton because it can be used across the application more frequently*/
services.AddSingleton<ICarServiceFactory>(provider => new CarServiceFactory(provider));
// create a service provider from the service collection
var serviceProvider = services.BuildServiceProvider();
/* instantiate car*/
var factory = serviceProvider.GetService<ICarServiceFactory>();
var audiCar = factory.Create("audi").CreateACar("Blue");
Console.Read();
}
}
public interface ICarServiceFactory
{
ICreateCars Create(string input);
}
public class CarServiceFactory : ICarServiceFactory
{
private readonly Dictionary<string, ICreateCars> _services
= new Dictionary<string, ICreateCars>(StringComparer.OrdinalIgnoreCase);
public CarServiceFactory(IServiceProvider serviceProvider)
{
_services.Add("ford", serviceProvider.GetService<FordFigoFactory>());
_services.Add("audi", serviceProvider.GetService<AudiQ7Factory>());
}
public ICreateCars Create(string input)
{
Console.WriteLine(input + " car is created.");
return _services.ContainsKey(input) ? _services[input] : _services["ford"];
}
}
public interface ICreateCars
{
Car CreateACar(string color);
}
public class FordFigoFactory : ICreateCars
{
public Car CreateACar(string color)
{
Console.WriteLine("FordFigo car is created with color:" + color);
return new Fordigo { Color = color};
}
}
public class AudiQ7Factory : ICreateCars
{
public Car CreateACar(string color)
{
Console.WriteLine("AudiQ7 car is created with color:" + color);
return new AudiQ7 { Color = color };
}
}
public abstract class Car
{
public string Model { get; set; }
public string Color { get; set; }
public string Company { get; set; }
}
public class Fordigo : Car
{
public Fordigo()
{
Model = "Figo";
Company = "Ford";
}
}
public class AudiQ7 : Car
{
public AudiQ7()
{
Model = "Audi";
Company = "Q7";
}
}
}
Explanation:
To understand better try to read the program from bottom to top. We have 3 sections:
Car (Car, Fordigo, AudiQ7)
CarFactory (ICreateCars, FordFigoFactory, AudiQ7Factory)
CarService (ICarServiceFactory, CarServiceFactory)
In this Dependency injection is registered as transient for Factory classes FordFigoFactory and AudiQ7Factory. And Singleton for CarServiceFactory.
In ASP.NET Core the default resolver will resolve Microsoft.Extensions.Logging.ILogger<MyClass> in the controller.
Suppose I create a fresh .NET Standard library that is called from the controller.
How do I pass a Microsoft.Extensions.Logging instance into it?
How do I create a new() instance of my class if ILogger<MyClass2> is required?
Can C# create a manual automapping for ILogger<T>, which I can pass into my library?
There are times when Dependency Injection isn't available - or when you're in a context where you shouldn't be using DI (such as a Unit Test, where you're meant to explicitly define each injected service), ditto some forms of Integration testing.
In those cases - if you don't care about logging (such as when prototyping or experimenting) then use the NullLogger, which is built-in to Microsoft.Extensions.Logging.Abstractions (which is the common NuGet package that all MEL-using projects must reference, so it's guaranteed to be available).
For example, if you have a service implementation that requires a non-null ILogger<T>:
public interface IEncabulatorService
{
void Foo();
}
public class TurboEncabulatorService : IEncabulatorService
{
private readonly ILogger log;
public TurboEncabulatorService( ILogger<TurboEncabulatorService> log )
{
this.log = log ?? throw new ArgumentNullException(nameof(log));
}
public void Foo()
{
this.log.LogInformation( "Foo was invoked." );
}
}
Then you can instantiate this with the NullLogger dummy logger (for example, in a Unit testing project) like so:
using Microsoft.Extensions.Logging; // This namespace must be imported because it uses extension-methods.
using Microsoft.Extensions.Logging.Abstractions;
[TestClass]
public class MyTests
{
[TestMethod]
public void TestEncabulator()
{
ILogger<TurboEncabulatorService> log = NullLoggerFactory.Instance.CreateLogger<TurboEncabulatorService>()
IEncabulatorService service = new TurboEncabulatorService( log );
}
}
If you do care about what is logged, then unfortunately you do need to implement your own ILoggerFactory (and log to some internal buffer), but you do not need to provide your own CreateLogger<T>() method to create strongly-typed ILogger<T> instances, as that's provided for-free in the MEL library as an extension method.
Regarding subclasses
You mentioned in your post "derived" classes - because if you have this...
public class BaseService
{
public BaseService( ILogger<BaseService> log )
{
// ...
}
}
public class DerivedService : BaseService
{
// ...?
}
...you might wonder if a DerivedService is supposed to accept ILogger<BaseService> or ILogger<DerivedService> as surely it needs an ILogger<BaseService> to pass down to BaseService, but then DerivedService would lose its strongly-typed category name.
...but this is not the case! If you look at the definition of ILogger<T> you'll see it's a covariant generic interface because it has <out T> rather than just <T>. This means that any variable, method or constructor that accepts an ILogger<Base> will also accept an ILogger<Derived>!
So you have this and it's perfectly legal:
public class BaseService
{
public BaseService( ILogger<BaseService> log )
{
// ...
}
}
public class DerivedService : BaseService
{
public DerivedService( ILogger<DerivedService> log )
: base( log ) // `ILogger<BaseService>` can accept an `ILogger<DerivedService>`!
{
}
}
And you can instantiate an instance of DerivedService or BaseService with a NullLogger as per my earlier example:
BaseService bs = new BaseService( NullLoggerFactory.Instance.CreateLogger<BaseService>() );
DerivedService ds = new DerivedService ( NullLoggerFactory.Instance.CreateLogger<DerivedService>() );
Factory helper:
If you find yourself needing to make a NullLogger (or your own ILogger implementation) frequently then you can use this factory-helper method:
public static TService CreateServiceWithLogger<TService>( Func<ILogger<TService>,TService> ctor )
{
ILogger<TService> log = NullLoggerFactory.Instance.CreateLogger<TService>();
return ctor( log );
}
C#'s type-inference rules will ensure you won't need to provide an explicit TService generic parameter type argument, like so:
TurboEncabulatorService service = CreateServiceWithNullLogger( log => new TurboEncabulatorService( log ) );
You should use Dependency Injection for this.
Your Controller leverages DI resources by referencing the interface in its constructor. For ILogger<Class> this would look this like:
public class MyAwesomeController : Controller
{
private readonly ILogger _logger;
public MyAwesomeController(ILogger<MyAwesomeController> logger)
{
// logger contains a refference to the DIed ILogger
// We assign it to _logger so we can reference it from other
// methods in the class
_logger = logger;
}
public IActionResult GetIndex()
{
// Log something
//_logger.LogInformation();
return View();
}
}
You can find a lot more detail in the documentation: Logging in ASP.NET Core
public class ActionFilterVersionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Any(x => x.Key == "SetInternalVersion"))
{
// determine somehow that the **InternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
else
{
// determine somehow that the **ExternalSystem implementation** should be resolved when the controller class is instantiated with the **ISystem constructor** parameter
}
base.OnActionExecuting(actionContext);
}
}
I have ExternalSystem/InternalSystem with the ISystem interface.
How can I tell autofac to inject the ExternalSystem or InternalSystem into the instantiated controller as ISystem instance depending on the string value I pass in the ActionFilter or maybe message handler.
I know I can do stuff like:
builder.RegisterType<InternalSystem>().As<ISystem>().Keyed<ISystem>("Internal");
where I can use a func<string,ISystem> factory to resolve the class during runtime but this is not what I want to do.
Actually I need to register the ISystem within the the action filter, but then I would need somehow to pass the container into the filter, but that is not what I want...and prolly its also not possible.
// Action: returns external or internal value
public string Get()
{
return resolvedISystem.Get();
}
Of course I could resolve the ISystem depending on the func factory within each single action or put behavior into a base controller where I check for the header, but I really would prefer the action filter as it can be just globally registerd ONE time, but for each new controller I have to subclass the base controller.
Base controller sample with pseudo code , because the base.Request is null which needs another workaround/fix...
public class BaseController : ApiController
{
public BaseController(Func<string, ISystem> dataServiceFactory)
{
string system = base.Request.Headers.Any(x => x.Key == "SetInternalVersion") ? "internal" : "external";
System = dataServiceFactory(system);
}
public ISystem System { get; set; }
}
UPDATING the container is also marked as OBSOLETE by the Autofac author.
Thus I do not want to add registrations in my filter/handler and update/build the container again.
I think you should not use ActionFilter at all. You have a controller dependency which should be resolved properly based on the information coming from request. Here is a possible solution. You can use a static HttpContext.Current property in order to extract request header.
System classes:
public interface ISystem { }
public class ExternalSystem : ISystem { }
public class InternalSystem : ISystem { }
SystemKeyProvider:
public enum SystemKey
{
External,
Internal
}
public interface ISystemKeyProvider
{
SystemKey GetSystemKey();
}
public class SystemKeyProvider : ISystemKeyProvider
{
private const string HeaderKey = "SetInternalVersion";
private readonly HttpRequest _request;
public SystemKeyProvider(HttpRequest request)
{
_request = request;
}
public SystemKey GetSystemKey()
{
return (_request.Headers[HeaderKey] != null) ?
SystemKey.Internal :
SystemKey.External;
}
}
Controller constructor: ValuesController(ISystem system)
Autofac container registration:
var builder = new ContainerBuilder();
builder.Register(c => HttpContext.Current.Request).As<HttpRequest>().InstancePerRequest();
builder.RegisterType<SystemKeyProvider>().AsImplementedInterfaces();
// service registration
builder.RegisterType<ExternalSystem>().Keyed<ISystem>(SystemKey.External);
builder.RegisterType<InternalSystem>().Keyed<ISystem>(SystemKey.Internal);
builder.Register(c =>
c.ResolveKeyed<ISystem>(c.Resolve<ISystemKeyProvider>().GetSystemKey()))
.As<ISystem>();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(builder.Build());
In this solution I created a SystemKeyProvider wrapper class which is responsible for providing appropriate key in order to resolve ISystem.
Demo:
When no SetInternalSystem header is present.
Then the dependency is resolved as ExternalSystem.
When SetInternalSystem header is present.
Then the dependency is resolved as InternalSystem.
As the title says. I'm creating a Web API and in my API controller, I'm trying to declare a repository in the constructor. I successfully declare it, but every API method I try to call in that controller returns a 500 error. When I remove the constructor/repository variable, I have no issues.
Controller
[Route("api/[controller]")]
public class TestController: Controller
{
private ITestRepository _testRepository;
public TestController(ITestRepository testRepository)
{
_testRepository= testRepository;
}
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services
.AddMvcCore()
.AddJsonFormatters()
.AddApiExplorer();
services.AddScoped<ITestRepository , TestRepository >();
services.AddSwaggerGen();
}
Am I missing something?
Short Answer
I'm trying to declare a repository in the constructor. I successfully declare it, but every API method I try to call in that controller returns a 500 error. When I remove the constructor/repository variable, I have no issues.
You probably need to make one of two changes:
remove the parameters from the repository's constructor, or
register the services that the repository's constructor takes.
Explanation
The exact code from your question works with the following repository code.
public interface ITestRepository { }
public class TestRepository : ITestRepository { }
The code throws a 500 error, though, if the constructor takes a parameter.
public class TestRepository : ITestRepository
{
public TestRepository(object someObject)
{
}
}
It throws with that constructor, because a call to services.AddScoped<ITestRepository, TestRepository>() requires that the TestRepository constructor meets one of these two criteria.
a constructor without parameters, or
a constructor that takes resolvable services.
So to fix your code you need to make one of two changes:
remove the parameters from the constructor, or
register the services that your constructor takes.
For instance, if the repository takes a DbContext in its constructor, then your code might look like this.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddJsonFormatters()
.AddApiExplorer();
services
.AddEntityFramework()
.AddInMemoryDatabase()
.AddDbContext<TestDbContext>(); // register a service
services.AddScoped<ITestRepository, TestRepository>();
services.AddSwaggerGen();
}
TestRepository.cs
public class TestRepository : ITestRepository
{
// pass the registered service to the ctor
public TestRepository(TestDbContext testDbContext)
{
}
}
First we register the dependent component using Microsoft.practices.Unity, and second we resolve them where we are to use them.
You have not resolved your dependency before using it.
public class TestController: Controller
{
private ITestRepository _testRepository;
public TestController(ITestRepository testRepository)
{
_testRepository= testRepository;
}
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
Registering here:
DIContainer.Instance.RegisterType<ITagManager, TagManager>();
We resolve our dependencies before using them.
DIContainer.Instance.Resolve<ITagManager>().RetrieveTwitterTags();
I am building an ASP.NET Core MVC application with Entity Framework Code-First.
I implemented a simple repository pattern, providing basic CRUD operations for all the model classes I have created.
I chose to follow all the recommendations provided in docs and DI is one of these.
In ~~.NET 5~~ (6 years later update: .net 5 was the alpha name of .net core 1.0) dependency injection works very well for any class that we do not directly instantiate (e.g.: controllers, data repositories, ...).
We simply inject them via the constructor, and register the mappings in the Startup class of the application :
// Some repository class
public class MyRepository : IMyRepository
{
private readonly IMyDependency _myDependency;
public MyRepository(IMyDependency myDependency)
{
_myDependency = myDependency;
}
}
// In startup.cs :
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyRepository, MyRepository>();
The problem is that in some of my model classes, I would like to inject some of the dependencies I have declared.
But I think that I cannot use the constructor injection pattern because model classes are often explicitly instantiated. Therefore, I would need to provide myself with the dependencies, which I can't.
So my question is: is there another way than constructor injection to inject dependencies, and how? I was for example thinking of an attribute pattern or something like that.
As I already explained in a comment, when creating an object using new, there is nothing from the dependency injection framework that is involved in the process. As such, it’s impossible for the DI framework to magically inject things into that object, it simply doesn’t know about it.
Since it does not make any sense to let the DI framework create your model instances (models are not a dependency), you will have to pass in your dependencies explicitly if you want the model to have them. How you do that depends a bit on what your models are used for, and what those dependencies are.
The simple and clear case would be to just have your model expect the dependencies on the constructor. That way, it is a compile time error if you do not provide them, and the model has access to them right away. As such, whatever is above, creating the models, is required to have the dependencies the model type needs. But at that level, it’s likely that this is a service or a controller which has access to DI and can request the dependency itself.
Of course, depending on the number of dependencies, this might become a bit complicated as you need to pass them all to the constructor. So one alternative would be to have some “model factory” that takes care of creating the model object. Another alternative would also be to use the service locator pattern, passing the IServiceCollection to the model which can then request whatever dependencies it needs. Note that is generally a bad practice and not really inversion of control anymore.
Both these ideas have the issue that they modify the way the object is created. And some models, especially those handled by Entity Framework, need an empty constructor in order for EF to be able to create the object. So at that point you will probably end up with some cases where the dependencies of your model are not resolved (and you have no easy way of telling).
A generally better way, which is also a lot more explicit, would be to pass in the dependency where you need it, e.g. if you have some method on the model that calculates some stuff but requires some configuration, let the method require that configuration. This also makes the methods easier to test.
Another solution would be to move the logic out of the model. For example the ASP.NET Identity models are really dumb. They don’t do anything. All the logic is done in the UserStore which is a service and as such can have service dependencies.
The pattern often used in domain driven design (rich domain model to be specific) is to pass the required services into the method you are calling.
For example if you want to calculate the vat, you'd pass the vat service into the CalculateVat method.
In your model
public void CalculateVat(IVatCalculator vatCalc)
{
if(vatCalc == null)
throw new ArgumentNullException(nameof(vatCalc));
decimal vatAmount = vatcalc.Calculate(this.TotalNetPrice, this.Country);
this.VatAmount = new Currency(vatAmount, this.CurrencySymbol);
}
Your service class
// where vatCalculator is an implementation IVatCalculator
order.CalculateVat(vatCalculator);
Finally your service can inject another services, like a repository which will fetch the tax rate for a certain country
public class VatCalculator : IVatCalculator
{
private readonly IVatRepository vatRepository;
public VatCalculator(IVatRepository vatRepository)
{
if(vatRepository == null)
throw new ArgumentNullException(nameof(vatRepository));
this.vatRepository = vatRepository;
}
public decimal Calculate(decimal value, Country country)
{
decimal vatRate = vatRepository.GetVatRateForCountry(country);
return vatAmount = value * vatRate;
}
}
I know my answer is late and may not exactly what you're asking for, but I wanted to share how I do it.
First of all: If you want to have a static class that resolves your dependencies this is a ServiceLocator and it's Antipattern so try not to use it as you can.
In my case I needed it to call MediatR inside of my DomainModel to implement the DomainEvents logic.
Anyway, I had to find a way to call a static class in my DomainModel to get an instance of some registered service from DI.
So I've decided to use the HttpContext to access the IServiceProvider but I needed to access it from a static method without mention it in my domain model.
Let's do it:
1- I've created an interface to wrap the IServiceProvider
public interface IServiceProviderProxy
{
T GetService<T>();
IEnumerable<T> GetServices<T>();
object GetService(Type type);
IEnumerable<object> GetServices(Type type);
}
2- Then I've created a static class to be my ServiceLocator access point
public static class ServiceLocator
{
private static IServiceProviderProxy diProxy;
public static IServiceProviderProxy ServiceProvider => diProxy ?? throw new Exception("You should Initialize the ServiceProvider before using it.");
public static void Initialize(IServiceProviderProxy proxy)
{
diProxy = proxy;
}
}
3- I've created an implementation for the IServiceProviderProxy which use internally the IHttpContextAccessor
public class HttpContextServiceProviderProxy : IServiceProviderProxy
{
private readonly IHttpContextAccessor contextAccessor;
public HttpContextServiceProviderProxy(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor;
}
public T GetService<T>()
{
return contextAccessor.HttpContext.RequestServices.GetService<T>();
}
public IEnumerable<T> GetServices<T>()
{
return contextAccessor.HttpContext.RequestServices.GetServices<T>();
}
public object GetService(Type type)
{
return contextAccessor.HttpContext.RequestServices.GetService(type);
}
public IEnumerable<object> GetServices(Type type)
{
return contextAccessor.HttpContext.RequestServices.GetServices(type);
}
}
4- I should register the IServiceProviderProxy in the DI like this
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<IServiceProviderProxy, HttpContextServiceProviderProxy>();
.......
}
5- Final step is to initialize the ServiceLocator with an instance of IServiceProviderProxy at the Application startup
public void Configure(IApplicationBuilder app, IHostingEnvironment env,IServiceProvider sp)
{
ServiceLocator.Initialize(sp.GetService<IServiceProviderProxy>());
}
As a result now you can call the ServiceLocator in your DomainModel classes "Or and needed place" and resolve the dependencies that you need.
public class FakeModel
{
public FakeModel(Guid id, string value)
{
Id = id;
Value = value;
}
public Guid Id { get; }
public string Value { get; private set; }
public async Task UpdateAsync(string value)
{
Value = value;
var mediator = ServiceLocator.ServiceProvider.GetService<IMediator>();
await mediator.Send(new FakeModelUpdated(this));
}
}
The built-in model binders complain that they cannot find a default ctor. Therefore you need a custom one.
You may find a solution to a similar problem here, which inspects the registered services in order to create the model.
It is important to note that the snippets below provide slightly different functionality which, hopefully, satisfies your particular needs. The code below expects models with ctor injections. Of course, these models have the usual properties you might have defined. These properties are filled in exactly as expected, so the bonus is the correct behavior when binding models with ctor injections.
public class DiModelBinder : ComplexTypeModelBinder
{
public DiModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders) : base(propertyBinders)
{
}
/// <summary>
/// Creates the model with one (or more) injected service(s).
/// </summary>
/// <param name="bindingContext"></param>
/// <returns></returns>
protected override object CreateModel(ModelBindingContext bindingContext)
{
var services = bindingContext.HttpContext.RequestServices;
var modelType = bindingContext.ModelType;
var ctors = modelType.GetConstructors();
foreach (var ctor in ctors)
{
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
if (parameters.All(p => p != null))
{
var model = ctor.Invoke(parameters);
return model;
}
}
return null;
}
}
This binder will be provided by:
public class DiModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) { throw new ArgumentNullException(nameof(context)); }
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = context.Metadata.Properties.ToDictionary(property => property, context.CreateBinder);
return new DiModelBinder(propertyBinders);
}
return null;
}
}
Here's how the binder would be registered:
services.AddMvc().AddMvcOptions(options =>
{
// replace ComplexTypeModelBinderProvider with its descendent - IoCModelBinderProvider
var provider = options.ModelBinderProviders.FirstOrDefault(x => x.GetType() == typeof(ComplexTypeModelBinderProvider));
var binderIndex = options.ModelBinderProviders.IndexOf(provider);
options.ModelBinderProviders.Remove(provider);
options.ModelBinderProviders.Insert(binderIndex, new DiModelBinderProvider());
});
I'm not quite sure if the new binder must be registered exactly at the same index, you can experiment with this.
And, at the end, this is how you can use it:
public class MyModel
{
private readonly IMyRepository repo;
public MyModel(IMyRepository repo)
{
this.repo = repo;
}
... do whatever you want with your repo
public string AProperty { get; set; }
... other properties here
}
Model class is created by the binder which supplies the (already registered) service, and the rest of the model binders provide the property values from their usual sources.
HTH
Is there another way than constructor injection to inject dependencies, and how?
The answer is "no", this cannot be done with "dependency injection". But, "yes" you can use the "service locator pattern" to achieve your end-goal.
You can use the code below to resolve a dependency without the use of constructor injection or the FromServices attribute. Additionally you can new up an instance of the class as you see fit and it will still work -- assuming that you have added the dependency in the Startup.cs.
public class MyRepository : IMyRepository
{
public IMyDependency { get; } =
CallContextServiceLocator.Locator
.ServiceProvider
.GetRequiredService<IMyDependency>();
}
The CallContextServiceLocator.Locator.ServiceProvider is the global service provider, where everything lives. It is not really advised to use this. But if you have no other choice you can. It would be recommended to instead use DI all the way and never manually instantiate an object, i.e.; avoid new.
I'm simply adding some supplemental information here to the answers provided that can help.
IServiceProvider was provided in the accepted answer, but not the important IServiceProvider.CreateScope() method. You can use it to create scopes as necessary that you added through ConfigureServices.
I'm not sure if IServiceProvider is actually a Service Locator pattern behind the scenes or not, but it's how you create scopes as far as I know. At least in the case if it is a Service Locator pattern, it's the official one for today in .NET, and so it's not compounded by the problems of writing your own Service Locator, which I also agree is anti-pattern.
Example, Startup.cs/ConfigureServices and Configure:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SomeDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection("Databases").GetSection("SomeDb")["ConnectionString"]);
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}, ServiceLifetime.Scoped);
services.AddMvcCore().AddNewtonsoftJson();
services.AddControllersWithViews();
}
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)
{
...
IServiceScope scope = provider.CreateScope();
SomeDbContext context = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
SomeModelProxyClass example = new SomeModelProxyClass(context);
await example.BuildDefaults(
Configuration.GetSection("ProfileDefaults").GetSection("Something"),
Configuration.GetSection("ProfileDefaults").GetSection("SomethingSomething"));
scope.Dispose();
}
The above is for doing some default interactions on Startup, maybe if you need to build some default records in your database on a first usage, just as an example.
Ok so let's get to your repository and dependency though, will they work?
Yep!
Here's a test in my own CRUD project, I made a simple minimalist implementation of your IMyDependency and IMyRepository like so, then added them scoped as you did to Startup/ConfigureServices:
public interface IMyRepository
{
string WriteMessage(string input);
}
public interface IMyDependency
{
string GetTimeStamp();
}
public class MyDependency : IMyDependency
{
public MyDependency()
{
}
public string GetTimeStamp()
{
return DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString();
}
}
public class MyRepository : IMyRepository
{
private readonly IMyDependency _myDependency;
public MyRepository(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public string WriteMessage(string input)
{
return input + " - " + _myDependency.GetTimeStamp();
}
}
Here ContextCRUD is a Model class from my own project not derived from Scaffold-DbContext tooling like my other database classes, it's a container of logic from those scaffold Model classes, and so I put it in the namespace Models.ProxyModels to hold its own business logic for doing CRUD operations so that the Controllers are not gummed up with logic that should be in the Model:
public ContextCRUD(DbContext context, IServiceProvider provider)
{
Context = context;
Provider = provider;
var scope = provider.CreateScope();
var dep1 = scope.ServiceProvider.GetService<IMyRepository>();
string msg = dep1.WriteMessage("Current Time:");
scope.Dispose();
}
Debugging I get back the expected results in msg, so it all checks out.
The calling code from the Controller for reference, just so you can see how IServiceProvider is passed from upstream by constructor injection in the Controller:
[Route("api/[controller]")]
public class GenericController<T> : Controller where T: DbContext
{
T Context { get; set; }
ContextCRUD CRUD { get; set; }
IConfiguration Configuration { get; set; }
public GenericController(T context, IConfiguration configuration, IServiceProvider provider)
{
Context = context;
CRUD = new ContextCRUD(context, provider);
Configuration = configuration;
}
...
You can do it, check out [InjectionMethod] and container.BuildUp(instance);
Example:
Typical DI constructor (NOT NEEDED IF YOU USE InjectionMethod) public
ClassConstructor(DeviceHead pDeviceHead) {
this.DeviceHead = pDeviceHead; }
This attribute causes this method to be called to setup DI.
[InjectionMethod] public void Initialize(DeviceHead pDeviceHead) {
this.DeviceHead = pDeviceHead; }