I am looking for a DI framework that can satisfy this scenario:
Every Controller has a constructor like this
public ThisController( ThatRepository repo)
Every Repository has a controller like this:
public ThatRepository (DataSource ds)
There is one master DataSource, but that is never passed to the repository. Instead it needs:
MasterDataSource.WithUser ( httpContext?.User?.Identity?.Name )
Are there any DI frameworks for WebAPI that would support this out of the box?
I believe that you could use almost every DI container for such a purpose, by registering current HttpContext (or even the current user Identity) inside the container and then injecting it for constructing your DataSource instance.
Here it is a simple solution using HttpContext in SimpleInjector (you may easily port the code to any DI framework you like):
container.Register<HttpContextBase>(() =>
new HttpContextWrapper(HttpContext.Current),
Lifestyle.Scoped);
container.Register<DataSource>(() =>
{
var httpContext = container.GetInstance<HttpContextBase>();
return MasterDataSource.WithUser(httpContext?.User?.Identity?.Name);
},
Lifestyle.Scoped);
Abstract the HttpContext behind an interface you control and have your DI container of choice resolve that when needed.
public interface ICurrentUser {
string Name{get;}
}
A concrete implementation of that interface can look like...
public class UserProvider : ICurrentUser {
HttoContextBase httpContext;
UserProvider(){
httpContext = HttpContext.Current;
}
public string Name {
get{ return httpContext?.User?.Identity?.Name ?? string.Empty; }
}
}
You register your interface/contract with your DI container and resolve it when needed for your DataSource.
public void SomeSetupMethod(ICurrentUser user) {
MasterDataSource.WithUser(user?.Name);
}
Related
In my Asp.Net MVC Core project I use SimpleInjector as IoC. I use it because of possibility of registering open generics.
In some of my viewmodels I implement IValidatableObject.
public class MyViewmodel: IValidatableObject
{
public string SomeProperty { get;set; }
//...
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//...
IMyService service = validationContext.GetService(typeof(IMyService)) as IMyService;
}
}
And method GetService returns null because IMyService was registered in application by SimpleInjector.
In my controller I use such a validation:
[HttpPost]
public async Task<IActionResult> Edit(MyViewmodel model)
{
if (ModelState.IsValid)
{
//...
}
return View(model);
}
So, is there way to get IMyService from Asp.Net Core IServiceProvider in ValidationContext?
Although there is nothing inherently wrong with placing validation logic inside the model object itself, problems start to appear when that validation logic requires services to work. In that case you'll end up applying the Service Locator anti-pattern (by calling validationContext.GetService).
Instead, when it comes to more complex validations that require services to run, it's much better to separate data and behavior. This allows you to move the validation logic to a separate class. This class can apply Constructor Injection and, therefore, doesn't have to use any anti-patterns.
To achieve this, start off with your own abstraction that can validate instances. For instance:
public interface IValidator<T>
{
IEnumerable<string> Validate(T instance);
}
On top of this abstraction, you can define as many implementations as you will, for instance one (or more) for validating MyViewmodel:
public class MyViewmodelValidator : IValidator<MyViewmodel>
{
private readonly IMyService service;
public MyViewmodelValidator(IMyService service) => this.service = service;
public IEnumerable<string> Validate(MyViewmodel instance)
{
yield return "I'm not valid.";
}
}
This is all the application code you need to get things in motion. Of course you should model the IValidator<T> interface according to your application needs.
Only thing left is ensure MVC uses these validators when validating your view models. This can be done with a custom IModelValidatorProvider implementation:
class SimpleInjectorModelValidatorProvider : IModelValidatorProvider
{
private readonly Container container;
public SimpleInjectorModelValidatorProvider(Container container) =>
this.container = container;
public void CreateValidators(ModelValidatorProviderContext ctx)
{
var validatorType = typeof(ModelValidator<>)
.MakeGenericType(ctx.ModelMetadata.ModelType);
var validator =
(IModelValidator)this.container.GetInstance(validatorType);
ctx.Results.Add(new ValidatorItem { Validator = validator });
}
}
// Adapter that translates calls from IModelValidator into the IValidator<T>
// application abstraction.
class ModelValidator<TModel> : IModelValidator
{
private readonly IEnumerable<IValidator<TModel>> validators;
public ModelValidator(IEnumerable<IValidator<TModel>> validators) =>
this.validators = validators;
public IEnumerable<ModelValidationResult> Validate(
ModelValidationContext ctx) =>
this.Validate((TModel)ctx.Model);
private IEnumerable<ModelValidationResult> Validate(TModel model) =>
from validator in this.validators
from errorMessage in validator.Validate(model)
select new ModelValidationResult(string.Empty, errorMessage);
}
The only thing left to do is add SimpleInjectorModelValidatorProvider to the MVC pipeline and make the required registrations:
services.AddMvc(options =>
{
options.ModelValidatorProviders.Add(
new SimpleInjectorModelValidatorProvider(container));
});
// Register ModelValidator<TModel> adapter class
container.Register(typeof(ModelValidator<>), typeof(ModelValidator<>),
Lifestyle.Singleton);
// Auto-register all validator implementations
container.Collection.Register(
typeof(IValidator<>), typeof(MyViewmodelValidator).Assembly);
Et voila! There you have it—a completely loosely coupled validation structure that can be defined according to the needs of your application, while using best practices like Constructor Injection and allows your validation code to be fully tested without having to resort to anti-patterns, and without being tightly coupled with the MVC infrastructure.
An amazing answer from #Steven, but for those of you wondering how to adapt it to the built-in dependency injection mechanism using IServiceProvider instead of a Container from some other library, and are stuck at
services.AddMvc(options =>
{
options.ModelValidatorProviders.Add(
new SimpleInjectorModelValidatorProvider(/* TODO how do I get the IServiceProvider */));
});
The secret sauce is to create yet another class that configures the MvcOptions and gets an IServiceProvider injected into it:
public class ConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
private readonly IServiceProvider provider;
public ConfigureMvcOptions(IServiceProvider provider)
{
this.provider = provider;
}
public void Configure(MvcOptions options)
{
options.ModelValidatorProviders.Add(new SimpleInjectorModelValidatorProvider(this.provider));
}
}
and then you can register that in Startup.cs in the usual way:
services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
Is it possible to set up injection scopes for the default DI in Asp.Net Core? I mean For example:
services.AddSingleton<IUser, UserService>
services.AddSingleton<IUser, UserService>
And for the second configuration somehow specify that it should be injected into only HomeController. Unlike the first one should be injected to all others. Is it possible with default DI?
I answered a similar question here but using scoped instead of singleton:
How to register multiple implementations of the same interface in Asp.Net Core?
My gut feeling is that this might be what you're trying to achieve, or might be a better approach, and you might be mixing up the User with the UserService. When you have multiple implementations of the same interface DI will add these to a collection, so it's then possible to retrieve the version you want from the collection using typeof.
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(IUserService, UserServiceA);
services.AddScoped(IUserService, UserServiceB);
services.AddScoped(IUserService, UserServiceC);
}
// Any class that uses the service(s)
public class Consumer
{
private readonly IEnumerable<IUserService> _myServices;
public Consumer(IEnumerable<IUserService> myServices)
{
_myServices = myServices;
}
public UserServiceA()
{
var userServiceA = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceA));
userServiceA.DoTheThing();
}
public UserServiceB()
{
var userServiceB = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceB));
userServiceB.DoTheThing();
}
public UseServiceC()
{
var userServiceC = _myServices.FirstOrDefault(t => t.GetType() == typeof(UserServiceC));
userServiceC.DoTheThing();
}
}
Assuming this registration, how should the dependency injection container possibly know which “singleton” (it’s not really a singleton when there are two of them) it should inject into the HomeController, or a different service, when they are all just depend on IUser?
The type the dependency gets registered as, in your case IUser, is the “key” which DI containers use to resolve the dependency. So two services that both depend on IUser will get their dependency resolved in the same way. With a singleton lifetime, this means that both services get the same instance.
Service registrations are also usually replacing. So if you have one registration AddSingleton<X, Y>() and then have another one AddSingleton<X, Z>(), then the latter will replace the former. So all services dependending on X will receive Z.
DI containers, including the default container that ships with ASP.NET Core, do usually support resolving all registrations by depending on IEnumerable<X> instead. But for this example this just means that a services would get both Y and Z.
The closest thing you are looking for are keyed or named dependencies. While these are supported in some DI containers, they are technically not part of dependency injection and as such often deliberately absent from many containers, including the ASP.NET Core one. See this answer for more details on that and for some idea to get around that.
To get back to your use case, you should really think about what you are actually doing there. If you have two “singleton” instances of UserService, you should really think about why that is the case: Why isn’t there just one? And if there is support for multiple, why not register it as transient?
More importantly, what would possibly differ between those two instances? After all, they are both instances of the same implementation, so there isn’t much that they can do differently.
If you can identify that, and also confirm that this is something that actually makes the instances different, then consider splitting this up in the type hierarchy as well. It’s difficult to explain this without having a use case here, but what you should try is to end up with two different interfaces that each do exactly what each dependent service type needs. So HomeController can depend on IUserA, and others can depend on IUserB (please choose better names than this).
I have the similar issue. There is my solution.
On the top level in controller I use custom attribute for the action, where I need specific service implementation (for reports for example):
public class HomeController : ControllerBase
{
private readonly IService _service;
public HomeController(IService service)
{
_service = service;
}
[HttpGet]
[ReportScope]
public IEnumerable<WeatherForecast> Get()
{
_service.DoSomeThing();
}
This attribute is processed by custom middleware:
public class ReportScopeLoggingMiddleware
{
private readonly RequestDelegate _next;
public ReportScopeLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, ReportScopeContext scopeContext)
{
var controllerActionDescriptor = context
.GetEndpoint()
.Metadata
.GetMetadata<ControllerActionDescriptor>();
bool analytical = controllerActionDescriptor.EndpointMetadata.Any(m => m is ReportScopeAttribute);
if (analytical) scopeContext.SetActive();
await _next(context);
}
}
In this middleware I use ReportScopeContext.
public class ReportScopeContext
{
public bool Active { get; private set; } = false;
public void SetActive()
{
Active = true;
}
}
This ReportScopeContext has scoped lifetime in DI and I use it to select an implementation of IService:
services.AddScoped<ReportScopeContext>();
services.AddTransient<Service2>();
services.AddTransient<Service1>();
services.AddTransient<IService>(sp =>
sp.GetRequiredService<ReportScopeContext>().Active
? sp.GetRequiredService<Service1>()
: sp.GetRequiredService<Service2>());
Within my Web API I have linked Autofac as IoC container, and I do it like this:
Domain level
public class Autofac
{
protected ContainerBuilder Builder { get; set; }
public Autofac()
{
this.Builder = new ContainerBuilder();
}
public virtual IContainer Register()
{
// Register dependencies
SetUpRegistration(this.Builder);
// Build registration.
var container = this.Builder.Build();
// End
return container;
}
private static void SetUpRegistration(ContainerBuilder builder)
{
// === DATALAYER === //
// MyRepository
builder.RegisterType<MyRepository>()
.As<IMyRepository>()
.InstancePerLifetimeScope();
// === DOMAIN === //
// MyManager
builder.RegisterType<MyManager>()
.As<IMyManager>()
.InstancePerLifetimeScope();
}
}
Web API
public class Autofac : Domain.IoC.Autofac
{
public IContainer Register(HttpConfiguration config)
{
// Register your Web API controllers.
base.Builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
base.Builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
// Complete registration and get container instance.
var container = base.Register();
// Set the dependency resolver to be Autofac.
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Done.
return container;
}
}
As you see it inherits from the base class from Domain and sets up Web API specific config.
Usage
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new IoC.Autofac().Register(GlobalConfiguration.Configuration);
}
Which is at global.asax, as you know.
The question
This works fine for Web API, but I haven't got a clue what I need to do to register all this within a UnitTest project context.
The idea is that I would create a similar implementation to the Autofac class at Web API level, but than with mocks (completely ignoring the base class from Domain).
Any pointers?
Personally I never see the need (and I struggle to comprehend how viable or helpful it would be) to setup my IoC container directly within a unit test.
As a unit test is used to test a logical piece of code that can be quickly built, easily ran and doesn't require much (I'd advocate no) tear-down. It should not require all of your application to be be setup for the test to run.
Remember that your unit test is simply testing the flow of data through the system i.e that your DomainManager is actually going to call a IRepository when you expect that it should. Then you would have separate test classes for all your repositories to determine that they would correctly add to the database etc.
I'm not sure how you use the DBContext class but as an example of a wrapper this is what it would sort of look like.
interface IDBSetWrapper
{
object Add(object entity);
}
interface IDBContextWrapper
{
...
IDBSet Set(Type entityType);
...
}
class DBContextWrapper : IDBContextWrapper
{
private readonly DBContext context;
public DBContextWrapper()
{
context = new DBContext();
}
...
public IDBSet Set(Type entityType)
{
var dbSet = context.Set(entityType);
return new DBSetWrapper(dbSet);
}
...
}
It's not much but I hope that it demonstrates what I mean about a thin wrapper. Basically the wrapper is the DBContext and will contain an instance of it within the class, the actual DBContext will be called when you request the wrapper to do anything.
I have shown what would happen when returning another object (in this case a DBSet), this will also be wrapped in a separate object with an interface. This is so that you can mock the returns from this class easily.
You can add this new wrapper into your IoC a little better now as it provides an interface.
One thing to note is that you won't be able to and probably wouldn't wish to test the wrapper class, there would be very little point as I see it. But previously I've seen colleagues do an integration test on these sort of classes.
I have the following classes / interfaces:
public interface IProjectRepository
{
IQueryably<Project> GetProjects();
}
// Depends on my EF Context
public ProjectRepository : IProjectRepository
{
private MyDbEntities context;
public ProjectRepository(MyDbEntities context)
{
this.context = context;
}
public IQueryable<Project> GetProjects()
{
return context.Projects;
}
}
My controller:
// Depends on IProjectRepository
public class ProjectsController : Controller
{
private IProjectRepository projectRepository;
public ProjectsController(IProjectRepository projectRepository)
{
this.projectRepository = projectRepository;
}
public ActionResult Index()
{
return View(projectRepository.GetProjects());
}
}
I need to set up my dependency injection so that it passes in ProjectRepository into my Controller AND it needs to pass in my Entity Framework context into the Project Repository. I need to Entity Context to be HTTP Request scoped.
I'm not sure where I am supposed to put all the mapping code to make the dependency injection work. I also don't understand how MVC will work without the default constructor.
Can someone help me put all the pieces together? I am using StructureMap but I could easily switch to something else because I have no idea what I'm doing.
If you are using MVC 3, to do things properly, you should make use of the built in dependency resolution bits. I would highly recommend you read through the series of blog posts from Brad Wilson (member of the ASP.NET MVC team).
As far as a StructureMap specific implementation, I found the following blog posts helpful.
StructureMap and ASP.NET MVC 3 – Getting Started
StructureMap, Model Binders and Dependency Injection in ASP.NET MVC 3
StructureMap, Action Filters and Dependency Injection in ASP.NET MVC 3
StructureMap, Global Action Filters and Dependency Injection in ASP.NET MVC 3
Anyway, here's some code. To start with, I would suggest that you install the StructureMap-MVC3 NuGet package.
I can't remember what exactly it creates in the way of files, but here's what's basically involved.
/App_Start/StructuremapMvc.cs - This hooks into the Application_Start and sets up your container (SmIoC.Initialize()) and then sets the MVC 3 DependencyResolver to a your SmDependencyResolver
using System.Web.Mvc;
using YourAppNamespace.Website.IoC;
using StructureMap;
[assembly: WebActivator.PreApplicationStartMethod(typeof(YourAppNamespace.App_Start.StructuremapMvc), "Start")]
namespace YourAppNamespace.Website.App_Start {
public static class StructuremapMvc {
public static void Start() {
var container = SmIoC.Initialize();
DependencyResolver.SetResolver(new SmDependencyResolver(container));
}
}
}
/IoC/SmDependencyResolver.cs - this is your MVC 3 IDependencyResolver implementation. It's used in the App_Start code above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace YourAppNamespace.Website.IoC
{
public class SmDependencyResolver : IDependencyResolver
{
private readonly IContainer _container;
public SmDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType == null)
{
return null;
}
try
{
return _container.GetInstance(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType).Cast<object>(); ;
}
}
}
/IoC/SmIoC.cs - this is where you setup your container... also used in the App_Start code.
namespace YourAppNamespace.Website.IoC
{
public static class SmIoC
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
//etc...
});
return ObjectFactory.Container;
}
}
}
Now everything is hooked up... (I think ;-) but you still have one last thing to do. Inside your Global.asax, we need to make sure you dispose of everything that is HttpContext scoped.
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
So you should be able to achieve dependency injection through constructor injection, which is the correct way to go about doing things.
If you are set on using StructureMap, here is a tutorial on the setup that you will probably need.
Some other dependency injection frameworks come with custom controller factories which will do that for you. Ninject (open source dependency injection), for example has an extension that you can use that contains this behaviour. See here for example. And here to the extension.
You can use also Unity IOC which is another popular dependency injection framework with which, to my knowledge, you will have to create a custom controller factory (like with structuremap) to achieve this behaviour. See here for an example.
You can also research all other dependency injection frameworks to see what support you can get with each.
EDIT:
I hope I am explaining this correctly but here is some background info.
MVC uses a controller factory that has the responsibilities of instantiating the respective controllers needed when a request is made. By default, it will initialize a controller by calling its parameterless constructor.
To create the infrastructure for the constructor parameter injection you need to create a custom factory that can resolve constructor parameters. That is where the dependency injection containers come in: essentially the DI container (if configured properly) knows how to resolve those dependency and your custom factory will leverage it to request the registered dependencies and pass the to the controller constructor.
All work pretty much the same. Historically, all have had setter injectors (set up a property that is then filled), but most have constructor injection now. In structure map, the easiest way to accomplish this is use the attribute: [StructureMap.DefaultConstructor].
Once you add the attribute, the objects you have placed in your "map" should inject without any extra work. If you can't use attributes, consider using the setter.
There is a file on the structure map site:
http://structuremap.net/structuremap/ConstructorAndSetterInjection.htm
When using StructureMap I would generally have something like this in my controller:
private static IProjectRepository GetProjectRepository()
{
var retVal = ObjectFactory.TryGetInstance<IProjectRepository>()
?? new ProjectRepository();
return retVal;
}
If the TryGetInstance returns null (because nothing was set for that type) it will default to the concrete type you specify.
Now you have a bootstrapper somewhere like this:
public static class StructureMapBootStrapper
{
public static void InitializeStructureMap()
{
ObjectFactory.Initialize(x =>
{
x.For<IProjectRepository>().Use<ProjectRepository>();
}
}
}
Now you call this bootstrapper in your Global.asax Application_Start event:
protected void Application_Start()
{
StructureMapBootStrapper.InitializeStructureMap();
}
Now in a test project, when you want to inject a mock repository you can just do this:
[TestMethod]
public void SomeControllerTest()
{
StructureMap.ObjectFactory.Inject(
typeof(IProjectRepository),
new MockProjectRepository());
// ... do some test of your controller with the mock
}
I have implemented my mvc base controller called DefaultController using dependency injection pattern in order to be able to construct test cases. Example below:
public class DefaultController : Controller
{
protected readonly ISessionHelper _sessionHelper;
string _thisUserOpenID;
protected IUsersRepository _UserRepository;
...
public DefaultController()
{ } //not for testing
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper=session;
_UserRepository = repo;
}
}
Then I have my controllers using this controller, homecontroller, usercontroller, etc.
Now, building some test cases I found myself in a situation where I don't know how to actually use the injection dependency pattern.
[TestMethod]
public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
{
// Below I want to insert FakeRepositories using
//ISessionHelper and so on. but the constructor
//for homecontroller don't have it.
HomeController controller = new HomeController();
Any ideas?
Your HomeController needs to have a matching "injectable" constructor, which would then call the base constructor.
public HomeController(ISessionHelper session, IUserRepository repo)
: base(session, repo)
{
}
Now, in your test, you would create your HomeController using that constructor, and pass in a mocked up session and user repository. Speaking of mocking, you might also be interested in Scott Hanselman's MvcMockHelpers classes, with code for many popular mocking frameworks.
I don't see why you have two constructors. You should only have one, get rid of the constructor with no parameters. Using a DI framework like Castle Windsor, or my preferred one, Autofac will handle all of this for you. Then as far as testing is concerned use something like Moq. Ie
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper = session;
_UserRepository = repo;
}
Register DefaultController, ISessionHelper and IUserRepository with your DI framework. Something along the lines of:
Register(new DefaultController()); (it is something like that in Autofac)
Register<SessionHelper>().As<ISessionHelper>();
Register<UserRepository>().As<IUserRepository>();
That way, you can pull DefaultController from the container and the DI framework will inject the two parameters for you. I wrap up a static method to access my DI container, it looks like:
var controller = IoC.Resolve<DefaultController>();
Basically head over to Autofac and have a look. There's also a web module for registering your Controllers for you.
Then for testing just use Moq, or find some form of "AutoMocker" (google it). I would do:
var session = new Mock<ISessionHelper>();
var repo = new Mock<IUserRepository>();
repo.Setup(s => s.FindById(123)).Returns(new User());
var conroller = new DefaultController(session.Object, repo.Object);
controller.Execute();
Also ewww repositories. With .Net and generics etc... just create yourself an nice ISession.
var session = IoC.Resolve<ISession>();
var user1 = session.Get<User>(123);
var user2 = session.Get<User>(u => u.Username == "admin");
session.Update(user3);
Means you only need to pass in one thing and you can use it for whatever. Rather than having to pass in sometimes many repositories. Also sets you up nicely for the Unit Of Work pattern.