This question already has an answer here:
How to implement a UserFactory using IHttpContextAccessor
(1 answer)
Closed 4 years ago.
I am trying to recreate HttpContext.Current in vNext but I am having trouble with this.
The code so far:
public class CurrentContext
{
public IHttpContextAccessor ctx { get; private set; }
public CurrentContext(IHttpContextAccessor accessor)
{
ctx = accessor;
}
}
services.AddTransient<CurrentContext>();
I want to use:
public static class UserFactory
{
public static void SetCurrentUser(User u)
{
//tryed to get the context but GetService returns null
IHttpContextAccessor _context = ((CurrentContext)CallContextServiceLocator.Locator.ServiceProvider.GetService(serviceType: typeof(CurrentContext))).ctx;
//add the user to the Session
}
}
How can I now get an instance of CurrentContext anywhere in the project?
I do not use the vNext DI system, but I believe you should define an interface for your CurrentContext, e.g.
public interface IContextProvider {
IHttpContextAccessor GetContext();
}
And then use
public class CurrentContextProvider : IContextProvider
{
private readonly IHttpContextAccessor _context;
public CurrentContextProvider(IHttpContextAccessor accessor)
{
_context = accessor;
}
public IHttpContextAccessor GetContext() {
return _context;
}
}
And wire
services.AddScoped<IContextProvider, CurrentContextProvider>();
But if you are going to just use the context, why dont just depend directly on the IHttpContextAccessor - where you need it?
You should declare the variable of the CurrentContext type in constructors of dependent classes:
public class SomeClassThatUsesCurrentContext
{
private readonly SomeClassThatUsesCurrentContext currentContext;
public SomeClassThatUsesCurrentContext(CurrentContext currentContext)
{
if (currentContext == null)
throw new ArgumentNullException("currentContext");
this.currentContext = currentContext;
}
}
These classes may occur in constructors of other classes. Finally you usually resolve from the DI container the single instance of the high level class. The place where you do it is called composite root.
And, as #janhartmann says, usually you should use interfaces or abstract classes instead of concrete classes.
Related
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();
}
}
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.
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 creating an instance of a type scoped to HTTPContextScoped. I am trying to figure out how to inject this specific instance into a property of the same type into an attribute that I don't have control over.
I want to inject the specific instance of UnitOfWork into a property of IUnitOfWork type in an attribute (see code below)
Here is my ObjectFactory.Initialize() method of the part that I am referring to:
ObjectFactory.Initialize(x =>
{
//...
//additional content
//...
x.For<IUnitOfWork>()
.HttpContextScoped()
.Use(context => new UnitOfWork(
context.GetInstance<ISessionFactory>()));
x.SetAllProperties(context =>
{
context.Matching(p =>
p.DeclaringType == typeof(UnitOfWorkAttribute));
context.OfType<IUnitOfWork>();
});
Attribute Class:
public class UnitOfWorkAttribute : ActionFilterAttribute {
public IUnitOfWork UnitOfWork { get; set; }
public UnitOfWorkAttribute() {
Order = 0;
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
UnitOfWork.Begin();
}
public void OnActionExecuted(ActionExecutedContext filterContext) {
UnitOfWork.End();
}
}
I was trying to follow one of Jeremy Miller's examples of using criteria to do so, but I am not doing something right.
Any thoughts of what I am doing incorrectly?
NOTE It does create the UnitOfWork instance as I use it else where, but I am specifically not correctly (or at all) injecting this attribute's property with that instance (or any for that matter).
Try solving this problem by creating a factory for IUnitOfWork objects. Since the lifetime of unit of work instances must be controlled explicly (since you are doing Begin and End, controlling them yourself is much more logical, and adheres the principle of least surprise.
Here is an example of what you can do:
public interface IUnitOfWorkFactory
{
IUnitOfWork NewUnitOfWork();
}
public class MyController : Controller
{
private readonly IUnitOfWorkFactory factory;
public MyController(IUnitOfWorkFactory factory)
{
this.factory = factory;
}
public void Operation()
{
using (var work = new this.factory.NewUnitOfWork())
{
work.Begin();
// do some interesting stuff here.
work.End();
}
}
}
My Entity class has a dependency on a Repository.
public class User
{
private readonly IUserRepository _userRepository;
public User(IUserRepository userRepository)
{
_userRepository = userRepository;
}
...
}
And I have an EntityFactory class used by the Repository to create entities.
public class UserRepository : IUserRepository
{
private readonly EntityFactory _entityFactory;
public UserRepository(EntityFactory entityFactory)
{
_entityFactory = entityFactory;
}
...
}
// EntityFactory #1 with no references or dependencies to DI frameworks or CommonServiceLocator
public class EntityFactory
{
public User InstantiateUser()
{
return new User(); // Requires IUserRepository parameter
}
}
// EntityFactory #2 with reference to Ninject
using Ninject;
public class EntityFactory
{
private readonly IKernel _kernel;
public EntityFactory(IKernel kernel)
{
_kernel = kernel;
}
public User InstantiateUser(IKernel kernel)
{
return new User(_kernel.Get<IUserRepository>());
}
}
// EntityFactory #3 with reference to CommonServiceLocator
using Microsoft.Practices.ServiceLocation;
public class EntityFactory
{
public User InstantiateUser()
{
return new User(ServiceLocator.Current.GetInstance<IUserRepository>());
}
}
Is there a way to avoid the EntityFactory having a reference to the container or using the CommonServiceLocator? (Context Agnostic)
Or am I just designing my classes wrong and the User class should not have a dependency on any Repositories?
Edit: Here is the code using the method from David:
// Ninject binding
Bind<Func<User>>().ToMethod(cxt => () => new User(cxt.Kernel.Get<IUserRepository>()));
// EntityFactory class
private readonly Func<User> _userFactory;
public EntityFactory(Func<User> userFactory)
{
_userFactory = userFactory;
}
public User InstantiateUser()
{
return userFactory.Invoke();
}
Your DI framework should provide you with a method of creating factories:
public class EntityFactory
{
public EntityFactory(Func<User> userFactory) { /* ... */ }
public User InstantiateUser()
{
return userFactory.Invoke();
}
}
When the EntityFactory is created it'll receive a proper User factory which can then be used to create properly resolved users without any reference to the IoC.
What's wrong with option 2 or 3? If you are using IoC or a service locator, you will need to have a reference to it somewhere.
I have a global reference to the IoC container and use that to resolve the interfaces all over the place. This looks a lot like the service locator, but then instead using the IoC container.
I don't believe there is a way around this.