I have a service class :
public class MyService : IService
{
private IRepoA repoA;
private IRepoB repoB;
public MyService(IRepoA repoA,IRepoB repoB)
{
this.repoA=repoA;
this.repoB=repoB;
}
}
my Controller depends on the MyService classL
public MyController : DefaultController
{
IService myService;
public MyController(IService service)
{
myService=service;
}
}
how do I inject the MyService class into the controller ?
should i do this ? :
Bind<IPostService>()
.To<PostService>();
Bind<IPostsRepository>()
.To<SqlPostsRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings[0].ConnectionString);
Bind<IUserRepository>()
.To<FakeUserRepository>();
Look at Ninject.Extensions.Mvc. Read the read me and documentation. It has everything you need. From the looks of it, all you'll need is to properly setup your HttpApplication to inherit from NinjectHttpApplication and add the proper config code (all located in the readme/documenation)
You'll want to create your own controller factory that injects the dependencies for you and register that factory in Global.asax.
If you're using structure map, that could look like this:
public class IoCControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Related
I have a Web Api project and using Castle Windsor as the IoC. I have done this quite a few times and honestly I cannot understand why this is not working so here goes everything that I am doing:
Controller on the Web Api project:
Nothing fancy here
public class TestController : ApiController, ITestController
{
... //Currently with its default constructor.
}
Global.asax
public class WebApiApplication : System.Web.HttpApplication
{
private readonly IWindsorContainer container;
public WebApiApplication()
{
container = new WindsorContainer().Install(FromAssembly.Named("DependenciesConfiguration"));
}
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new DiControllerActivator(container));
}
}
DiControllerActivation class
This is the class that is replacing the default controller activator in the Global.asax class.
public class DiControllerActivator : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public DiControllerActivator(IWindsorContainer container)
{
this.container = Argument.NotNull(container, (nameof(container)));
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
//This is the line that fails saying "No component for supporting the service TestController was found.
var controller = (IHttpController)container.Resolve(controllerType);
request.RegisterForDispose(new Release(() => container.Release(controller)));
return controller;
}
}
internal class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
And finally the Web Services Installer
public class ServicesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromAssemblyNamed("WebServices")
.Where(type => type.Name.EndsWith("Controller"))
.WithService.DefaultInterfaces()
.Configure(c => c.LifestylePerWebRequest()));
}
}
What it is really frustrating is that, like I said, I have donde this before, I went to my previous work to see if I was missing anything and I cannot find anything and this has always worked well.
When running the application after the installer runs I can see that the service is in the container and when it fails saying "No component for supporting the service TestController was found" I can still see the service within the container in the Watch Window.
I am using Castle version 4.0
Thank you for any pointers and help.
As it turns out there is a subtle but critical difference in this code from the other times I did this.. The fact that the TestController is implementing an interface and is registered as such messes up the whole thing.
Since the Create method in the DiActivator class is trying to resolve the controller based on its type and not its default interface the container cannot find it.
One solution is just to remove the interface from the controller or to add the necessary code in the Create method that gets the default interface of the received type and resolves for it.
I need to inject out of constructor, everything I declared in Setup.
Ho can I do it ? How can I inject services out of constructor ?
Something like Injector service in Angular 2.
INJECT SERVICES WITHOUT CONSTRUCTOR IN CONTROLLERS
something like this
public class ControllerBase : Controller
{
protected IRepository<Test> _test;
protected IRepository<Test1> _test1;
protected IRepository<Test2> _test2;
public ControllerBase(INJECTOR injector)
{
_test = injector.inject(IRepository<Test>);
_test1 = injector.inject(IRepository<Test1>);
_test2 = injector.inject(IRepository<Test2>);
}
}
public class SomeController : ControllerBase
{
public SomeController(INJECTOR injector)
: base(injector)
{
}
}
THANKS FOR ANSWER #Rick van den Bosch
FOR THOSE WHO STILL CAN'T GET WHAT I WANTED:
public class ControllerBase : Controller
{
protected IRepository<Test> _test;
protected IRepository<Test1> _test1;
protected IRepository<Test2> _test2;
public ControllerBase(IServiceProvider injector)
{
_test = injector.GetService<IRepository<Test>>();
_test1 = injector.GetService<IRepository<Test1>>();
_test2 = injector.GetService<IRepository<Test2>>();
}
}
public class SomeController : ControllerBase
{
public SomeController(IServiceProvider injector)
: base(injector)
{
//HERE I HAVE ALL 3 REPO NOW WITHOUT EXTRA LINES
}
}
public class SomeController1 : ControllerBase
{
public SomeController1(IServiceProvider injector)
: base(injector)
{
//HERE I HAVE ALL 3 REPO NOW WITHOUT EXTRA LINES
}
}
You can inject the service as a parameter to the action method. This is done by marking the parameter with the attribute [FromServices].
This looks something like this:
public IActionResult About([FromServices] IDateProvider dateProvider)
{
ViewData["Message"] = $"Current date is {dateProvider.CurrentDate}";
return View();
}
If you're looking for default services in a BaseController: you could go about that several ways:
1. Still use a constructor
This would look something like this:
public class HomeController : BaseController
{
public HomeController(IDateProvider dateProvider) : base(dateProvider)
{
}
}
and
public class BaseController
{
protected IDateProvider _dateProvider;
protected BaseController(IDateProvider dateProvider)
{
_dateProvider = dateProvider;
}
}
This way the IDateProvider is available to both the BaseController and all inheriting Controllers.
2. Resolve services manually
This way you resolve the service manually. This could be in the BaseController, and only when you need them (lazy). For more info, see this post.
For simplicity and readability I would probably choose the constructor one.
I have the following problem and I currently have a solution using conditional dependency injection. I have read that this is a bad idea, such as here in the SimpleInjector docs. I have read a large number of posts now and have seen various things suggesting using Strategy, Factory patterns, etc. What I am really looking for is some specifics - i.e. an example of some code - about how to solve without conditional injection. I need more that "use a factory". Here's a simplified version of my code. This is in an MVC web app, thus the controllers.
public abstract class QAControllerBase : Controller
{
protected readonly QABusinessLayer _blQA;
public QAControllerBase(QABusinessLayer bl)
{
_blQA = bl;
}
[HttpGet]
public ActionResult PPR(string accession, string site)
{
var m = _blQA.popPPRViewModel(accession);
return View(m);
}
}
public class QASouthController : QAControllerBase
{
public QASouthController([QASouthBinding] QABusinessLayer bl) : base(bl)
{
}
// some actions that are specific to South
}
public class QANorthController : QAControllerBase
{
public QANorthController([QANorthBinding] QABusinessLayer bl) : base(bl)
{
}
// some actions that are specific to North
}
public abstract class QABusinessLayer
{
protected readonly IFullBaseRepo _repo;
public QABusinessLayer(IFullBaseRepo repo)
{
_repo = repo;
}
public abstract PPRViewModel popPPRViewModel(string accession);
protected PPRViewModel DoSomeCommonStuff(PPRViewModel model)
{
...
return model;
}
}
public class SouthBusinessLayer: QABusinessLayer
{
public SouthBusinessLayer([QASouthBinding] IFullBaseRepo repo) : base(repo)
{
}
public override PPRViewModel popPPRViewModel(string accession)
{
var m = new PPRViewModel();
// do some stuff that is specific to South
DoSomeCommonStuff(m);
return m;
}
}
public class NorthBusinessLayer : QABusinessLayer
{
public NorthBusinessLayer([QANorthBinding] IFullBaseRepo repo) : base(repo)
{
}
public override PPRViewModel popPPRViewModel(string accession)
{
var m = new PPRViewModel();
// do some stuff that is specific to North
DoSomeCommonStuff(m);
return m;
}
}
and here is the Ninject binding code that is pertinent:
kernel.Bind<QABusinessLayer>()
.To<SouthBusinessLayer>()
.WhenTargetHas<QASouthBinding>()
.InRequestScope();
kernel.Bind<QABusinessLayer>()
.To<NorthBusinessLayer>()
.WhenTargetHas<QANorthBinding>()
.InRequestScope();
The QASouthBinding and QANorthBinding are just simple attributes. I am not asking for Ninject specific example. Any code sample as to how this might be handled without using conditional or context based injection as I am now.
Make your QABusinessLayer class abstract.
Change your startup configuration to:
kernel
.Bind<SouthBusinessLayer>()
.To<SouthBusinessLayer>()
.InRequestScope();
kernel
.Bind<NorthBusinessLayer>()
.To<NorthBusinessLayer>()
.InRequestScope();
Change your controller constructors to accept a concrete business layer type:
public class QANorthController : QAControllerBase
{
public QANorthController(NorthBusinessLayer businessLayer) : base(businessLayer)
{
}
}
public class QASouthController : QAControllerBase
{
public QASouthController(SouthBusinessLayer businessLayer) : base(businessLayer)
{
}
}
Few things:
If Ninject auto-binds concrete types to the same type, then you don't need to manually configure the dependencies during startup.
You may want to use an interface rather than just passing your concrete BusinessLayer type.
My current Autofac config is working to resolve my ApiControllers in a WebApi.
Where I'm struggling is, I'm attempting to create a 'BaseApiController' with generic constructor parameters, but getting exception:
No constructors on type 'Service`1[WorldRegion]' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.
Here is the code structure:
public interface IEntityKey { }
public class WorldRegion : IEntityKey { }
public interface IRepository<T> where T : IEntityKey { }
public interface IService<T> where T : IEntityKey { }
public abstract class Service<T> : IService<T> where T : IEntityKey { }
public interface IWorldRegionService : IService<WorldRegion> { }
public class WorldRegionService : Service<WorldRegion>, IWorldRegionService
{
private readonly IRepository<WorldRegion> _repository;
}
WORKING API Controller:
public class WorldRegionsController : BaseApiController
{
private readonly IWorldRegionService _worldRegionService;
private readonly ICultureService _cultureService;
public WorldRegionsController(IWorldRegionService worldRegionService, ICultureService cultureService)
{
_worldRegionService = worldRegionService;
_cultureService = cultureService;
}
}
WORKING Autofac config:
public static void Register(HttpConfiguration config, IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
RegisterTypes(builder);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
}
public static void RegisterTypes(ContainerBuilder builder)
{
// Context
builder.RegisterType<DataContext>().As<IDataContext>().InstancePerRequest();
// UOW
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
// Repositories
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerRequest();
// Services
builder.RegisterType<CultureService>().As<ICultureService>().InstancePerRequest();
builder.RegisterType<WorldRegionService>().As<IWorldRegionService>().InstancePerRequest();
}
Here is the generic ATTEMPT:
// BaseApiController
public abstract class BaseApiController<T> : ApiController where T : IEntityKey
{
protected readonly IService<T> _service;
protected readonly ICultureService _cultureService;
public BaseApiController(IService<T> service, ICultureService cultureService)
{
_service = service;
_cultureService = cultureService;
}
}
// ApiController
public class WorldRegionsController : BaseApiController<WorldRegion>
{
public WorldRegionsController(
IService<WorldRegion> service, ICultureService cultureService)
: base(service, cultureService) {}
}
// Added to Autofac config
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerRequest();
// Removed
builder.RegisterType<WorldRegionService>().As<IWorldRegionService>().InstancePerRequest();
With this change, I'm getting the exception message noted above (in yellow). I think I'm missing something in the Autofac config, just not sure what. Maybe include/register/add 'WorldRegion' somehow.
How should I register my types ?
Your controller expect a IService<WorldRegion>. Autofac find the following registration for this service :
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerRequest();
So it tries to create a Service<WorldRegion> which is not possible because Service<T> is an abstract class.
Don't forget that a IWorldRegionService is a IService<WorldRegion> but a IService<WorldRegion> is not a IWorldRegionService.
You don't want to register a generic service but want to register all children as a IService<T>, you can do this by using the RegisterAssemblyTypes method with the AsClosedTypedOf
builder.RegisterAssemblyTypes(this.GetAssemblies())
.AsClosedTypesOf(typeof(IService<>));
Read Autofac documentation - Assembly scanning for more information and how to properly implement the GetAssemblies method in IIS.
At first, I tried removing the abstract from Service<T>, that didn't work, same error. Then I read the Autofac docs and searched around, and I found something similar to Cyril's answer that works:
builder.RegisterAssemblyTypes(typeof(Service<>).Assembly)
.Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces();
I tried Cyril's implementation of builder.RegisterAssemblyTypes() but this.GetAssemblies() wasn't available. I had to use the full path and this also works:
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IService<>));
To note, using either builder.RegisterTypes(), the Service<T> can still be abstract. And just to test, I changed WorldRegionService to abstract, and that DID NOT work.
// THIS DOES NOT WORK..!!!! Must remove 'abstract' from this class.
public abstract class WorldRegionService {}
So both above builder.RegisterTypes() work.
I have following interfaces, abstract classes etc.
public interface IAggregateRootMapping<T> : IAggregateDefinition where T : AggregateRoot
{
IEnumerable<Expression<Func<T, object>>> IncludeDefinitions { get; }
}
public abstract class AggregateRootMapping<T> : IAggregateRootMapping<T> where T : AggregateRoot
{
public abstract IEnumerable<Expression<Func<T, object>>> IncludeDefinitions { get; }
}
public class OrderAggregateRootMapping : AggregateRootMapping<Order>
{
public override IEnumerable<Expression<Func<Order, object>>> IncludeDefinitions
{
get
{
return new Expression<Func<Order, object>>[] {
order => order.Supplier
};
}
}
}
I use those in another class like this:
public class Repository<TAggregateRoot> : IRepository<TAggregateRoot> where TAggregateRoot : AggregateRoot
{
private readonly AggregateRootMapping<TAggregateRoot> _aggregateRootMapping;
public Repository(AggregateRootMapping<TAggregateRoot> aggregateRootMapping)
{
_aggregateRootMapping = aggregateRootMapping;
}
Do something...
}
How do I use the dependency injection of ASP.NET Core so that on runtime the matching class is injected?
For example if the AggregateRoot type class is Order than for the Repository class the OrderAggregateRootMapping class should be injected.
How do I use the ServiceCollection in ConfigureServices of the Startup class in .NET Core to accomplish this?
The dependency injection that comes by default is very basic. If you want to start wiring up rules based on generics, you will need to use a different implementation.
But, what you're after is still possible if you're willing to code the dependencies one by one.
In your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<AggregateRootMapping<Order>, OrderAggregateRootMapping>();
services.AddScoped<Repository<Order>>();
// Add framework services.
services.AddMvc();
}
And then you can use your Repository class by injecting it into a controller, for example.
In ValuesController.cs
[Route("api/[controller]")]
public class ValuesController : Controller
{
private Repository<Order> _repository;
public ValuesController(Repository<Order> repository)
{
_repository = repository;
}
}
ValuesController will then receive an instance of Repository<Order> which will have been created with a OrderAggregateRootMapping.