Update
Tried to clarify my problem
I have a ASP.NET 5 Web Api application. I'm trying to create a controller class that makes use of a custom base controller. As soon as I add a constructor to the base controller then MVC can no longer find the Get() end point defined in the Generic class.
This works:
When I navigate to /api/person then the Get() end point is triggered defined in the Generic class
Generic:
public class Generic
{
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
PersonController
[Route("api/[controller]")]
public class PersonController : Generic
{
}
This doesn't work
When I navigate to /api/person then the Get() end point is not triggered. The only thing that is added is a constructor in both the Generic class and the PersonController class.
public class Generic
{
protected DbContext Context { get; set; }
public Generic(DbContext context)
{
Context = context;
}
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
PersonController
[Route("api/[controller]")]
public class PersonController : Generic
{
public PersonController(DbContext context) : base(context) { }
}
Is this a bug or am I doing something wrong?
Your problem has nothing to do with inheriting from another base class. I think the problem is, a proper implementation of your DbContext is not being injected to the constructor. Since asp.net 5 is so modular/dependency injectable, you need to explicitly configure it.
In the ConfigureServices method in your Startup.cs class, register your DbContext service so MVC will use that and inject that to your class controller when needed.
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddDbContext<DbContext>();
services.AddMvc();
}
Related
I have multiple models for state,country,city ,roles,emails etc.( 30 models)
I have single controller which handles multiple api calls with single API method.
I created 30 different Interfaces which implements to return List of objects.
public interface state
{
IEnumerable<state> GetState();
}
public interface city
{
IEnumerable<city> GetCity();
}
From the controller , through constructor injection , I'm injecting dependency and calling each method based on api parameter "section" using switch .
[Microsoft.AspNetCore.Mvc.HttpGet("{section}")]
public ActionResult GetModelBySection(string section)
{
switch(section)
{
case "country":
return Ok(countryDAL.GetCountry());
...
...
default:
return Ok("Not Found");
}
}
Instead of injecting all 30 interfaces here , I tried using IGeneric . when I use IGeneric , I need to create multiple controller . I dont want to create multiple controller. Please help me here
Created IGeneric interface and implemented in each DAL , and made Controller generic .
public interface IGenericDAL<T> where T : class
{
Task<IEnumerable<T>> GetAllAsync();
Task<T> GetByNameAsync(string name);
long Add(T item);
long Update(T item);
long Delete(long id);
}
public class CityDAL : IGenericDAL<City>
{
.......
}
[Microsoft.AspNetCore.Mvc.Route("api/[controller]")]
[ApiController]
public class CommonController<T> : Controller where T : class
{
private IGenericDAL<T> _generic;
}
I tried as below:
public class GenericDAL<T> : IGenericDAL<T> where T : class
{
......
}
Regist in startup:
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddTransient(typeof(IGenericDAL<>), typeof(GenericDAL<>));
....
}
In controller:
public class HomeController : Controller
{
private readonly IServiceProvider _serviceProvider;
public HomeController( IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IActionResult SomeController()
{
var someservice = (GenericDAL<City>)_serviceProvider.GetService(typeof(IGenericDAL<City>));
var cities = someservice.GetAllAsync().Result;
return OK();
}
}
The Codes excuted successfully:
I am designing a NuGet package that will be consumed by my application. Due to the project's already implemented architecture, I need to provide a way to instantiate objects using dependency injection both for MVC and Web API outside my controller scope.
Currently I have a class that works in MVC projects, by instantiating objects using the DependencyResolver
public abstract class MyBaseClass<T> where T : class
{
public static T Instance
{
get
{
return DependencyResolver.Current.GetService<T>();
}
}
}
However, when consuming this same class from a WebAPI project, the DependencyResolver is not present, so Im not able to retrieve any object.
I have tried to access the dependency resolver via the HttpContext but have been unsuccessfull. Do you have any way I can access it through a NuGet package?
Thanks!
If it's possible, I'd suggest avoid the service locator pattern and inject the dependency through the constructor instead:
public abstract class MyBaseClass<T> where T : class
{
public MyBaseClass(T instance)
{
Instance = instance;
}
public T Instance { get; }
}
This will allow you to use your package through any "main" entry point (e.g. MVC or WebAPI) that you choose. At that point, it would be the responsibility of the consumer to provide the necessary dependency resolution strategy.
Here's an example of how a consumer (in this case a WebAPI service) of the package would implement the above code:
public class MyWebApiClass : MyBaseClass<MyDependency>
{
public MyWebApiClass(MyDependency resolvedDependency) : base(resolvedDependency) { }
}
public class MyDependency
{
public string Foo { get; set; }
public MyDependency()
{
Foo = "Bar";
}
}
Then the consuming service would also register those dependencies:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<MyDependency>();
services.AddTransient<MyWebApiClass>();
}
... and inject as needed, allowing the framework to resolve the dependencies (IoC at work):
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly MyWebApiClass _myWebApiClass;
public ValuesController(MyWebApiClass myWebApiClass)
{
_myWebApiClass = myWebApiClass;
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { _myWebApiClass.Instance.Foo };
}
}
Making a call to the GET endpoint above, we can see our instance being resolved in MyBaseClass:
My Startup is like this :
public void ConfigureServices(IServiceCollection services)
{
// code here
Bootstraper.Setup(services);
}
And my Bootstraper class is like this :
public static partial class Bootstraper
{
// code here
public static IServiceCollection CurrentServiceCollection { get;set;}
public static IServiceProvider CurrentServiceProvider
{
get { return CurrentServiceCollection.BuildServiceProvider(); }
}
public static void Setup(IServiceCollection serviceCollection)
{
// code here
SetupLog();
InitializeCulture();
InitializeDbContexts();
RegisterDataModelRepositories();
}
and this is content of my RegisterDataModelRepositories():
CurrentServiceCollection.AddTransient<IDefAccidentGroupRepository>(p => new DefAccidentGroupRepository(ApplicationMainContextId));
CurrentServiceCollection.AddTransient<IDefGenderRepository>(p => new DefGenderRepository(ApplicationMainContextId));
in short : I just want to be able to use Service Locator in my methods without resolving dependency in class constructor ... is there any way around it ....
Dependency injection can also be done on a by action basis.
Referece Dependency injection into controllers: Action Injection with FromServices
Sometimes you don't need a service for more than one action within your controller. In this case, it may make sense to inject the service as a parameter to the action method. This is done by marking the parameter with the attribute [FromServices]
public IActionResult SomeAction([FromServices] IReportService reports) {
//...use the report service for this action only
return View();
}
Just make sure that the required services are registered with the service collection.
services.AddTransient<IDefAccidentGroupRepository>(p => new DefAccidentGroupRepository(ApplicationMainContextId));
services.AddTransient<IDefGenderRepository>(p => new DefGenderRepository(ApplicationMainContextId));
services.AddTransient<IReportService, ReportService>().
well , thanks for your help ...
There is a easier and better way for it , I just need to add another Service that use these repository and then resolve that service in my controller and let Asp.net Core 2.0 DI to solve the problem for me ...
public interface IActionService
{
IRepositoryA repA {get;set;}
IRepositoryB repB { get;set;}
DoTaskX();
DoTaskY();
}
then in my ActionService :
public class ActionService : IActionService
{
public IRepositoryA repA {get;set;}
public IRepositoryB repB { get;set;}
public ActionService (IRepositoryA rep_a , IRepositoryB rep_b ) {
repA = rep_a;
repB = rep_b;
}
DoTaskX(){
// do task using repository A and B
}
}
then I register IActionService in Startup.cs and resolve itin my ActionController and life become easier and code become cleaner ...
the solution was easy but I had to change my mindset to solve the problem ...
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.
We have a project where we need to use DI and ASP Core.
I'm very new to this and have a question.
I have a controller named HomeController like this:
public class HomeController : BaseController {
private IOrderService _orderService;
public HomeController(IOrderService orderService) {
_orderService = orderService;
}
public IActionResult Index() {
var orders = _orderService.GetMyOrders();
return View(orders);
}
}
The code looks like this:
public class OrderService : BaseService, IOrderService {
public OrderService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public List<Orders> GetMyOrders() {
var orders = // do my code here which works fine!;
// here i need some code do check orders for delivery so
DeliveryService deliveryService = new DeliveryService(_dataContextService);
// update my orders and return these orders
return orders;
}
}
public class DeliveryService : BaseService, IDeliveryService {
public DeliveryService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public void MyMethod() {
}
}
public class BaseService {
protected IDataContextService _dataContextService;
}
Almost all my services have a constructor like the OrderService and DeliveryService. My question is, do I have to pass the _dataContextService every time, or is there a solution within the dependency pattern?
You should keep it the way you have it and asp.net core IoC will inject it for you, but make sure it is injected per request, this will help to insantiate only one context for each request and dispose it after the request is served.
You can register the context and services in the ConfigureServices method inside the Startup class as below
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<HomeController>();
services.AddTransient<IOrderService , OrderService >();
services.AddTransient<IDeliveryService, DeliveryService>();
services.AddScoped<IDataContextService , YourDataContextService >();
}
The AddScoped method will create only one instance of the object for each HTTP request
If I understand correctly what you are asking, you are looking for an IoC container. .NET Core has built in support for dependency injection. Basically, you just indicate which implementation should be provided when an interface is requested. Then the container will instantiate the types for you. See for example https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection.
Hope that helps