In my app, there is one interface and two subclasses.
Two subclasses have been registered as services.
My question is how to control which one to get when i use them?
HomeController.cs
public class HomeController : Controller
{
public interface ITestDI
{
}
public class TestDIClass1: ITestDI
{
public TestDIClass1()
{
}
}
public class TestDIClass2 : ITestDI
{
public TestDIClass2()
{
}
}
ITestDI td;
public HomeController(ITestDI _td)
{
this.td = _td; // how to control which ITestDI implementation will injected with constructor injection? With the configuration below, always get TestDIClass2.
}
public IActionResult Index()
{
return View();
}
}
Startup.cs
services.AddScoped<ITestDI, TestDIClass1>();
services.AddScoped<ITestDI, TestDIClass2>(); // it seems like TestDIClass2 has overwrited the TestDIClass1.
There are a few options.
First, you can abandon Auto-Wiring and make the registration using a delegate, as follows:
services.AddScoped<TestDIClass1>();
services.AddScoped<TestDIClass2>();
services.AddTransient<HomeController>(c => new HomeController(
_td: c.GetRequiredService<TestDIClass2>());
Here you register both ITestDI by their concrete type. This allows the delegate for HomeController to request a specific implementation using GetRequiredService<T>.
Hand-wiring such object, however, can become cumbersome, especially when HomeController contains more dependencies, because it would require you to resolve all dependencies manually. So instead, you can make use of MS.DI's ActivatorUtilities.CreateInstance class. It implements a simplified form of MS.DI's Auto-Wiring abilities. The following snippet shows this:
services.AddScoped<TestDIClass1>();
services.AddScoped<TestDIClass2>();
services.AddTransient<HomeController>(c =>
ActivatorUtilities.CreateInstance<HomeController>(
c,
new object[]
{
c.GetRequiredService<TestDIClass2>(),
}));
In this example, HomeController is requested from ActivatorUtilities. The CreateInstance call is supplied an IServiceProvider instance (the c argument) and an array of instances to inject into HomeController's constructor. ActivatorUtilities will match the supplied objects to HomeController's constructor arguments and will resolve all missing arguments from the provided IServiceProvider.
The use of ActivatorUtilities.CreateInstance allows your registration to stay unchanged, even if new arguments are added to HomeController's constructor, for instance:
public HomeController(
ILogger logger, // new argument added
ITestDI td,
IProductService service // another argument added
)
ActivatorUtilities.CreateInstance will figure out that the resolved TestDIClass2 can be mapped to the td constructor argument, and it will resolve ILogger and IProductService from the IServiceProvider.
There are other options available, but these are in your case probably the most likely options, in case you don't want to change your design.
This information is an condensed version of the book Dependency Injection Principles. Practices, and Patterns. That contains a complete chapter on Microsoft.Extensions.DependencyInjection (MS.DI) and about 16 pages on Working with multiple components.
It is possible to register concrete class.
public HomeController(TestDIClass2 _td)
{
this.td = _td; //
}
Since you have registered more than one instances, you have to ask Dependency Injection framework for an IEnumerable<ITestDI> _testDis;
and then you have to iterate trough it
foreach(var instance in _testDis)
{
instance.YourMethod();
}
Related
I am going to implement repository pattern in my asp.net core mvc application , for that i am trying my hands on a simple demo application which include repository and Unit of Work concept.
My First Repository
public interface ICustomerRepository
{
bool Add();
bool Update();
bool Delete();
}
and
public class CustomerRepository:ICustomerRepository
{
public bool Add()
{
return true;
}
public bool Update()
{
return true;
}
public bool Delete()
{
return true;
}
}
Second Repository
public interface IOrderRepository
{
bool Add();
bool Update();
bool Delete();
}
and
public class OrderRepository:IOrderRepository
{
public bool Add()
{
return true;
}
public bool Update()
{
return true;
}
public bool Delete()
{
return true;
}
}
IUnit Of Work
public interface IUnitOfWork
{
IOrderRepository Order {get;}
ICustomerRepository Customer { get; }
void Save();
void Cancel();
}
and
public class UnitOfWork:IUnitOfWork
{
public UnitOfWork(IOrderRepository order, ICustomerRepository customer)
{
Order = order;
Customer = customer;
}
public IOrderRepository Order { get; }
public ICustomerRepository Customer { get; }
public void Save() { }
public void Cancel() { }
}
And in my controller ,
public class HomeController : Controller
{
IUnitOfWork UW { get; }
public HomeController(IUnitOfWork uw)
{
UW = uw;
}
public IActionResult Index()
{
UW.Customer.Add();
UW.Order.Update();
UW.Save();
return View();
}
}
I will add more code later for dapper , but at least it should work wiyhout any error , but it give me error
InvalidOperationException: Unable to resolve service for type 'CoreTS.Repository.UnitOfWork.IUnitOfWork' while attempting to activate 'CoreTS.Controllers.HomeController'.
Someone suggested me to add IUnitOfWork as service in startup.cs under ConfigureService Method, as
services.AddSingleton<IUnitOfWork, UnitOfWork>();
And After Adding this another error
InvalidOperationException: Unable to resolve service for type 'CoreTS.Repository.Order.IOrderRepository' while attempting to activate 'CoreTS.Repository.UnitOfWork.UnitOfWork'.
To make it work i had to add other two repository also in startup.cs also
services.AddSingleton<IOrderRepository, OrderRepository>();
services.AddSingleton<ICustomerRepository, CustomerRepository>();
If there going to be n number of repository than i have to add everyone of them in startup.cs (according to this code ), what is the solution for that.
So
1.] What does these errors means ?
2.] What will be the correct configuration here ?
3.] What is the way to not to add n number of repository as service here ?
Note: As a mentioned already , this is just to understand the flow of pattern , i will add code for Dapper or EF Core later in this
What does these errors means ?
These error means that you are using the services through constructor Dependency Injection but you have not registered those services to DI resolver.
What will be the correct configuration here ?
What you have done is the correct way to resolve services.
What is the way to not to add n number of repository as service here?
You can extend the IServiceCollection as follows in a separate file.
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomServices(this IServiceCollection services,
IConfiguration configuration)
{
services.AddSingleton<IUnitOfWork, UnitOfWork>();
services.AddSingleton<IOrderRepository, OrderRepository>();
services.AddSingleton<ICustomerRepository, CustomerRepository>();
return services;
}
}
Then in the startup class as follows:
services.AddCustomServices(Configuration);
The constructor for HomeController takes an IUnitOfWork, so ASP.NET Core needs to know what instance to give it, that's why you specify it in ConfigureServices. But, your UnitOfWork class' constructor takes an IOrderRepository and an ICustomerRepository, and ASP.NET Core needs to know what instances of those to supply, so you have to specify those in ConfigureServices as well.
I think the configuration you've ended up at is correct, as far as it goes, but it doesn't address your next question...
There's already a problem with your pattern without the ASP.NET Core dependency injection issues. Your constructor for UnitOfWork takes 2 distinct parameters, one for each repository. If you want to have N different repositories, that constructor no longer works. Instead, maybe you need to introduce a "repository manager" class and just inject that into the constructor (add it in ConfigureServices too). Then you need to devise a relationship between UnitOfWork and RepositoryManager that allows UnitOfWork to work with any specific repository.
Well, the error message is quite meaningful. The DI container has to resolve the instance of IUnitOfWork which has two dependencies that are injected into its ctor. So DI container has to resolve these two as well.
There is no built-in functionality in asp.net-core that allows you to register all your repositories using pattern matching or something like that. You could register all dependencies one by one or use 3rd party libraries.
With Scrutor you can do something like this:
services.Scan(scan => scan
.FromAssemblyOf<OrderRepository>()
.AddClasses(classes => classes.AssignableTo<IRepository>())
.AsImplementedInterfaces()
.WithSingletonLifetime());
Note that for it to work all repositories must implement IRepository interface (which can be empty)
Conclusion:
If it's only a few dependencies I'd probably register them one by one however if you plan to add N repositories later - use 3rd party libs.
There is no service registered in the IoC container for IUnitOfWork/IOrderRepository. You solved this by registering these services using AddSingleton method.
Not sure what you mean by correct configuration, but using AddSingleton/AddTransient/AddScoped you are registering some classes as services in the IoC container. So when you inject something (for example into your HomeController), then you are using the interface mapped to some concrete implementation.
You have to register the service somehow, that is what you are doing with methods mentioned before. If you won't register it, it won't be resolved and you will get exceptions when trying to activate some other dependent services. If you want to register some services without doing it explicitely, you will have to scan the assembly and look for types that you want to register.
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>());
I am configuring AutoMapper to map domain objects from / to the view model ones in a Asp.Net MVC5 application with Autofac 4.3, Autofac.Owin 4, Autofac.Mvc5 4, AutoFac.Mvc5.Owin 4 and AutoMapper 5.2.
I did decide to create one AutoMapper profile per domain entity like the followin leaving only the constructor with no parameters because I want to set the profile's name.
Note: this code is in assembly A.
public partial class DoctorsMappingProfile : Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
// Code of mapping removed because it is not part of the problem
}
#endregion Constructors
}
To register AutoMapper and the profiles I followed this and this guides well explained by the user mpetito there and that it works as the user has checked here. My code in the Startup partial class is this:
Note1: this code is in assembly B which references assembly A.
Note2: I perfom assembly scanning of registered assemblies, then I pass as paramerter the array of scanned assemblies to the method RegisterAssemblyTypes of ContainerBuilder
public partial class Startup
{
#region Methods
public void ConfigureAutoFacContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterFilterProvider();
builder.RegisterSource(new ViewRegistrationSource());
// TODO: Logger!
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
this.ConfigureAutoMapper(builder, assemblies);
// TODO: Modules!
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>(); //.UsingConstructor(typeof(string));
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
#endregion Methods
}
When de application runs and try to resolve the profile the following exception happens:
Autofac.Core.DependencyResolutionException
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'AutoMapper.Configuration.MapperConfigurationExpression+NamedProfile' can be invoked with the available services and parameters: Cannot resolve parameter 'System.String profileName' of constructor 'Void .ctor(System.String, System.Action`1[AutoMapper.IProfileExpression])'.
the line of the error is the foreach loop when the context attempts to resolve the Profile:
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
I believe it its due to the Autofac default constructor location convention it is looking for the constructor with most parameters, which is in case of the AutoMapper.Profile class:
protected Profile(string profileName, Action<IProfileExpression> configurationAction)
{
}
To fix this I replaced the line that looks for profiles, the first line of code in in ConfigureAutoMapper, forcing it to use the constructor with no parameters:
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>().UsingConstructor();
but still it does not work.
Solutions / workaround I have found:
If I replace the class Profile by my DoctorsMappingProfile in method ConfigureAutoMapper it works but doing this will invalidate the assembly scanning for profiles.
Finally I managed it to work by creating a base abstract class inheriting from AutoMapper.Profile and referencing it in my ConfigureAutoMapper method of the Startup class, this way I can perform assembly scanning for that class' descendants...
Note: this code is in Assembly C
public abstract class G2AutoMapperProfile : Profile
{
#region Constructors
protected G2AutoMapperProfile()
{
}
protected G2AutoMapperProfile(string profileName) : base(profileName)
{
}
#endregion Constructors
}
Note: And this code is in assembly A
public partial class DoctorsMappingProfile : G2AutoMapperProfile //Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
//removed because it is not part of the problem
}
#endregion Constructors
}
and finally, this is the code of ConfigureAutoMapper in assembly B, that works:
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(G2AutoMapperProfile)).As<G2AutoMapperProfile>();
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve<IEnumerable<G2AutoMapperProfile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
... but still I don't understand why the original code is not working for me.
First, there's no need for you to explicitly call the protected constructor of Profile in your DoctorsMappingProfile. The reason is that the profileName you pass is the one used by default by AutoMapper as we can see here.
Also, regarding the first way you try to register your profiles in the Autofac container:
builder
.RegisterAssemblyTypes(registeredAssemblies)
.AssignableTo(typeof(Profile))
.As<Profile>()
.UsingConstructor(typeof(string));
This means that you explicitly ask Autofac to create instance of your Profile classes by using the constructor that has exactly one parameter that is of type string. The problem with that is Autofac has no idea what string it has to use in the constructor.
It's also wrong since you created a parameter-less constructor which in turn calls the parameterized constructor.
I'm not sure what calling UsingConstructor with no parameters does, but in my opinion, you'd be better off leaving Autofac choose the best constructor for you, especially when the defaut parameter-less one is the one you want it to use.
My feeling is reinforced by looking at the solution/workaround you provided. What you effectively did is:
create a base class that mimics exactly what Profile has, that is, a default parameter-less constructor and a constructor that takes a string
register the profiles in the Autofac container by not using UsingConstructor
So I'm quite sure that by:
getting rid of your custom base class
having your profiles inherit from Profile again
registering your profiles without using UsingConstructor
you should be fine.
I'm trying to Inject a dependency into a controller which inherits from Umbraco's RenderMvcController and getting the error
No registration for type RenderMvcController could be found and an implicit registration could not be made. For the container to be able to create RenderMvcController it should have only one public constructor: it has 3. See https://simpleinjector.org/one-constructor for more information.
Below is my code to wire up the DI
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
private static void InitializeContainer(Container container)
{
container.Register<ICacheProvider, CacheProvider>(Lifestyle.Transient);
container.Register<ICacheService, CacheService>(Lifestyle.Transient);
}
This is an example of a class receiving the dependency, it inherits from a base class I wrote
public class NewsroomController : BaseRenderMvcController
{
public NewsroomController(ICacheService cacheService) : base(cacheService) { }
The base class extends RenderMvcController which is an Umbraco Controller
public class BaseRenderMvcController : RenderMvcController
{
public ICacheService CacheService { get; set; }
public BaseRenderMvcController(ICacheService cacheService)
{
CacheService = cacheService;
}
}
As you can see the base Umbraco controller does in fact have 3 different constructors
public class RenderMvcController : UmbracoController, IRenderMvcController, IRenderController, IController
{
public RenderMvcController();
public RenderMvcController(UmbracoContext umbracoContext);
public RenderMvcController(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper);
I'm not sure how to get SimpleInjector to place nicely with this controller inherited from Umbraco.
Thanks in advance!
The exception message "No registration for type RenderMvcController could be found and an implicit registration could not be made" means that the RenderMvcController type is requested directly from Simple Injector, while it hasn't been registered. A controller type is usually only requested by the DefaultControllerFactory and it will only request a specific type when it gets a request that has the name of the controller in its url, as in: http:\\localhost\RenderMvc\3.
Since you stated in the comments that the RenderMvcController is only meant to be used as base controller, I find it suspicious that it is actually requested by MVC. I think you should look into that.
But it the use of this controller is really required, you can simply register it in Simple Injector like this:
container.Register<RenderMvcController>(() => new RenderMvcController());
There are ways to override Simple Injector's constructor resolution behavior, but I would advise against doing this, because it is an anti-pattern for components to have multiple constructors. It's wise to don't use a container's auto-wiring behavior on framework types (as explained here), so registering them using a lambda is the advised practice.
I've run into an interesting design issue with a class library I am writing. I have a custom implementation of the AuthorizeAttribute that I want clients to be able to use like this:
[Protected("permission_name")]
In the above code, PermissionAttribute inherits from AuthorizeAttribute and uses a local default (DefaultContext created using HttpContext).
Behind the scenes, the attribute uses a SecurityService to check users, roles and permissions against (the SecurityService itself uses a client-provided persistence service that they can wire up in the composition root of their app).
So my attributes need a reference to the SecurityService to function. Since Attribute constructors can only have compile-time constants, I cannot use constructor injection.
I don't want to force my clients to use a DI framework - they should be able to discover and wire up the necessary dependencies in their composition root without using an IoC library, if they so choose.
Here are my options:
Have the library use a singleton SecurityService.
Use property injection, which would work but
it would make the dependency seem optional, which it is not and
I don't know where I can do property injection in an MVC app on an authorize attribute.
A possible solution to 2. above is to do set an instance of SecurityService as a static property on the attribute at application startup and use a guard clause to prevent it from being set more than once, like this:
class ProtectedAttribute : ...
{
private static ISecurityService _SecurityService ;
public static ISecurityService SecurityService
{
get
{
return _SecurityService ;
}
set
{
if (_SecurityService != null)
throw new InvalidOperationException("You can only set the SecurityService once per lifetime of this app.") ;
_SecurityService = value ;
}
}
}
The SecurityService could be an abstract service facade so that it can be extended/replaced by a different implementation.
Is there a better way to solve this problem?
UPDATE: Adding some code to show how I am going to do it:
Add a public property on the attribute that returns the permission name:
public class ProtectedAttribute : ...
{
private string _Permission ;
public string Permission { get { return _Permission ; } /*...*/ }
public ProtectedAttribute(string permission) { /*...*/ }
}
Setup an authorization filter and configure dependency via Ninject (if using Ninject):
using Ninject.Web.Mvc.FilterBindingSyntax;
public class MyModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
// mySecurityService instance below can have a singleton lifetime - perfect!
this.BindFilter<MyAuthorizationFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<ProtectedAttribute>()
.WithConstructorArgument("securityService", mySecurityService)
.WithConstructorArgumentFromActionAttribute<ProtectedAttribute>("permission", p => p.PermissionName) ;
}
}
Ohhh it's...beautiful sniffle
With ASP.NET MVC 3 you could use constructor injection with action filters thanks to the new IFilterProvider. This way you no longer need to decorate your controller actions with action filters. You could apply them thanks to this interface and using a marker attribute.
And if you don't wanna bother implementing it manually you could always use an existing DI framework such as Ninject which provides a fluent way to define action filter dependencies.
My applications inherit from a base Application class that exposes the IOC container.
public interface IInjectableApplication
{
IUnityContainer Container { get; }
}
Then I have a base attribute class, which is aware of this
public abstract IocAwareActionFilterAttribute : ActionFilterAttribute{
protected T ResolveItem<T>(ResultExecutedContext context)
{
var app = context.HttpContext.ApplicationInstance as IInjectableApplication;
if (app == null) { throw new NullReferenceException("Application is not IInjectable."); }
T c = (T)app.Container.Resolve(typeof(T));
if (c == null) { throw new NullReferenceException(string.Format("Could not find injected {0}.", typeof(T).FullName)); }
return c;
}
}
While this is not true Injection, since Attributes aren't constructed 'normally', this provides a similar behavior. No reason it should not be adaptable to other IOCs