Blazor FluentValidation how to Inject dependency to AbstractValidator - c#

I am using FluentValidator for a current Blazor-Server Project.
Now i need to inject my database service class for validate duplication and stuff like that.
public class StockValidator : AbstractValidator<LagertypModel>
{
private StockOverviewService _stockservice;
public StockValidator(StockOverviewService stockservice)
{
_stockservice = stockservice;
RuleFor(LagertypModel => LagertypModel.Lagertyp).NotEmpty().MaximumLength(4).Must(Lagertyp => {
return _stockservice.validateStockTypeCU(Lagertyp).Result;
});
}
}
But when i do that i get the error that StockValidator needs to have a parameterless contructor.
How can i inject my dependency now?

Where you instantiate your StockValidator class make sure you pass your service into it like so:
Program.cs
builder.Services.AddSingleton<StockOverviewService>();
StockOverviewService.cs
private StockValidator_validator;
public StockOverviewService(LiveConnectionString connectionString)
{
_connectionString = connectionString;
_validator = new StockValidator(this);
}
StockValidator.cs
public class StockValidator : AbstractValidator<LagertypModel>
{
private StockOverviewService _stockservice;
public StockValidator(StockOverviewService stockservice)
{
_stockservice = stockservice;
RuleFor(LagertypModel => LagertypModel.Lagertyp).NotEmpty().MaximumLength(4).Must(Lagertyp => {
return _stockservice.validateStockTypeCU(Lagertyp).Result;
});
}
}
Assuming your StockOverviewService uses async methods for accessing a DB/Api, I don't recommend this approach because you're making the code run synchronously here:
return _stockservice.validateStockTypeCU(Lagertyp).Result;
but it will work.

Related

Dependency Injection Ensure that you have not accidentally loaded the same module twice

I am using Ninject for Dependency Injection. I have to call two identical classes in the constructor.
public EsyonluAntennaManager(
IModbusActuatorService dksEkbService1, IModbusActuatorService dksEkbService2)
{
_dksEkbService1 = dksEkbService1;
_dksEkbService2 = dksEkbService2;
}
IModbusActuatorService and ModbusActuatorManager are connected to each other.
public ModbusActuatorManager(
ISocketDeviceDal socketDeviceDal,
IDataBaseErrorService dataBaseError,
IDataBaseService dataBase,
Code code)
{
_socketDeviceDal = socketDeviceDal;
_dataBaseError = dataBaseError;
_dataBase = dataBase;
_code = code;
}
The ISocketDeviceDal's constructor does not take any arguments. IDataBaseErrorService and IDataBaseService have only one argument in constructor.
Bind<IDataBaseService>().To<DataBaseManager>()
.WithConstructorArgument("path", _pathDbLog);
Bind<IDataBaseErrorService>().To<DataBaseErrorManager>()
.WithConstructorArgument("path", _pathDbError);
Bind<ISocketDeviceDal>().To<SocketDeviceDal>();
Bind<IModbusActuatorService>().To<ModbusActuatorManager>()
.WithConstructorArgument("code", _code);
Bind<IKamciAntennaService>().To<KamciAntennaManager>();
I observed Injection Ensure that you have not accidentally loaded the same module twice this error. How can I do that? How can Inject IKamciAntennaService and KamciAntennaManager
public static T GetService<T>(
string pathDbError, string pathDbLog, Code _code,Code _code1)
{
var kernel = new StandardKernel(
new DependecyInjection(pathDbError, pathDbLog, _code),
new DependecyInjection(pathDbError, pathDbLog, _code1));
return kernel.Get<T>();
}
UPDATED
I fixed the problem.
public EsyonluAntennaManager(
[Named("Local")]IModbusActuatorService dksEkbService1,
[Named("Remote")] IModbusActuatorService dksEkbService2)
{
_dksEkbService1 = dksEkbService1;
_dksEkbService2 = dksEkbService2;
}
Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope()
.Named("Remote").WithConstructorArgument("code", _codeRemote);
Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope()
.Named("Local").WithConstructorArgument("code", _codeLocal);
The common solution to this issue is to employ the factory pattern.
You create a factory, that based on some paramter set, during runtime, decide which of the classes to use, and then you merely dependency inject that factory.
public interface IDksServiceFactory
{
IDkservice ResolveDksService()//add some input paraameters?
}
public DksServiceFactory : IDksServiceFactory
{
public IDkservice ResolveDksService()
{
if()//something?
{
return new DksEkbService1();
}
else
{
return new DksEkbService2();
}
}
}
public interface IDksService() // implement the interface for your "identical" services.
{
}
public class DksEkbService1 : IDksService
{
}
public class DksEkbService2 : IDksService
{
}
and then in your services, you just add the factory, and use the "resolve method" on the object from your constructor to find the class you need.

Implementing the Options pattern with a class injected during ConfigureServices - AddScoped

I have a small class to obtain a series of information about my user on several of my MVC applications. A minimal reproducible example would be:
public class InformationGetter
{
public string GetUserInformation(string connectionStr, string storedProcedureName, int userId)
{
// Do SQL work
return info;
}
}
I'm injecting it on the ConfigureServices step using
services.AddScoped<InformationGetter>
And then in my classes I simply call it from the DI.
Now, obviously the connectionStr and storedProcedure only changes per application but right now I'm passing it as parameter.
I've tried to make those parameters public and configure it using services.Configure but when I call it from my controllers, I get null values.
services.AddOptions();
services.Configure<InformationGetter>(options =>
{
options.ConnectionString = Configuration.GetSection("Model").GetSection("ConnectionString").Value;
options.StoredProcedureName = "prInformationGetter";
});
I'm not sure if the reason why this is failing it's because I'm missing an interface on my original class or am I failing to understand this concept.
I've also thought on doing something like services.AddInformationGetter(options => {}) but my understanding is that this pattern is to implement middlewares and not DI specifically.
I tried checking the documentation (learn.microsoft.com) but I got even more confused.
There may be misunderstanding of the concepts involved.
Configure<TOption> will register IOptions<TOptions>. There are now two separate registrations in your example.
Once when you register the class
services.AddScoped<InformationGetter>()
and the other when you register the options.
Do the following
//..
services.AddOptions();
//Adds IOptions<InformationGetter>
services.Configure<InformationGetter>(options => {
options.ConnectionString = Configuration.GetSection("Model").GetSection("ConnectionString").Value;
options.StoredProcedureName = "prInformationGetter";
});
//Adds InformationGetter but gets it from the registered options
services.AddScoped<InformationGetter>(sp =>
sp.GetRequiredService<IOptions<InformationGetter>>().Value
);
//...
The scoped registration will use the factory delegate to extract the options registered and return the desired type.
public class InformationGetter {
public string ConnectionString { get; set; }
public string StoredProcedureName { get; set; }
//...
public string GetUserInformation(int userId) {
// Do SQL work
return info;
}
}
InformationGetter looks like a service.
I would suggest refactoring to follow a more Single Responsibility Principle (SRP) and Separation of Concerns (Soc) design.
//Needed by InformationGetter to perform its function
public class InformationGetterOptions {
public string ConnectionString { get; set; }
public string StoredProcedureName { get; set; }
}
//abstraction of InformationGetter
public interface IInformationGetter {
string GetUserInformation(int userId);
}
//implementation.
public class InformationGetter : IInformationGetter{
private readonly InformationGetterOptions options;
public InformationGetter(InformationGetterOptions options) {
this.options = options;
}
public string GetUserInformation(int userId) {
//use values in options to connect
// Do SQL work
return info;
}
}
I would have avoid options pattern altogether and just registered the class using the delegate factory, extracting what I need from configuration. That way your code is not tightly coupled to framework concerns like IOptions
public void ConfigureServices(IServiceCollection services) {
//...
InformationGetterOptions options = new InformationGetterOptions {
ConnectionString = Configuration.GetSection("Model").GetSection("ConnectionString").Value;
StoredProcedureName = "prInformationGetter";
};
services.AddSingleton(options);
services.AddScoped<IInformationGetter, InformationGetter>();
//...
}
Now IInformationGetter can be injected where needed and have all the necessary dependencies to perform its function.

ASP.NET Core DI in a class library?

I have a ASP.NET Core 2.1 project that references a "Data Access Layer" project of typ .NET Core Class Library.
The Data Access Layger needs connection string from the appsettings.json in the ASP.NET Core project.
I have created a simple container like this :
public class DatabaseConnectionString : IDatabaseConnectionString
{
private readonly string _connectionString;
public DatabaseConnectionString(string connectionString)
{
_connectionString = connectionString;
}
public string ConnectionString {
get { return _connectionString; }
set { }
}
}
In the ASP.NET Core Startup.cs > ConfigureService I have this :
services.AddScoped<IDatabaseConnectionString>(p => new DatabaseConnectionString(Configuration.GetConnectionString("DefaultConnection")));
I know that I can add the IDatabaseConnectionString to a constructor of a controller in ASP.NET to get the container. But How do I get it while in the class library? I dont want to pass it all the way down from the controller and just adding the IDatabaseConnectionString to the constructor of a class in the class library do not work.
I probably need a service where I can ask to create a object of a class and let the service fill in the constructor interfaces with the correct objects?
For example filling in the IDatabasConnectionString in this class :
public class UserFactory : FactoryBase
{
private readonly IDatabaseConnectionString _iDatabaseConnectionString;
public UserFactory(IDatabaseConnectionString connectionString)
{
_iDatabaseConnectionString = connectionString;
}
}
I know that I can add the IDatabaseConnectionString to a constructor of a controller in ASP.NET to get the container.
No, that's not needed and it would be wrong.
just adding the IDatabaseConnectionString to the constructor of a class in the class library do not work.
It doesn't work because you need to create the service that will use the connection string and add it to the services container.
For example:
public class Repository: IRepository
{
public Repository(IDatabaseConnectionString databaseConnectionString)
{
_databaseConnectionString = databaseConnectionString;
}
}
public class ServiceThatRequiresDatabase : IServiceThatRequiresDatabase
{
public ServiceThatRequiresDatabase(IRepository repository)
{
_repository = repository;
}
}
// ...
services.AddScoped<IRepository, Repository>();
services.AddScoped<IServiceThatRequiresDatabase, ServiceThatRequiresDatabase>();
public class HomeController : Controller
{
public HomeController(IServiceThatRequiresDatabase service)
{
_service = service;
}
}
By the way, as #YeldarKurmangaliyev said, your DatabaseConnectionString should be like this if you want to make it read-only:
public class DatabaseConnectionString : IDatabaseConnectionString
{
public string ConnectionString { get; }
public DatabaseConnectionString(string connectionString)
{
ConnectionString = connectionString;
}
}
There is no difference between controller and class from a class library. You need to
Define a class in a class library and inject IDatabaseConnectionString into it. Your UserFactory is the right way.
register the UserFactory for DI
serviceCollection.AddScoped<IUserFactory, UserFactory>();
Resolve the UserFactory by the DI. For example, use the UserFactory as the constructor parameter in some controller. Everything is connected by DI automatically.
public MyController(IUserFactory userFactory)
{
_userFactory = myUserFactory;
}
Here is the good explanation for understanding Composition root.

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);
}
}
}

How to modify DbContext base constructor parameter as its being passed?

In this project I am trying to migrate from .NET to .NET Core. Here I have a code that I want to implement in .NET Core.
public partial class CompanyFormsContext : DbContext
{
public CompanyFormsContext()
: base("name=CompanyFormsContext")
{
}
public CompanyFormsContext(string connName)
: base("name=" + connName)
{
}
...
}
In .NET Core, string is not accepted as a parameter to DbContext. Instead, you can pass DbContextOptions as a parameter. For example, in the following link: http://ef.readthedocs.io/en/latest/miscellaneous/configuring-dbcontext.html
You can see the example:
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
}
and
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Filename=./blog.db");
using (var context = new BloggingContext(optionsBuilder.Options))
{
// do stuff
}
what I want to do is similar to this. I could possibly create an instance of DbContextOptions and pass it but I do not know how I would modify the SqlServer connection as I am passing it through the base class constructor.
The most important thing that I cannot figure out is that I want to be able to keep my empty constructor which would trigger a default "CompanyFormsContext" connection. It would also be great if I could simply change the connection name while passing it as a parameter in the CompanyFormsContext constructors.
I was thinking of the following as an alternative way instead of the base constructors but I would prefer to keep the base constructor functionality.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (connName == null)
{
optionsBuilder.UseSqlServer(#"Server=.\;Integrated Security=True;Database=CompanyFormsContext");
}
else
{
optionsBuilder.UseSqlServer(#"Server=.\;Integrated Security=True;Database=" + connName);
}
}
You could create a static method which returns a DbContextOptions<BloggingContext> which will be created from a passed connection string.
So your class could look something like this:
public partial class CompanyFormsContext : DbContext
{
public CompanyFormsContext()
: base(CreateOptions(null))
{
}
public CompanyFormsContext(string connName)
: base(CreateOptions(connName))
{
}
private static DbContextOptions<BloggingContext> CreateOptions(string connName)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Filename=./blog.db");
if (connName == null)
{
optionsBuilder.UseSqlServer(#"Server=.\;Integrated Security=True;Database=CompanyFormsContext");
}
else
{
optionsBuilder.UseSqlServer(#"Server=.\;Integrated Security=True;Database=" + connName);
}
return optionsBuilder.Options;
}

Categories

Resources