I have setup the dependency injection in startup.cs say: IAction. In controller, I can inject the service as a parameter in the constructor. But what if my normal class in Business Layer for example, How do that service be injected.
In Microsoft documentation, it is a bad design if do something like the image below:
Is there a better way? If I tried passed these service from controller to other layers, this will not give good result as well.
You should be able to pass the same dependencies through the constructors of the classes in your business layer just like you pass them through the constructors of your controllers in your Web API layer or MVC layer.
Something like this:
public class UsersService
{
private readonly IUsersRepository usersRepository;
public UsersService(IUsersRepository usersRepository)
{
this.usersRepository = usersRepository;
}
public async Task<User> GetUser(int userId)
{
return await usersRepository.GetByIdAsync(userId);
}
}
Related
I'm working on web application project which uses ASP.NET Core 2.1. Along with developing the API we are also trying to Unit test it using MSTest framework.
My Controllers are inheriting from ControllerBase. In my Test Bench I'm mocking my Business Layer using Moq Framework. When I'm calling the Controller from the test method, I need to pass a Mocked Business instance to the controller, for which I'm trying to declare parameterized constructor.
It's working fine for test cases, but my normal flow is disturbed. I even tried using both parameterized and parameterless constructors.
This works fine with Dot Framework which inherits APIController.
public class BookingController: ControllerBase {
BusinessManager business = new BusinessManager();
//Non-Parameterized Constructor
public BookingController() {}
//Parameterized Constructor
public BookingController(BusinessManager mockedBusiness) {
this.business = mockedBusiness;
}
}
A non-parameterized constructor should be used when called from UI.
Parameterized should only work when called from Test Bench passing some instance.
In the original code, the
BusinessManager business = new BusinessManager();
was tightly coupling the controller to the dependency, and is considered a code smell. Which is why you ended up having to try a work around in order to be able to test the controller in isolation.
Use the explicit dependency principle and keep the parameterized constructor
public class BookingController: ControllerBase {
private readonly BusinessManager business;
//Parameterized Constructor
public BookingController(BusinessManager business) {
this.business = business;
}
//...
}
In Startup, register you dependency with the service collection
public void ConfigureServices(IServiceCollection services) {
//...
services.AddScoped<BusinessManager>();
//...
}
The will allow the framework to inject the required dependency at run time when the controller is created in your normal flow, and also allows the controller to be flexible enough to be tested in isolation with your mocked business instance.
I am sure there are answers on here to my question, though I just don't either quite understand what I'm looking for or what I'm reading... Also, not 100% sure DI is what I should be using in this case.
I am attempting to use Unity for my DI. I am injecting dependency into ASP.Net Web API Controllers. And so far so good.
I am injecting Services into my controllers that the controller will require. For example, in one of my controllers I have:
private TransactionService _transactionService;
public TransactionsController(TransactionService transactionService)
{
_transactionService = transactionService;
}
In this case I am injecting an instance of TransactionService into the controller. This is all working.
My WebApiConfig.cs contains the following, which as i understand it actually performs the injection:
var container = new UnityContainer();
container.RegisterType<ServiceBase>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
I can show you my UnityResolver if needed.
Now the part I'm struggling with...
My services all inherit from an Abstract class ServiceBase - in its simplest for it looks like this:
public abstract class ServiceBase : IDisposable
{
internal Account _account;
public ServiceBase(){}
}
What I would like to do is create the Account during my injection process and pass it in somehow so that my injected services don't need to deal with instansiating the account.
The moment I try adding any constructors to my services to accept an Account I receive the message to ensure my controllers have a parameterless constructor.
So.. how do i set up my DI so that I can inject services into my controllers and also inject a pre-instantiated instance of Account into my services?
Update
I forgot to mention (sorry Wiktor) - I would like to NOT use Attributes if possible. It seems strange in my mind that we can use DI to unhook dependency and then go and put a bunch of dependent attributes everywhere. I quite possibly just don't understand the DI concept correctly, though this doesn't seem right to me
That should be simple, just make the additional property public and add the dependency attribute on it.
[Dependency]
public Account _account { get; set; }
Unity should be able to inject the attribute and you can even register the Account class in an ordinary way (for example with an injection factory).
I hope this would give some idea for you.
Create an interface for service base and declare Acccount as public property.
Interface for your service:
you can also inherit other interfaces.
public interface ITransactionService : IDisposable
{
IAccount Account{get;set;}
}
Implement it in your class:
public class TransactionService : ITransactionService{
private IAccount _account;
public IAccount Account
{
get
{if(_account==null)_account=new Account(); return _account;}
set
{_account=value;}
}
}
Now use the constructor at API controller as shown below:
private ITransactionService _transactionService;
public TransactionsController(ITransactionService transactionService)
{
_transactionService = transactionService;
}
Unity resolver:
var container = new UnityContainer();
container.RegisterType<ITransactionService,TransactionService>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
So using in this way where property injection and constructor injection used for reducing tightly coupled dependency.
It will be very easy for mocking the interface for unit testing.
You may also create an interface for Account class, so that it could be easy for mocking based on your use.
In case you don't want to use attributes, which I totally agree with, the best approach is to have ServiceBase accept the account parameter, like:
public abstract class ServiceBase {
private Account _account;
public ServiceBase(Account account) {
this._account = account;
}
}
You will have to declare the same constructor on your derived service as well TransactionService. When the controller is instantiated, Unity will correctly create the instance of Account class first and then pass it on to your TransactionService object via constructor injection. And you should register Account object using a life time manager to scope it to singleton.
Hope this helps.
this question is a follow-up of this question i posted last weekend.
As of now, i have something like this in my service layer which talks with UI in MVC application.
IDepartmentService deptService = kernel.Get<IDepartmentService>();
IList<Department> deptList = deptService.GetAllDepartments();
Everything is fine and DI is working as expected. However, for some reason if i decide to use Structuremap then my entire service layer needs to be changed. How do i abstract it out so that a change in DI tool wont affect my service layer or has minimum impact.
However, for some reason if i decide to use Structuremap then my
entire service layer needs to be changed.
That's not true. As shown in the previous thread the Service Layer doesn't know anything about the DI framework.
You should have a layer called composition root. This is the only layer which is aware of the DI framework and all the underlying layers. This is where you are doing the composition. So if you change the DI framework, the only place you need to make changes is in the composition root.
So you should absolutely get rid of kernel.Get<> calls from your service. Right now you are using Service Locator and not Dependency Injection. Service Locator is an anti-pattern. Your service layer should look like this:
public class MyService
{
private readonly ISomeDependency dependency;
public MyService(ISomeDependency dependency)
{
this.dependency = dependency;
}
public void SomeMethod()
{
// do something with the dependency here
}
}
instead of:
public class MyService
{
private readonly ISomeDependency dependency;
public MyService()
{
this.dependency = kernel.Get<ISomeDependency>();
}
public void SomeMethod()
{
// do something with the dependency here
}
}
I have a layered application with the following projects:
DAL (using EntityFramework with repositories)
DAL.Model (contains the entities, and is referenced by all the others)
Services
UI (in wpf)
The base repository looks like this:
public abstract class RepositoryBase<T> where T : class
{
private readonly MyContext context;
private readonly IDbSet<T> dbSet;
protected RepositoryBase(MyContext dataContext)
{
context = dataContext;
dbSet = context.Set<T>();
}
protected MyContext Context
{
get { return context; }
}
**And a series of virtual methods for Add, Delete, etc.
}
All repositories extend this one, such as:
public class MarketRepository : RepositoryBase<Market>
{
public MarketRepository(MyContext dataContext) : base(dataContext)
{
}
public IEnumerable<Market> GetAllMarkets()
{
return this.Context.Markets.ToList<Market>();
}
}
The services look like this:
public class MarketService
{
IMarketRepository _marketRepository;
public MarketService(IMarketRepository marketRepository)
{
_marketRepository = marketRepository;
}
public IEnumerable<Market> GetAllMarkets()
{
return _marketRepository.GetAllMarkets();
}
}
What I would like to achieve is that the UI layer would only have a reference to the Services layer, the Services layer only with the DAL layer (and all of them to Model, where the entities live) using DI (right now I'm using Unity).
The problem is, in my container in the UI I only want to do this
unity.RegisterType<IMarketService, MarketService>();
and not have to do it as well for the repositories, because then the UI layer would have a dependency on the DAL layer.
I thought about adding a parameterless constructor to the Service classes, like:
public MarketService() : this(new MarketRepository(*What would I put here?)) { }
but then I'm loosing the abstraction that the interface gives, and also I don't know what to do with the MyContext that the repository needs as a parameter; if I pass a new one, then I need to reference the DAL.
Should I change my repositories to create a new MyContext in the constructor, rather than getting it as a parameter?
How can I refactor my architecture to make it work properly and with minimal dependencies?
Well, I belive it is up to the bootstrapper to configure dependencies, in the higher level of the application. As it is usually the UI project, if it needs to reference other assemblies, so be it. If you do not like your UI project managing that, than create a bootstrapper project responsable for getting your app running and separete your UI classes in another one.
Your IoC container should support Dependency Injection using a string from an external configuration file. This way you are not hardcoding the mapping. Structuremap does this quite well, so I am sure other IoCs will.
Adding external dependenices as a parameter when creating an instance is the way to go.
I think you should make yourself more familiar with the different ways to configure Unity, so that the dependencies are resolved.
Could you elaborate why you are creating a repository when using a dependency injection framework?
When configuring DI, you should follow the same pattern - UI bootstrapper initializes Services, Services initialize DAL. (With autofac or ninject you could achiece this using modules. With unity you should emulate modules).
In pseudocode something like
//ui
void UILayer.ConfigureUnity(unity)
{
ServiceLayer.ConfigureUnity(unity)
}
//services
void ServiceLayer.ConfigureUnity(unity)
{
DAL.ConfigureUnity(unity)
unity.RegisterType<IMarketService, MarketService>();
}
//dal
void DAL.ConfigureUnity(unity)
{
unity.RegisterType<IMarketRepository, MarketRespository>();
unity.RegisterType<MyContext, MyContext>(); //not sure exact syntax - just register type for 'new Type()' activator.
}
Using Autofac, suppose I have a PersonRepository and an EventRepository class, which both depend on a IDataService service... I use both of the repository classes in an Mvc Controller action (for example - might as well be some MvvM WPF application) like
public class Mycontroller : controller
{
public Mycontroller(PersonRepository personRepo, EventRepository eventRepo) {...}
...
public ActionResult Index(){ ... I use the repository classes in here ...}
}
public class PersonRepository
{
public PersonRepository(IDataService service){...}
}
public class EventRepository
{
public PersonRepository(IDataService service){...}
}
I want to make sure, when using the repository classes and injecting them with a IDataService implementation, that both of the repository classes receive the same instance of the IDataService service...
How can I do that?
It depends on the lifetime of the IDataService.
Do you want to keep reusing the same one over and over again? Then it's basically a singleton, and you must configure Autofac to treat it as one:
builder.RegisterType<IDataService>().As<MyDataService>().SingleInstance();
But if you're running in MVC and want to reuse the same instance only during the lifetime of the HTTP request, you configure Autofac like so:
builder.RegisterType<IDataService>().As<MyDataService>().HttpRequestScoped();
Call the .SingleInstance() method when registering the component. (assuming fluent registration)
Try implementing the IComponentLifetime with your rules of reusing and register the services using your lifetime.