How to use FluentValidation with LightInject in asp.net web-api project - c#

I'm trying to inject a service using the IoC container into a Validation class. See the example below:
[Validator(typeof(UserPayloadValidator))]
public class UserPayload
{
public int UserId { get; set; }
}
public class UserPayloadValidator : AbstractValidator<UserPayload>
{
private IUserService _userService;
public UserPayloadValidator(IUserService userService)
{
_userService = userService;
RuleFor(x => x.UserId).Must(BeUnique).WithMessage("This user already exists");
}
private bool BeUnique(int userId)
{
var user = _userService.GetUser(userId);
return user == null;
}
}
At this point I was hoping everything would auto-magically work and the userService would be injected into the validation class. Instead, I get an exception complaining about a parameter-less constructor not being found.
After some reasearch I've attempted to create a ValidationFactory as in the example linked.
public class LightInjectValidationFactory : ValidatorFactoryBase
{
private readonly ServiceContainer _serviceContainer;
public LightInjectValidationFactory(ServiceContainer serviceContainer)
{
_serviceContainer = serviceContainer;
}
public override IValidator CreateInstance(Type validatorType)
{
return _serviceContainer.TryGetInstance(validatorType) as IValidator;
}
}
and in the LightInject configuration
//Set up fluent validation
FluentValidationModelValidatorProvider.Configure(httpConfiguration, provider =>
{
provider.ValidatorFactory = new LightInjectValidationFactory(container);
});
This results in an exception:
Unable to resolve type: FluentValidation.IValidator`1
I guess the IoC container doesn't know how to resolve the correct instance for the validator.
Any ideas are much appreciated.

Thanks to the comment above I realized I wasn't actually registering the validator in container. This can be done like this for all the validators:
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
Please note that UserPayloadValidator needs to be just one of your validators. Based on this type, FindValidatorsInAssembly can infer all the other available validators.
Also, in the validation factory you should use TryGetInstance instead of GetInstance in case the factory tries to instantiate non existant validators (parameter in the controller for which validators do not exist)

I have found solution for all validation classes use injected service.
Replace below code
FluentValidation.AssemblyScanner.FindValidatorsInAssemblyContaining<UserPayloadValidator>()
.ForEach(result =>
{
container.Register(result.InterfaceType, result.ValidatorType);
});
With
FluentValidation.AssemblyScanner findValidatorsInAssembly = FluentValidation.AssemblyScanner.FindValidatorsInAssembly(typeof(UserPayloadValidator).Assembly);
foreach (FluentValidation.AssemblyScanner.AssemblyScanResult item in findValidatorsInAssembly)
{
container.Register(item.InterfaceType, item.ValidatorType);
}
Using this your all validator classes use injected service.

Related

Set the type of registered Service during runtime within an action filter/message handler

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.

Dependency Injection in Model classes (entities)

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

How to inject something in custom validator?

I'm using CustomValidation for one entity and I want to inject Repository in it. Validation method must be static. Is there any way to inject object in static context other than service location?
Here's my metadata:
[MetadataTypeAttribute(typeof(BillPosition.BillPositionsMetadata))]
[CustomValidation(typeof(BillPositionValidator), "ValidateBillPositionsCount")]
public partial class BillPosition
{
internal sealed class BillPositionsMetadata
{
private BillPositionsMetadata() { }
public int BillId { get; set; }
}
}
Here's validator code:
public class BillValidator
{
[Inject]
public static IRepository Repository { get; set; }
public static ValidationResult ValidateBillPositionsCount(BillPosition bill, ValidationContext context)
{
ValidationResult result = ValidationResult.Success;
/* Repository wasn't injected and I get null reference exception */
var billPositions = Repository.BillPositions.Count(position => position.BillId == bill.BillId);
if (bill.BillPositions.Count == 0 && billPositions == 0)
{
result = new ValidationResult("Invalid positions count", new[] { "BillPositions" });
}
return result;
}
}
There is not any way to inject into custom validators. A Service Locator or some form of reflection could be used to either access a property or method on the instance the validator is being executed on. You can access this instance through the ValidationContext.
http://www.jaltiere.com/index.php/2010/05/04/ninject-with-mvc-and-validationattributes/
You can just call the IoC and resolve the dependency. Like I am using Unity. In these cases I would call Bootstrapper.Unity.Resolve("NameOfMyDependency")
If you are not resolving the validator from the dependency injection container, you can still resolve the repository directly using some kind of service locator:
public class BillValidator
{
static BillValidator()
{
Repository = ServiceLocator.Current.GetInstance<IRepository>();
}
public static IRepository Repository { get; set; }
}
That way you can initialize the validator using the new-keyword:
var validator = new BillValidator();
and you still get the dependency resolved in the validator.
Due to the fact that the repository gets resolve in the type initializer it will be executed only once per type in your applcation. All instances of the validator will use the same repository.
This code works when working with Unity, but should be equivalent when working with MEF or other containers.

StructureMap Setter Injection not setting property

I am trying to setup setter/property injection for my MVC project using StructureMap, but I can't seem to get it to set the properties. I am well aware that Constructor injection is the recommended practice, but I have a strict requirement that requires we do it using setter injection, so please hold the comments attempting to tell me otherwise.
I have the normal boilerplate setup code such as the following in my Global.asax
ControllerBuilder.Current.SetControllerFactory(new TestControllerFactory());
ObjectFactory.Initialize(x => {
x.For<IPaymentService>().Use<PaymentService>();
x.ForConcreteType<HomeController>().Configure.Setter<IPaymentService>(y => y.PaymentService).IsTheDefault();
x.SetAllProperties(y =>
{
y.OfType<IPaymentService>();
});
});
My TestControllerFactory looks like the following:
public class TestControllerFactory:System.Web.Mvc.DefaultControllerFactory
{
protected IController GetControllerInstance(Type controllerType)
{
if (controllerType == null)
throw new ArgumentNullException("controllerType");
return ObjectFactory.GetInstance(controllerType) as IController ;
}
}
I have the following Service/Implementation class pair
public interface IPaymentService
{
}
public class PaymentService:IPaymentService
{
}
And finally, I have my controller that will have the property that needs to have the concrete payment service implementation injected into it:
public class HomeController:Controller
{
public IPaymentService Service {get;set;}
public ActionResult Index(){
var test = Service... //Service is Null
}
}
Shown above, the property remains null when I debug.
Additionally, I have tried using the [SetterProperty] just to see if it worked(I have no intention of coupling my controllers with those attributes), and it still didnt work.
I am not sure if I need to do something else, or what the problem might be. I have been using constructor injection with StructureMap for quite awhile.
Try dropping this line:
x.ForConcreteType<HomeController>().Configure
.Setter<IPaymentService>(y => y.PaymentService).IsTheDefault();
It shouldn't be necessary.
Given the following controller:
public class HomeController : Controller
{
public IMsgService Service { get; set; }
public ActionResult Index()
{
return Content(Service.GetMessage());
}
}
This was all that was required to configure StructureMap to set the property:
ObjectFactory.Initialize(cfg =>
{
cfg.For<IMsgService>().Use<MyMsgService>();
cfg.SetAllProperties(prop =>
{
prop.OfType<IMsgService>();
});
});
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());

IoC: Dependency Injection and overall instances between assemblies

I heared this should be possible, but I can not imagine how this should work.
I am using Dependency Injection (autofac) for my project. I develop a project with someone else and call the methods of his classes (I use his assembly).
Then I get an instance of an object which the other person should use for his operations.
We want to avoid passing this object instance on every method and use autofac.
Can he resolve this instance in his assembly project without passing any parameter?
I think we have to pass at least the DI-Container... But I heard that the concept of Dependency Injection should make it possible that you can resolve objects in the whole "execution context" and get the same one.
Here is an example with the asp.net web api:
This is a api controller of a asp.net webapi project:
public class DocumentsController : ApiController
{
// GET /api/documents
public HttpResponseMessage Get()
{
// Here I call the method of the other developer,
// security/authorization should be handled in
// his method!
// In this context the WebAPI provides the
// IPrincipal of the current user in this
// variable => "HttpContext.Current.User" but we
// don't want to pass it on every method call
ClassFromOtherAssembly.GetDocuments();
HttpResponseMessage response =
Request.CreateResponse<IEnumerable<Document>>(
HttpStatusCode.OK, documents);
return response;
}
}
This is the class of the other developer. He should deliver the documents and check if the user is authorized:
public class ClassFromOtherAssembly
{
public List<Documents> GetDocuments()
{
//Security check
IPrincipal principal =
DI_Container.Resolve(IPrincipal);
if(principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}
No, do not pass the container itself, you will end up with a Service Locator patter, and if you do a quick search you will understand that this pattern has a rotten smell.
public class Foo
{
private IContainer container;
private IBar bar;
public Foo( IContainer container) //no-no
{
this.container = container;
this.bar = container.Resolve<IBar>();
}
}
Instead use proper DI, like
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}
It doesn't really matter in which assembly your types are. This is the whole point of IoC and DI - to decouple parts of the application and make you depend on abstractions, rather than concrete implementations.
Edit
You misunderstood Service locator pattern with DI. "Instead of passing a parameter we want to use Dependency Injection" - passing a parameter is a DI, in contrast, resolving a type from a static container is a service locator.
public class DocumentsController : ApiController
{
public HttpResponseMessage Get()
{
ClassFromOtherAssembly.GetDocuments(); //this is Service locator
//really bad for testability and maintenance
...
}
}
DI looks like this
public class DocumentsController : ApiController
{
private IDocumentProvider;
public DocumentsController(IDocumentProvider provider)
{
this.provider = provider;
}
public HttpResponseMessage Get()
{
provider.GetDocuments(); //this is DI
...
}
}
You're using the ServiceLocator (anti-pattern) by calling Resolve directly from GetDocuments()
Use inversion of control with constructor injection to pass in the IPrinciple thus:
public class ClassFromOtherAssembly
{
private IPrincipal principal;
public ClassFromOtherAssembly(IPrincipal principal)
{
this.principal = principal;
}
public List<Documents> GetDocuments()
{
//Security check
if (principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}

Categories