Dependency Injection pass parameters by constructor - c#

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

Related

AddSingleton doesn't work in my ASP.NET Core project

I have the problem that I want to add my service CourseService as Singleton and I want to add only once my initial data like this:
context.Courses.Add(new Course { ... });
But it turned out that every time when I upload my page with courses my initial data added again and again to my database. So I see the same courses on my page as much time as I upload this page. Can't understand where is the problem.
My interface:
public interface ICourseService
{
IEnumerable<CourseDto> GetCourses();
Task<IEnumerable<CourseDto>> GetCoursesAsync();
}
My service:
public class CourseService : BaseService<Course, CourseDto>, ICourseService
{
public CourseService(IMapper mapper, DataContext context) : base(mapper,context)
{
context.Courses.Add(new Course { ... });
context.Courses.Add(new Course { ... });
context.SaveChanges();
}
public IEnumerable<CourseDto> GetCourses() { ... }
public async Task<IEnumerable<CourseDto>> GetCoursesAsync() { ... }
}
My controller:
public class CourseController : Controller
{
private readonly CourseService _courseService;
public CourseController(CourseService courseService)
{
_courseService = courseService;
}
[Route("courses")]
public async Task<IActionResult> GetCourses()
{
var courses = await _courseService.GetAllAsync();
return View("CourseList", courses);
}
}
And I added my service as Singleton in the method ConfigureServices:
services.AddSingleton<ICourseService, CourseService>();
services.AddEntityFrameworkSqlite().AddDbContext<DataContext>();
AddDbContext by default adds context with Scoped lifetime, so it can't be resolved in singleton services. Possible workarounds:
register ICourseService as scoped
register context as scoped or transient (would not recommend)
inject IServiceScopeFactory and use it to create scope and resolve context from the scope (on each method call), like in this answer
Personally I would go with the first approach.
Read more:
Service lifetimes
Data seeding in EF Core

How to refactor from static methods to Dependency Injection using MS.DI and .NET Core?

I am in the process of migrating a project from .Net Framework to .Net Core. In the existing project we have a utility class with a few functions like below:
public static class BudgetUtilities
{
public static decimal CalculateBudgetRemaining(string fiscalYear = null)
{
if (string.IsNullOrWhiteSpace(fiscalYear))
fiscalYear = DateTime.Now.GetFiscalYear().ToString();
using (AppContext _context = new AppContext())
{
FiscalYearBudget currentBudget = _context.FiscalYearBudgets.Find(fiscalYear);
return currentBudget.BudgetAllocation - currentBudget.ExpenditureToDate;
}
}
// other functions removed for brevity
}
I can then reference it anywhere else using BudgetUtilities.CalculateBudgetRemaining(). Very simple and straightforward.
When migrating this function to .Net Core I need to use Dependency Injection so I have amended the class by removing the static modifier (since static constructors cannot have parameters) and injecting the AppContext into the constructor:
public class BudgetUtilities
{
private readonly AppContext _context;
public BudgetUtilities(AppContext context)
{
_context = context;
}
public decimal CalculateBudgetRemaining(string financialYear = null)
{
if (string.IsNullOrWhiteSpace(fiscalYear))
fiscalYear = DateTime.Now.GetFiscalYear().ToString();
FiscalYearBudget currentBudget = _context.FiscalYearBudgets.Find(fiscalYear);
return currentBudget.BudgetAllocation - currentBudget.ExpenditureToDate;
}
}
I then tried to call my code by doing the following:
BudgetUtilities utils = new BudgetUtilities();
decimal remaining = utils.CalculateBudgetRemaining();
But I cannot make a new instance of BudgetUtilities without providing an AppContext in the constructor which makes sense. Every method in this application is at some point initiated by a controller action, and I know that DbContexts are supposed to be short lived, so I assume passing the context the whole way down to this BudgetUtilities class from the initial controller is a bad idea.
The only other option I can see is to keep going back up the call stack from where CalculateBudgetRemaining() is referenced and keep adding in constructor injections until I get to a controller but this is not the only class I will have to inject like this so my constructors further up the chain are going to be really bloated and this will make my ConfigureServices() method bloated too.
I'm sure there's a simple way to do this but I just can't see it.
Don't manually create a new BudgetUtilities instance, that type should also be registered with the DI Framework, preferably interfaced:
public interface IBudgetUtilities
{
decimal CalculateBudgetRemaining(string financialYear);
}
public class BudgetUtilities : IBudgetUtilities
Then in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddScoped<IBudgetUtilities, BudgetUtilities>();
}
Then it can be injected into any class that needs it, such as a controller:
public class YourController : Controller
{
private readonly IBudgetUtilities _utils;
public YourController(IBudgetUtilities utils)
{
_utils = utils;
}
public ActionResult YourMethod()
{
//...
decimal remaining = _utils.CalculateBudgetRemaining();
}
}
By default, registered DbContexts have a scoped lifetime, which means a single instance is used for the entirety of a HTTP request.

How to access dependency resolver in ASP.NET WebAPI in external library

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:

How to configure services based on request in ASP.NET Core

In ASP.NET Core we can register all dependencies during start up, which executed when application starts. Then registered dependencies will be injected in controller constructor.
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
public IActionResult Get()
{
vart report = _reportFactory.Create();
return Ok(report);
}
}
Now I want to inject different implementations of IReportFactory based on data in current request (User authorization level or some value in the querystring passed with an request).
Question: is there any built-in abstraction(middleware) in ASP.NET Core where we can register another implementation of interface?
What is the possible approach for this if there no built-in features?
Update
IReportFactory interface was used as a simple example. Actually I have bunch of low level interfaces injected in different places. And now I want that different implementation of those low level interfaces will be injected based on request data.
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
public IActionResult Create()
{
var order = _orderService.Create();
return Ok(order);
}
}
public class OrderService
{
private OrderBuilder _orderBuilder;
private IShippingService _shippingService; // This now have many different implementations
public OrderService(
OrderBuilder _orderBuilder,
IShippingService _shippingService)
{
_orderService = orderService;
_shippingService = shippingService;
}
public Order Create()
{
var order = _orderBuilder.Build();
var order.ShippingInfo = _shippingService.Ship();
return order;
}
}
Because we know which implementation we need to use on entry point of our application (I think controller action can be considered as entry point of application), we want inject correct implementation already there - no changes required in already existed design.
No, you can't. The IServiceCollection is populated during application startup and built before Configure method is called. After that (container being built), the registrations can't be changed anymore.
You can however implement an abstract factory, be it as factory method or as an interface/class.
// Its required to register the IHttpContextAccessor first
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IReportService>(provider => {
var httpContext = provider.GetRequired<IHttpContextAccessor>().HttpContext;
if(httpContext.User.IsAuthorized)
{
return new AuthorizedUserReportService(...);
// or resolve it provider.GetService<AuthorizedUserReportService>()
}
return new AnonymousUserReportService(...);
// or resolve it provider.GetService<AnonymousUserReportService>()
});
Alternatively use an abstract factory class
I'm afraid you can not directly acheive the goal via simple dependency injection , as the the dependency injection configured at Startup stage , in other words , all services and implementions has been configured before a request comming .
However , you can inject a Create Service delegate so that can we create the required service implemention instance in runtime .
For instance , if we have a IReportFactory Interface and two implementions as blew :
public interface IReportFactory
{
object Create();
}
public class ReportFactory1 : IReportFactory
{
public object Create()
{
return new { F = 1, };
}
}
public class ReportFactory2 : IReportFactory {
public object Create()
{
return new { F = 2, };
}
}
As we want to get the required implemention in future , we need to register the Implementions first .
services.AddScoped<ReportFactory1>();
services.AddScoped<ReportFactory2>();
and here's where the magic happens :
We don't register a IReportFactory
We just add a Func<HttpContext,IReportFactory> instead , which is a CreateReportFactoryDelegate
public delegate IReportFactory CreateReportFactoryDelegate(Microsoft.AspNetCore.Http.HttpContext context);
We need add the CreateReportFactoryDelegate to servies too.
services.AddScoped<CreateReportFactoryDelegate>(sp => {
// return the required implemention service by the context;
return context => {
// now we have the http context ,
// we can decide which factory implemention should be returned;
// ...
if (context.Request.Path.ToString().Contains("factory1")) {
return sp.GetRequiredService<ReportFactory1>();
}
return sp.GetRequiredService<ReportFactory2>();
};
});
Now , we can inject a CreateReportFactoryDelegate into controller :
public class HomeController : Controller
{
private CreateReportFactoryDelegate _createReportFactoryDelegate;
public HomeController(CreateReportFactoryDelegate createDelegate) {
this._createReportFactoryDelegate = createDelegate;
// ...
}
public async Task<IActionResult> CacheGetOrCreateAsync() {
IReportFactory reportFactory = this._createReportFactoryDelegate(this.HttpContext);
var x=reportFactory.Create();
// ...
return View("Cache", cacheEntry);
}
}
It is possible by using the HttpContextAccessor in Startup.cs
services.AddHttpContextAccessor();
services.AddScoped<IYourService>(provider =>
{
var contextAccessor = provider.GetService<IHttpContextAccessor>();
var httpContext = contextAccessor.HttpContext;
var contextVariable = httpContext. ...
// Return implementation of IYourService that corresponds to your contextVariable
});
Expanding on #JohanP comment about using IEnumerable
//Program.cs
//get the builder
var builder = WebApplication.CreateBuilder(args);
//register each type
builder.Services.AddScoped<IReport,Report1>();
builder.Services.AddScoped<IReport,Report2>();
builder.Services.AddScoped<IReport,Report3>();
//register the factory class
builder.Services.AddScoped<IReportFactory,ReportFactory>();
//IReport Interface
public interface IReport
{
string ReportType{ get; set; }
}
//ReportFactory.cs
public class ReportFactory : IReportFactory
{
private IEnumerable<IReport> _handlers;
//ctor
public ReportFactory(IEnumerable<IReport> handlers)
=> _handlers = handlers;
internal IReport? Creat(string reportType) =>
_handlers.Where(h => h.ReportType== reportType).First();
}
//Controller
public class ReportController
{
private IReportFactory _reportFactory;
public ReportController(IReportFactory reportFactory)
{
_reportFactory = reportFactory;
}
//modify to your project needs
public IActionResult Get([FromBody] string reportType)
{
if (HttpContext.User.IsAuthorized)
{
var report = _reportFactory.Create(reportType);
return Ok(report);
}
}
}

Asp.net Core 2 - How to use ServiceLocator in Asp.net Core 2.0

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 ...

Categories

Resources