I have the follow trouble, in my base controller i do dependency injection. And i have a class child with implementation of base controller and i need pass the constructor. So my doubt is, my way to implementation of dependency injection is correctly?
If no, what is the best way to do this?
I use unity to implementate D.I, and my ide is VS2017 web api 2.
Follow this code i using:
Base controller or parent controller:
public class BaseController : ApiController
{
public string[] includes = null;
private readonly IFiltroServico servico;
public BaseController(IFiltroServico _servico)
{
servico = _servico;
}
}
Base controller to generics types implements Base Controller:
public abstract class BaseController<E, R, F> : BaseController
where E : class
where R : class
where F : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
}
Child controller:
public abstract class BaseController<R> : BaseController
where R : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
//services of controller;
}
You don't need to define the private field servico over and over again as it is already preset in the base controller. Just define it as protected readonly in the base class and use it in the childs.
Other than that your code is fine.
It is perfectly reasonable that a child has the same dependency parameters in the constructor as it inherits behavior of the base class that is most likely relying on the dependency.
Another option would be to use property injection in the base class but you need to add a unity specific attribute to the property. I don't like that as you bind your code directly to Unity.
Have you seen https://simpleinjector.org/index.html
check out git from https://github.com/simpleinjector/SimpleInjector
It is one of the best Inversion of Control library (IOC).
Only thing you need to do is register all your services and types.
using SimpleInjector;
static class Program
{
static readonly Container container;
static Program() {
// 1. Create a new Simple Injector container
container = new Container();
// 2. Configure the container (register)
container.Register<IOrderRepository, SqlOrderRepository>();
container.Register<ILogger, FileLogger>(Lifestyle.Singleton);
container.Register<CancelOrderHandler>();
// 3. Verify your configuration
container.Verify();
}
static void Main(string[] args)) {
// 4. Use the container
var handler = container.GetInstance<CancelOrderHandler>();
var orderId = Guid.Parse(args[0]);
var command = new CancelOrder { OrderId = orderId };
handler.Handle(command);
}
}
Once you register all your types and services you can inject those services where ever you want
public class CancelOrderHandler {
private readonly IOrderRepository repository;
private readonly ILogger logger;
private readonly IEventPublisher publisher;
// Use constructor injection for the dependencies
public CancelOrderHandler(
IOrderRepository repository, ILogger logger, IEventPublisher publisher) {
this.repository = repository;
this.logger = logger;
this.publisher = publisher;
}
public void Handle(CancelOrder command) {
this.logger.Log("Cancelling order " + command.OrderId);
var order = this.repository.GetById(command.OrderId);
order.Status = OrderStatus.Cancelled;
this.repository.Save(order);
this.publisher.Publish(new OrderCancelled(command.OrderId));
}
}
public class SqlOrderRepository : IOrderRepository {
private readonly ILogger logger;
// Use constructor injection for the dependencies
public SqlOrderRepository(ILogger logger) {
this.logger = logger;
}
public Order GetById(Guid id) {
this.logger.Log("Getting Order " + order.Id);
// Retrieve from db.
}
public void Save(Order order) {
this.logger.Log("Saving order " + order.Id);
// Save to db.
}
}
Let me know if you have any queries, Thanks.
Related
My project requires unit testing. I am using constructor dependency injection in my controller. When I mock the injected dependency object in my unit testing project and call it in a test method. Returns null in all cases.
Controller Class:
public class Owner:Controller
{
private readonly IComRepository repository;
private readonly DbContext context;
public Owner(IComRepository repository, DbContext context)
{
this.repository=repository;
this.context=context;
}
[HttpGet("GetAllTypes")]
public async Task<IActionResult> GetAllTypes()
{
var ownerTypes=repository.GetTypes();
return Ok(ownerTypes);
}
}
My Repository Class
public Interface IComRepository
{
IList<Type> GetTypes();
}
public Class ComRepository : IComRepository
{
private readonly DbContext context;
public ComRepository(DbContext context)
{
this.context=context;
}
public IList<Type> GetTypes()
{
var allTypes= context.Types.ToList();
return allTypes;
}
}
Now I need to test the GetAllTypes methods in my controller class. My Test Class is below mentioned:
using moq;
[TestClass]
public Class OwnerTest
{
public OwnerTest()
{
var mockIcomrepo = new Mock<IComRepository>();
var mockDbcontext = new Mock<Dbcontext>();
OwnerController owner = new OwnerController(mockDbContext.Object, mockIcomrepo.Object);
}
[TestMethod]
public void GetTypes()
{
var allTypes= owner.GetAllTypes(); //It's not trigger to my controller
Assert.AreEqual(5,allTypes.count());
}
}
How can I do it? Any one know the answer for this question.
As #Nkosi mentioned you have to use moq setup. Define your mocks outside constructor and initalize them in test class's constructor.
using moq;
[TestClass]
public Class OwnerTest
{
private readonly IComRepository _mockRepository;
private readonly OwnerControler _ownerController;
//your mock data
private readonly IList<Type> mockData;
public OwnerTest()
{
_mockRepository= new Mock<IComRepository>();
_ownerController = new OwnerController(mockDbContext.Object, mockIcomrepo.Object);
mockData=new IList<Type>{"Data1","Data2","Data3","Data4","Data5"};
}
//choose better names for testing a method
//Naming convention like this MethodName_StateUnderTest_ExpectedResult;
[TestMethod]
public void GetAllTypes()
{
_mockRepository.Setup(p=>p.GetAllTypes()).Returns(mockData);
var result= _ownerController.GetAllTypes();
var okResult=Assert.IsType<OkObjectResult>(result)
var returnTypes=Assert.IsAssignableFrom<IList<Type>>(okResult.Value);
Assert.AreEqual(5,returnTypes.count());
}
}
Also, why you inject your dbcontext to controller?your repository should depend dbcontext not controller.
I'm making an ASP.NET Core Razor Pages web application. In my application I use the following code:
public class MyClass
{
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
But when I use this class I need to do the following:
public class MySecondClass
{
private ImportIntoCalendar ImportHintSchedule;
public MySecondClass()
{
MyClass= new MyClass(_dbContext, _calendarService);
}
// Do something with variable ImportHintSchedule
ImportHintschedule.Function()
}
Everytime I need to add the dbcontext and the calendarservice into the parameters. So both need to be available in the other class. This feels like I'm doing something stupid, like I'm duplicating the same step. Does anybody know a better way to do this. Or is this just fine?
Edit:
I have this line in my startup.cs
services.AddScoped<ICalendarService, CalendarService>();
In your ConfigureServices you can add the IOC scopes.
For example, something like this. I don't know all of your code so the is just an example.
services.AddScoped<ICalendarService, CalendarService>();
services.AddScoped<IApplicationDbContext, ApplicationDbContext>();
You can also add singletons if that meets your needs as well.
Here is an example singleton call I use in my application
services.AddSingleton<IRepository<BaseItem>>(x => new Repository<BaseItem>(Configuration["MongoConnection:DefaultConnection"]));
I would suggest to create an Interface of your class, something like:
public interface IMyClass {
void MyFunction();
}
Then, implement that in your class:
public class MyClass : IMyClass {
private readonly ApplicationDbContext _dbContext;
private readonly ICalendarService _calendarService;
public MyClass(ApplicationDbContext dbContext, ICalendarService calendarService)
{
_dbContext = dbContext;
_calendarService = calendarService;
}
public void MyFunction()
{
// here I need to use _dbContext and _calendarService
}
}
And the add that to injector:
public void ConfigureServices(IServiceCollection services)
{
// existing code
services.AddTransient<IMyClass, MyClass>();
}
and finally use IMyClass in Controller constructor.
public class MyController:Controller
{
private IMyInterface _myClass;
public MyController(IMyInterface myclass) {
_myClass = myClass;
}
public IActionResult MyAction() {
_myClass.MyFunction();
return View();
}
}
In ASP.NET Core 2 we can add a Azure Redis Cache like this:
services.AddDistributedRedisCache(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection");
config.InstanceName = "MYINSTANCE";
});
Then the usage will be like this:
private readonly IDistributedCache _cache;
public MyController(IDistributedCache cache)
{
_cache = cache;
}
How can I do it so that I will have:
private readonly IDistributedCache _cache1;
private readonly IDistributedCache _cache2;
public MyController(IDistributedCache cache1, IDistributedCache cache2)
{
_cache1 = cache1;
_cache2 = cache2;
}
My questions how can I add another service that points to a different Azure Redis Cache Connection and instance and make separation of them when I want to use them?
Behind the scene, AddDistributedRedisCache() extension method does the following (code on github):
Registers action to configure RedisCacheOptions. Lambda that you pass to AddDistributedRedisCache() is responsible for that.
Instance of RedisCacheOptions is passed to constructor of RedisCache wrapped into IOptions<T>.
Registers Singletone implementation RedisCache of IDistributedCache interface.
Unfortunatelly, both of these actions aren't well suited for what you ask.
Only one action could be registered for configuring specific type of options.
Native implementation of .net core dependency injection does not support registration override.
There is still a solution that will do what you want. However this solution somewhat killing me.
The trick is that you inherit your custom RedisCacheOptions1, RedisCacheOptions2 from RedisCacheOptions and register distinct configurations for both of them.
Then you define your custom IDistributedCache1 and IDistributedCache2 interfaces that inherit from IDistributedCache.
And finally you define classes RedisCache1 (that inherits implementation from RedisCache and also implements IDistributedCache1) and RedisCache2 (the same).
Something like this:
public interface IDistributedCache1 : IDistributedCache
{
}
public interface IDistributedCache2 : IDistributedCache
{
}
public class RedisCacheOptions1 : RedisCacheOptions
{
}
public class RedisCacheOptions2 : RedisCacheOptions
{
}
public class RedisCache1 : RedisCache, IDistributedCache1
{
public RedisCache1(IOptions<RedisCacheOptions1> optionsAccessor) : base(optionsAccessor)
{
}
}
public class RedisCache2 : RedisCache, IDistributedCache2
{
public RedisCache2(IOptions<RedisCacheOptions2> optionsAccessor) : base(optionsAccessor)
{
}
}
public class MyController : Controller
{
private readonly IDistributedCache _cache1;
private readonly IDistributedCache _cache2;
public MyController(IDistributedCache1 cache1, IDistributedCache2 cache2)
{
_cache1 = cache1;
_cache2 = cache2;
}
}
// Bootstrapping
services.AddOptions();
services.Configure<RedisCacheOptions1>(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection1");
config.InstanceName = "MYINSTANCE1";
});
services.Configure<RedisCacheOptions2>(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection2");
config.InstanceName = "MYINSTANCE2";
});
services.Add(ServiceDescriptor.Singleton<IDistributedCache1, RedisCache1>());
services.Add(ServiceDescriptor.Singleton<IDistributedCache2, RedisCache2>());
I have FileHandler.ashx file in my main project.
public class FileHandler : IHttpHandler
{
private readonly IAccountService _accountService;
private readonly IAttachmentService _attachmentService;
public FileHandler(IAccountService accountService, IAttachmentService attachmentService)
{
_accountService = accountService;
_attachmentService = attachmentService;
}
....
}
Also, I have HandlerInstaller:
public class HandlersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.Where(Component.IsInSameNamespaceAs<FileHandler>())
.WithService.DefaultInterfaces()
.LifestyleSingleton());
}
}
But when I try to call file FileHandler.ashx I get an error:
No parameterless constructor defined for this object.
What is the reason? how to fix it?
I think you have to provide an empty construtor like that
public class FileHandler : IHttpHandler
{
private readonly IAccountService _accountService;
private readonly IAttachmentService _attachmentService;
public FileHandler()
{
}
public FileHandler(IAccountService accountService, IAttachmentService attachmentService)
{
_accountService = accountService;
_attachmentService = attachmentService;
}
....
}
It might be that Castle Windsor can't resolve the dependencies that your current constructor requires IAccountService and IAttachmentService.
In this case it is probably looking for a parameterless one instead to use.
Make sure the above dependencies are registered and windsor can resolve them.
In your web.config do you have this:
<castle>
<installers>
<install type="Your.Namespace.HandlersInstaller, Your.Namespace" />
</installers>
</castle>
Castle Windsor does not know how to create IHttpHandler instances. There is not somethig like ControlerFactory for handlers, so you cant intercept the handler creation process. You have two options:
Implement your handlers as controller actions and use standard WindsorControlerFactory to inject your dependencies.
Provide parameter less constructor with Windsor used as service locator:
public class FileHandler : IHttpHandler
{
readonly IAccountService accountService;
readonly IAttachmentService attachmentService;
public FileHandler()
{
var containerAccessor = HttpContext.Current.ApplicationInstance as IContainerAccessor;
var container = conatinerAccessor.Container;
accountService = container.Resolve<IAccountService>();
attachmentService = container.Resolve<IAttachmentService>();
}
public FileHandler(IAccountService accountService, IAttachmentService attachmentService)
{
this.accountService = accountService;
this.attachmentService = attachmentService;
}
...
}
See this answer to find out how to implement IContainerAccessor.
I am utilizing the Unit Of Work and Generic Repository pattern in my MVC 4 app. The problem I am trying to solve is creating Repository stubs for every entity in my system. In order to utilize the Autofac Ioc I am having to create a repository class and interface for every entity so that I can register it in Autofac.
app start...
builder.RegisterType<SchoolDetailRepository>().As<ISchoolDetailRepository>().InstancePerHttpRequest();
Repository class
public class SchoolDetailRepository : RepositoryBase<SchoolDetail>, ISchoolDetailRepository
{
public SchoolDetailRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
}
Interface
public interface ISchoolDetailRepository : IRepository<SchoolDetail>
{
}
It seems like a lot of extra work.
Is there a way to register the generic repository of Type rather than creating all these empty classes?
Then in my service class I can just have the generic type passed into the constructor via Ioc like...
public class SchoolService : ISchoolService
{
private readonly IRepository<SchoolDetail> _schoolRepository;
private readonly IUnitOfWork _unitOfWork;
public SchoolService(IRepository<SchoolDetail> schoolRepository, IUnitOfWork unitOfWork)
{
this._schoolRepository = schoolRepository;
this._unitOfWork = unitOfWork;
}
}
Container config
// Autofac iOC
var builder = new ContainerBuilder();
// register controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// register services
builder.RegisterType<MembershipService>().As<IMembershipService>().InstancePerHttpRequest();
builder.RegisterType<SchoolService>().As<ISchoolService>().InstancePerHttpRequest();
builder.RegisterType<StudentService>().As<IStudentService>().InstancePerHttpRequest();
builder.RegisterType<ClassRoomService>().As<IClassRoomService>().InstancePerHttpRequest();
builder.RegisterType<CourseService>().As<ICourseService>().InstancePerHttpRequest();
builder.RegisterType<SchoolYearService>().As<ISchoolYearService>().InstancePerHttpRequest();
builder.RegisterType<EnrollmentService>().As<IEnrollmentService>().InstancePerHttpRequest();
builder.RegisterType<TeacherService>().As<ITeacherService>().InstancePerHttpRequest();
// register data infrastructure
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerHttpRequest();
// register repositories
builder.RegisterType<SchoolRepository>().As<ISchoolRepository>().InstancePerHttpRequest();
builder.RegisterType<TeacherRepository>().As<ITeacherRepository>().InstancePerHttpRequest();
builder.RegisterType<MembershipRepository>().As<IMembershipRepository>().InstancePerHttpRequest();
builder.RegisterType<RoleRepository>().As<IRoleRepository>().InstancePerHttpRequest();
builder.RegisterType<ProfileRepository>().As<IProfileRepository>().InstancePerHttpRequest();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerHttpRequest();
builder.RegisterType<StudentRepository>().As<IStudentRepository>().InstancePerHttpRequest();
builder.RegisterType<ClassRoomRepository>().As<IClassRoomRepository>().InstancePerHttpRequest();
builder.RegisterType<CourseRepository>().As<ICourseRepository>().InstancePerHttpRequest();
builder.RegisterType<EnrollmentRepository>().As<IEnrollmentRepository>().InstancePerHttpRequest();
builder.RegisterType<SchoolYearRepository>().As<ISchoolYearRepository>().InstancePerHttpRequest();
builder.RegisterType<GradeLevelRepository>().As<IGradeLevelRepository>().InstancePerHttpRequest();
//builder.RegisterType<SchoolDetailRepository>().As<ISchoolDetailRepository>().InstancePerHttpRequest();
builder.RegisterGeneric(typeof(RepositoryBase<SchoolDetail>)).As(typeof(IRepository<SchoolDetail>));
// build and setup resolver
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
the exception is coming from the above code where the expression you gave me runs..
builder.RegisterGeneric(typeof(RepositoryBase<SchoolDetail>)).As(typeof(IRepository<SchoolDetail>));
RepositoryBase
public abstract class RepositoryBase<T> where T : class
{
private LearningCompactPilotContext _dataContext;
private readonly IDbSet<T> _dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
_dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected LearningCompactPilotContext DataContext
{
get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
}
... more code
}
You need the open generics feature of Autofac:
builder.RegisterGeneric(typeof(RepositoryBase<>))
.As(typeof(IRepository<>));
Then you use your repositories exactly as you described:
public class SomeService
{
private readonly IRepository<SomeEntity> _repository;
public SchoolService(IRepository<SomeEntity> repository)
{
this._repository= repository;
}
}