Resolving muliple implementation of interface - c#

I have an application that has 3 service :
A validator service that validates content based on type
A boss service that converts stuff in regard to boss people
An employee service that convert stuff in regard to employee people
It looks like this simplified :
public interface IValidatorService<T>
{
void ValidateContent(AbstractValidator<T> validator, List<T> content);
}
public class ValidatorService <T> : IValidatorService<T>
{
public void ValidateContent(AbstractValidator<T> validator, List<T> peopleContent)
{ ...does its job...}
}
public interface IPeopleService<T>
{
List<T> Convert(string json);
}
public class BossService : IPeopleService<People>
{
IValidatorService<Boss> _validatorService;
public BossService (IValidatorService<Boss> validatorService)
{
_validatorService = validatorService;
}
public List<People> Convert(string json)
{ ...does its job for boss...}
}
public class EmployeeService : IPeopleService<People>
{
IValidatorService<Employee> _validatorService;
public EmployeeService (IValidatorService<Employee> validatorService)
{
_validatorService = validatorService;
}
public List<People> Convert(string json)
{ ...does its job for employee...}
}
Now in my main I am ok if I do this :
var serviceProvider = new ServiceCollection()
.AddSingleton<IValidatorService<Boss>, ValidatorService<Boss>>()
.AddSingleton<IPeopleService<People>, BossService>()
.BuildServiceProvider();
var bosses = serviceProvider.GetService<IPeopleService<People>>().Convert(json);
But in fact I want to do something like this although my problem how can it know which implementation to execute for boss and for employee respectivly since they are of the same type in this case IPeopleService
var serviceProvider = new ServiceCollection()
.AddSingleton<IValidatorService<Boss>, ValidatorService<Boss>>()
.AddSingleton<IPeopleService<People>, BossService>()
.AddSingleton<IValidatorService<Employee>, ValidatorService<Employee>>()
.AddSingleton<IPeopleService<People>, EmployeeService>()
.BuildServiceProvider();
var bosses = serviceProvider.GetService<IPeopleService<People>>().Convert(json);
var employees = serviceProvider.GetService<IPeopleService<People>>().Convert(json);

You can't do that directly using the built-in container. You will have to introduce a factory that acts as an intermediary and inject the factory instead. This allows you to specify additional context to get the right service (e.g. by name).
Take a look at the GitHub repo and NuGet package for DependencyInjection.Extensions.
This solution was inspired by a question about named resolution.

It doesn't. Depending on which DI engine you use, that would throw some kind of ambiguous resolution exception or some lamer implementations might take the first one. Some others even allow you to get all implementations of IPeopleService<People> through an IEnumerable mechanism.
And why would the DI engine know which one you want? You haven't given it any context with which to make a decision.
You'd have to make one IPeopleService<Boss> and one IPeopleService<Employee>.
EDIT: Kit makes a good point... some DI engines support resolving by name or other type of contexts.

Related

Named service factory for .NET 6.0

I am trying to build a service factory extension method that mirrors the functionality of the popular "HttpClientFactory" within the context of a blazor client application. I want to register the same interface/class pair with a string name multiple times with different configurations. Essentially, I want to avoid making another interface or class but I want the properties of the class to be different and accessible via a factory pattern.
I would ideally like my code to look like this for registration
Program.cs
builder.Services.AddFoodFactory<IFoodService,FoodService>("Citrus", serviceConfig =>
serviceConfig.StorageRoom = "A1"
)
builder.Services.AddFoodFactory<IFoodService,FoodService>("Starch", serviceConfig =>
serviceConfig.StorageRoom = "A2"
)
And then use the service like so.
index.razor
#inject FoodServiceFactory;
CitrusService = FoodServiceFactory.Create("Citrus");
StarchService = FoodServiceFactory.Create("Starch");
CitrusService.GetRoom();
StarchService.GetRoom();
Currently I think this is a multiple part problem but without knowing how to begin with setting up a way to first register the services I feel a little lost. Tim Corey did an excellent video with a factory that looks like this
using FactoryPattern.Samples;
namespace FactoryPattern.Factories;
public static class DifferentImplementationsFactoryExtension
{
public static void AddVehicleFactory(this IServiceCollection services)
{
services.AddTransient<IVehicle, Car>();
services.AddTransient<IVehicle, Truck>();
services.AddTransient<IVehicle, Van>();
services.AddSingleton<Func<IEnumerable<IVehicle>>>
(x => () => x.GetService<IEnumerable<IVehicle>>()!);
services.AddSingleton<IVehicleFactory, VehicleFactory>();
}
}
public interface IVehicleFactory
{
IVehicle Create(string name);
}
public class VehicleFactory : IVehicleFactory
{
private readonly Func<IEnumerable<IVehicle>> _factory;
public VehicleFactory(Func<IEnumerable<IVehicle>> factory)
{
_factory = factory;
}
public IVehicle Create(string name)
{
var set = _factory();
IVehicle output = set.Where(x => x.VehicleType == name).First();
return output;
}
}
However, needing different classes defeats the first problem. My instinct is to drill into making a custom "AddTransient"/"AddScoped" etc. extension method but without guidance I am hesitant to start.
Thank you in advance for your assistance.

How to configure dependency injection container with Func<T, Result>?

BusinessAction is used to represent an action that can be performed by a user. Each action is related to the specific entity, so if for example, that entity is Order, business actions could be CancelOrder, IssueRefund, etc.
public abstract class BusinessAction<T>
{
public Guid Id { get; init; }
public Func<T, bool> IsEnabledFor { get; init; }
}
public class CancelOrderAction : BusinessAction<Order>
{
public CancelOrderAction ()
{
Id = Guid.Parse("0e07d05c-6298-4c56-87d7-d2ca339fee1e");
IsEnabledFor = o => o.Status == OrderStatus.Active;
}
}
Then I need to group all actions related to the specific type.
public interface IActionRegistry
{
Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId);
}
public class ActionRegistry<T> : IActionRegistry
where T : BaseEntity
{
private readonly IEnumerable<BusinessAction<T>> _actions;
private readonly IRepository<T> _repository;
public ActionRegistry(IEnumerable<BusinessAction<T>> actions, IRepository<T> repository)
{
_actions = actions;
_repository = repository;
}
public async Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId)
{
var entity = await _repository.FindByIdAsync(entityId);
return entity == null
? Enumerable.Empty<Guid>()
: _actions.Where(a => a.IsEnabledFor(entity)).Select(a => a.Id);
}
}
Finally, there is an API endpoint that receives entity type (some enumeration that is later on mapped to real .NET type) and ID of an entity. The API endpoint is responsible to return action IDs that are enabled for the current state of the entity.
public class RequestHandler : IRequestHandler<Request, IEnumerable<Guid>>>
{
private readonly Func<Type, IActionRegistry> _registryFactory;
public RequestHandler(Func<Type, IActionRegistry> registryFactory)
{
_registryFactory = registryFactory;
}
public async Task<IEnumerable<Guid>> Handle(Request request, CancellationToken cancellationToken)
{
var type = request.EntityType.GetDotnetType();
var actionRegistry = _registryFactory(type);
var enabledActions = await actionRegistry.GetEnabledActionIdsForAsync(request.EntityId);
return enabledActions;
}
}
The question is: How can I configure the dependency injection container in ASP.NET (using default option or Autofac) so that Func<Type, IActionRegistry> can be resolved?
For parameters in ActionRegistry<T> I guess I can do:
builder.RegisterAssemblyTypes().AsClosedTypesOf(typeof(BusinessAction<>));
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
But, how can I configure Func<Type, IActionRegistry> so that I am able to automatically connect a request for Order with ActionRegistry<Order>? Is there a way to do that or I will need to manually configure the factory by writing some switch statement based on type (and how will that look)?
Is there a better way to achieve what I need here? The end goal is that once I have runtime type, I can get a list of business actions related to that type as well as a repository (so that I can fetch entity from DB).
What you're trying to do is possible, but it's not a common thing and isn't something magic you'll get out of the box. You'll have to write code to implement it.
Before I get to that... from a future perspective, you might get help faster and more eyes on your question if your repro is far more minimal. The whole BusinessAction<T> isn't really needed; the RequestHandler isn't needed... honestly, all you need to repro what you're doing is:
public interface IActionRegistry
{
}
public class ActionRegistry<T> : IActionRegistry
{
}
If the other stuff is relevant to the question, definitely include it... but in this case, it's not, so adding it in here just makes the question harder to read through and answer. I know I, personally, will sometimes just skip questions where there's a lot of extra stuff because there are only so many hours in the day, you know?
Anyway, here's how you'd do it, in working example form:
var builder = new ContainerBuilder();
// Register the action registry generic but not AS the interface.
// You can't register an open generic as a non-generic interface.
builder.RegisterGeneric(typeof(ActionRegistry<>));
// Manually build the factory method. Going from reflection
// System.Type to a generic ActionRegistry<Type> is not common and
// not directly supported.
builder.Register((context, parameters) => {
// Capture the lifetime scope or you'll get an exception about
// the resolve operation already being over.
var scope = context.Resolve<ILifetimeScope>();
// Here's the factory method. You can add whatever additional
// enhancements you need, like better error handling.
return (Type type) => {
var closedGeneric = typeof(ActionRegistry<>).MakeGenericType(type);
return scope.Resolve(closedGeneric) as IActionRegistry;
};
});
var container = builder.Build();
// Now you can resolve it and use it.
var factory = container.Resolve<Func<Type, IActionRegistry>>();
var instance = factory(typeof(DivideByZeroException));
Assert.Equal("ActionRegistry`1", instance.GetType().Name);
Assert.Equal("DivideByZeroException", instance.GetType().GenericTypeArguments[0].Name);

Can not resolve a generic service using manual interception with ASP.NET Core 2 and Castle.Core

I know there are a lot of question similar to this one but actually none of them solved my issue.
I created a new Asp.Net Core 2 application.
Now I am trying to use an intercepter for a specific service to fetch some data into this service(I am using Castle.Core nuget package).
I have a generic IConfigurationInterceptor<> and a real implementation ConfigurationInterceptor<>
Here is the interface:
public interface IConfigurationInterceptor<T> : IInterceptor where T : class { }
public class ConfigurationInterceptor<T> : IConfigurationInterceptor<T> where T : class
{
public ConfigurationInterceptor(ConfigurationInfo<T> configurationInfo,
some other services)
{
_configurationInfo = configurationInfo;
//.....
}
public void Intercept(IInvocation invocation)
{
invocation.ReturnValue = somefunc(someconfig, invocation.Arguments);
}
}
Then I have an extension method like below:
public static void AddSingletonConfiguration<TInterface, TImplementation>(
this IServiceCollection services, string featureName)
where TImplementation : class, TInterface where TInterface : class
{
var info = new ConfigurationInfo<TImplementation>(featureName, typeof(TInterface));
var generator = new ProxyGenerator();
services.AddSingleton(x =>
{
var ic = x.GetService<Func<ConfigurationInfo<TImplementation>,
IConfigurationInterceptor<TImplementation>>>();
var icTemp = ic.Invoke(info);
return (TInterface) generator.CreateInterfaceProxyWithoutTarget(
info.ServiceType, icTemp);
});
}
But when I get to this line of code:
var ic = x.GetService<Func<ConfigurationInfo<TImplementation>,
IConfigurationInterceptor<TImplementation>>>();
it returns me a null value for ic:
ConfigurationInfo class is just a simple class I create for storing some extra data.
public sealed class ConfigurationInfo<TImpl>
{
public Type ServiceType { get; }
public string FeatureName { get; }
public ConfigurationInfo(string featureName, Type serviceType)
{
FeatureName = featureName;
ServiceType = serviceType;
}
public override string ToString()
=> $"{FeatureName} ({ServiceType} -> {typeof(TImpl)})";
}
In my ConfigureServices I have these both lines:
services.AddSingleton(typeof(IConfigurationInterceptor<>),
typeof(ConfigurationInterceptor<>));
services.AddSingletonConfiguration<IStaticDataConfiguration, StaticDataConfiguration>(
"SomeFeatureKey");
I am not sure why ic variable is null because previously another project was using Autofac and was working perfectly but in the startup you would find something like this:
builder.RegisterGeneric(typeof(ConfigurationInterceptor<>))
.As(typeof(IConfigurationInterceptor<>)).SingleInstance();
builder.RegisterConfiguration<IStaticDataConfiguration, StaticDataConfiguration>(
"SomeFeatureKey");
and the extension method was like this one:
public static void RegisterConfiguration<TInterface, TImplementation>(
this ContainerBuilder builder, string featureName)
where TImplementation : class, TInterface
{
var info = new ConfigurationInfo<TImplementation>(featureName, typeof(TInterface));
var generator = new ProxyGenerator();
builder
.Register(c =>
{
var ic = c.Resolve<Func<ConfigurationInfo<TImplementation>,
IConfigurationInterceptor<TImplementation>>>()(info);
return generator.CreateInterfaceProxyWithoutTarget(info.ServiceType, ic);
})
.As<TInterface>()
.SingleInstance();
}
Any help would be appreaciated.
EDIT 1:
Now I changed from method GetService<> to method GetRequiredService<> and throws an exception like below:
No service for type 'System.Func'2[StaticDataProvider.DomainModel.ConfigurationInfo'1[StaticDataProvider.Services.StaticDataConfiguration],StaticDataProvider.Services.Interfaces.IConfigurationInterceptor'1[StaticDataProvider.Services.StaticDataConfiguration]]' has been registered.
EDIT 2:
To wrap it up here is the issue: In my current project in Asp.Net core I can not get a Func<X, B> while in the Asp.Net MVC 5 project(It is a whole different project) I can get a Func<X, B> using Autofac. I think this has to do with parametrized instantiation feature in Autofac provided by default: here
Now, I dont know if in Asp.Net Core default DI container has something like this 'parametrized instantiation' feature where it allows me resolving Func<X, B> instead of B.
I'm guessing the root of the problem is in the fairly complex manual wiring up of the interceptors.
If you're using interceptors with Autofac, it'd be better to use the Autofac.Extras.DynamicProxy2 package and wire up interceptors using the built-in Autofac functionality instead of trying to chain a bunch of resolutions together with functions and parameters. I see a lot of little gotchas in here like how you're setting up a singleton interface proxy without a target but I'm not entirely clear how the target gets added post-facto. There's a lot of complexity you can avoid by using the tools provided.
That said, I'm also looking at the exception message. Without a stack trace I can't 100% guarantee it, but a search on the Autofac source indicates that's not a message that came from Autofac - it's likely, then, a message from the default Microsoft.Extensions.DependencyInjection container. That indicates you may not actually have everything wired up the way you think you do.
I'd back up a bit and just get simple things working and ensure they're coming from Autofac. If you decide you don't want Autofac in play, make sure you've removed it entirely from the equation. Basically, just make sure it's clean and working in the general sense.
After that, add things back slowly, one at a time. I might recommend putting a reproduction in a unit test where you use these registration mechanisms and get things working without the complexity of the entire app weighing down. Unwind it from there. If it's too complex to unit test... maybe that's an indicator you should simplify it and refactor. Make it testable.
I'll leave my previous answer for posterity, but... The default Microsoft IoC provider is very simple and does not support all the features of Autofac. You won't get parameterized resolution or auto-generated factories from it.
Here is what I had to do:
Modified ConfigureService method like below:
public void ConfigureServices(IServiceCollection services)
{
IConfigurationInterceptor<T> GetConfigurationInterceptor<T>(ConfigurationInfo<T> info) where T : class
{
return new ConfigurationInterceptor<T>(info, services.GetService<IConfigurationProvider>(), Configuration);
}
services.AddSingletonConfiguration<IStaticDataConfiguration, StaticDataConfiguration>("someFeatureKey", GetConfigurationInterceptor);
}
Then modified extension methods like below:
public static void AddSingletonConfiguration<TInterface, TImplementation>(this IServiceCollection services,
string featureName, Func<ConfigurationInfo<TImplementation>, IConfigurationInterceptor<TImplementation>> ic) where TImplementation : class, TInterface where TInterface : class
{
var info = new ConfigurationInfo<TImplementation>(featureName, typeof(TInterface));
var generator = new ProxyGenerator();
services.AddSingleton(x =>
{
var icTemp = ic.Invoke(info);
return (TInterface) generator.CreateInterfaceProxyWithoutTarget(info.ServiceType, icTemp);
});
}
public static TInterface GetService<TInterface>(this IServiceCollection services) where TInterface : class
{
var serviceProvider = services.BuildServiceProvider();
return serviceProvider.GetRequiredService<TInterface>();
}
Now its working fine but the idea is that I had to create Func<X, B> myself and pass as a parameter to extension method.

How do you avoid passing a DI container in a unidirectional api design?

I have a business layer with business entities designed using Active Record, and a unidirectional api surface. I have two distinct problems:
Without complicating the code, how should runtime values be handled, such as passing in an id value from the DAL to a constructed object? Would this be done with parameter overrides?
How do create other business entities and pass dependencies if I am not passing the container down as well (making it more of an anti-pattern / service locator)
Product is the root that wraps the container and acts as our application facade, and entry point to the rest of the BAL. The piece I am trying to solve is in Product.FindCustomer and Customer.FindDocument
public class Product
{
private IUnityContainer container;
public void RegisterType<T>() ...
public void RegisterType<TFrom, TTo>() ...
public Customer FindCustomer(string customerNumber)
{
var id = context.Customers
.Where(p => p.CustomerNumber == customerNumber)
.Select(p => p.Id)
.Single();
var customer = container.Resolve<Customer>(...); // param override?
customer.Load();
return customer;
}
}
public class Customer : BusinessEntity<Data.Customer, Guid>
{
private readonly IDocumentFileProvider provider;
public Customer(IDataContext context, IDocumentFileProvider provider) : base(context)
{
this.provider = provider;
}
public Customer(IDataContext context, IDocumentFileProvider provider, Guid id) : base(context, id)
{
this.provider = provider;
}
public Document FindDocument(string code)
{
var id = context.Documents
.Where(p => p.CustomerNumber == customerNumber)
.Select(p => p.Id)
.Single()
var document = new Document(context, provider, id); // Here is the issue
document.Load();
return document;
}
}
public class Document : BusinessEntity<Data.Document, Guid>
{
public Document(IDataContext context, IDocumentFileProvider provider) : base(context)
{
this.provider = provider;
}
public Document(IDataContext context, IDocumentFileProvider provider, Guid id) : base(context, id)
{
this.provider = provider;
}
public IDocumentFile GetFile()
{
return provider.GetFile();
}
}
Here is briefly the other classes.
public abstract class ActiveRecord<TEntity, TKey>
{
protected ActiveRecord(IDataContext context)
{
}
public virtual void Load() ...
public virtual void Save() ...
public virtual void Delete() ...
}
public abstract class BusinessEntity<TEntity, TKey> : ActiveRecord<TEntity, TKey>
{
protected BusinessEntity(IDataContext context) : base(context)
{
}
protected BusinessEntity(IDataContext context, TKey id) : this(context)
{
}
...
}
The hierarchies can be quite deep, but a shorter example:
var customer = product.FindCustomer("123");
var account = customer.FindAccount("321");
var document = account.FindDocument("some_code");
var file = document.GetFile();
One of my goals is to A) model the domain, and B) provide a very easy to understand API. Currently our BAL uses Service Locator, but I am experimenting on replacing that with proper IoC/DI and a container.
The deeper the API, and the more dependencies are needed, all the higher up class constructors can be quite long, and may no longer seem cohesive.
While DI can be squeezed into most application designs using half-measures, the unfortunate truth is that not all application designs are particularly DI friendly. Creating "smart entities" seems like magic when it comes to API design, but the fact of the matter is that at their core they violate the SRP (load and save are separate responsibilities regardless of how you slice it).
You basically have 4 options:
Find a design that is more conducive of DI and use its object model for your API
Find a design that is more conducive of DI and create a facade object model for your API
Use property injection to load your dependencies and give the end user control over the constructor
Use a service locator
I ran into a similar wall when trying to use CSLA in conjunction with DI and after many attempts, finally decided that it was CSLA that needed to go and to find a better design approach.
For a time, I tried using option 3. In this case you can create a facade wrapper around the DI container, and only expose its BuildUp() method through a static accessor. This prevents the use of the container as a service locator.
[Dependency]
public ISomeDependency SomeDepenency { get; set; }
public Customer()
{
Ioc.BuildUp(this);
}
Some DI containers can inject properties using fluent configuration instead of attributes (so your business model doesn't need to reference the container), but this can make the DI configuration very complex. Another option is to make build your own attributes.
Options 1 and 2 would be similar. You basically make every responsibility into its own class and separate your "entities" out into dumb data containers. An approach that works well for this is to use Command Query Segregation.
public class FindCustomer : IDataQuery<Customer>
{
public string CustomerNumber { get; set; }
}
public class FindCustomerHandler : IQueryHandler<FindCustomer, Customer>
{
private readonly DbContext context;
public FindCustomerHandler(DbContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public Customer Handle(GetCustomer query)
{
return (from customer in context.Customers
where customer.CustomerNumber == query.CustomerNumber
select new Customer
{
Id = customer.Id,
Name = customer.Name,
Addresses = customer.Addresses.Select(a =>
new Address
{
Id = a.Id,
Line1 = a.Line1,
Line2 = a.Line2,
Line3 = a.Line3
})
.OrderBy(x => x.Id)
}).FirstOrDefault();
}
}
Using option 1, the end user would create an instance of FindCustomer and call queryProcessor.Handle(findCustomer) (the queryProcessor is injected).
Using option 2, you would then need to create a wrapper API. You could use a fluent builder approach (more info here) to provide logical default dependencies, but allow the end user to call methods to supply their own.
var customer = new CustomerBuilder().Build(); // defaults
var customer = new CustomerBuilder(c =>
c.WithSomeDependency(new SomeDependency()).Build(); // overridden dependency
Unfortunately, the main issue with this is that control of the lifetime of objects is no longer up to the DI container, so dependencies like DbContext need special handling.
Another variant of this would be to make each entity into a humble object that internally builds up its own DI container using the other (loosely coupled) API objects. This is the recommended approach for legacy frameworks (such as web forms) that are difficult to use with DI.
Finally, there is making a static service locator that all of your API objects use to resolve their dependencies. While this best accomplishes the goal, it is something that should be considered a last resort. The biggest issue is that you lose the ability to quickly and easily understand what dependencies a class requires. So, you are either forced to create (and update) documentation indicating what the dependencies are to the end user, or end users will have to go digging through the source code to find out. Whether using a service locator is acceptable depends on your target audience and how frequent you expect them to need to be able to customize dependencies beyond the defaults. If custom dependencies are a once in a blue moon thing, it may work, but if 25% of your user base needs to add custom dependencies, service locator is probably not the right approach.
The bottom line is that if maintainability is your main goal, then option 1 is the clear winner. But if you are married to this particular API design, you will need to choose one of the other options and live with the extra maintenance involved in supporting such an API.
References:
DI Friendly Library
Dependency Injection in .NET.

When and where todo dependency injection.Could you clarify?

Getting more and more familiar with DI but I still have few niggles.
Read few articles where it says "Injection must be done at the entry point"
Suppose I have a situation where we have wcf Services and these are used both by internal win/web application and external third parties uses those wcf services.
Now where do you inject the Services and repositories?
Above to me seems to be a common scenarios!
Also i pass all those interfaces around.(Very good for mocking) how do I stop somebody from calling EG my repository from a layer that should NOT be calling the repository.
EG only the business Layer should call DAL.
Now by injecting a IRepository into a controller nothing stops a developer from calling the DAL.
Any suggestion? Links that clear all this
Noddy example of my poor man DI. How do I do the same using unity and Injecting all at the entryPoint?
[TestFixture]
public class Class1
{
[Test]
public void GetAll_when_called_is_invoked()
{
var mockRepository = new Mock<ICustomerRepository>();
mockRepository.Setup(x => x.GetAll()).Verifiable();
new CustomerService(mockRepository.Object);
ICustomerBiz customerBiz = new CustomerBizImp(mockRepository.Object);
customerBiz.GetAll();
mockRepository.Verify(x=>x.GetAll(),Times.AtLeastOnce());
}
}
public class CustomerService : ICustomerService //For brevity (in real will be a wcf service)
{
private readonly ICustomerRepository _customerRepository;
public CustomerService(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public IEnumerable<Customer> GetAll()
{
return _customerRepository.GetAll();
}
}
public class CustomerBizImp : ICustomerBiz
{
private readonly ICustomerRepository _customerRepository;
public CustomerBizImp(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public IEnumerable<Customer> GetAll()
{
return _customerRepository.GetAll();
}
}
public class CustomerRepository : ICustomerRepository
{
public IEnumerable<Customer> GetAll()
{
throw new NotImplementedException();
}
}
public interface ICustomerRepository
{
IEnumerable<Customer> GetAll();
}
public interface ICustomerService
{
IEnumerable<Customer> GetAll();
}
public interface ICustomerBiz
{
IEnumerable<Customer> GetAll();
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
thanks
This is a blog post on Composition roots or what you call entry points. Its from Mark Seemann the author of Dependency Injection in .NET. If you are looking for a deep understanding of DI this book is a must read.
There are a lot of samples out there on how to combine WCF and DI. If you are hosting your services in IIS you would need to write a custom ServiceHostFactory where you initialize you DI container. This is a sample for Microsoft's Unity.
As to
how do I stop somebody from calling EG my repository from a layer that should NOT be calling the repository
Do you use poor man's DI and pass all your references around through all your layers? Then you should definitely consider using a DI/IoC container like StructureMap, Castle Windsor, AutoFac or Unity.
If you are asking "how can I in general avoid the situation that someone does not follow my layer boundaries": Write tests that fail if an assembly references another one it should not reference (e.g. UI should not reference DAL).
UPDATE
I assume you wanted the service to use ICustomerBiz instead of the ICustomerRepository. If that is right the setup for Unity would look like this:
[TestMethod]
public void GetAll_with_Unity()
{
var container = new UnityContainer();
container.RegisterType<ICustomerRepository, CustomerRepository>();
container.RegisterType<ICustomerBiz, CustomerBizImp>();
container.RegisterType<ICustomerService, CustomerService>();
var svc = container.Resolve<ICustomerService>();
var all = svc.GetAll();
Assert.AreEqual(1, all.Count());
}
DI is much more about injecting a dependency inside your dipendency architecture, that's why it can not resolve, as is, layers isolation problem you face.
Production code can and should contain DI code, if it needed.
If we are talking about plugin-based architectureDI is one of most natural choices out there.
if we are talking about app behaviour change, like for example Logging system choice: save on remote server if connection present if not injject local logger for future sync with the server.
There are plenty of usages of DI in production, but all that is up to Architect to decide when, how and if use it.
In other words, there is no single rule of it use, it's not a hummer for any nail, so use it where you think it's approriate and use it wisely.

Categories

Resources