Request cannot be converted while using AbstractValidator as a base class - asp.net

My project throws a convert error when I use fluentvalidation class as a request model.
I have a BaseRequest. It is inherited from AbstractValidatator
public abstract class BaseRequest<TModel> : AbstractValidator<TModel>
{
}
Another model is CreateRuleRequest and it is inherited from BaseRequest. And also it includes some rule for its properties.
public class CreateRuleRequest : BaseRequest<CreateRuleRequest>
{
public CreateRuleRequest()
{
this.RuleFor(k => k.Rules).NotEmpty();
}
public List<RuleModel> Rules { get; set; }
}
And I am using an Extension to load all rules that are inherited from BaseRequest. Actually, AbstractValidator extends from IValidator so that I can catch all the classes that includes rules.
public static IServiceCollection AddValidation(this IServiceCollection services)
{
var validators = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s =>
s.GetTypes())
.Where(t => t.GetInterfaces().Contains(typeof(IValidator))).Where(k =>
k.GetInterfaces().Contains(typeof(IQuery)) ||
k.GetInterfaces().Contains(typeof(ICommand)));
foreach (var validator in validators)
{
services.AddValidatorsFromAssemblyContaining(validator);
}
return services;
}
Lastly, I have a controller that has a Create method. This method is using CreateRuleRequest as a parameter.
public async Task<IActionResult> Create([FromBody] CreateRuleRequest command) =>
and the application throws The JSON value could not be converted CreateRuleRequest. I am wondering why? is it mandatory to create another model binder or is there any other way

Related

Error in CreateInstance() while dynamically creating object of concrete type in Factory Pattern

I am actually new to design patterns and trying to implement factory pattern with .NET Core.
I tried to see couple of posts related to factory pattern and trying to implement it, I have added the concrete types in the config and reading it as dictionary in my code -
My Factory Interface -
public interface IEmpFactory
{
public BaseEmployee CreateEmployeeType<EmpType>()
where EmpType : BaseEmployee, new();
}
Implementation -
public class EmpFactoryImpl : IEmpFactory
{
public BaseEmployee CreateEmployeeType<EmpType>()
where EmpType: BaseEmployee, new()
{
return new EmpType();
}
}
Below are my services which are using the Factory as dependency -
public interface IEmpService
{
public string GetEmployeeBonus();
}
public class ContractEmpService : IEmpService
{
IEmpFactory _empFactory;
public ContractEmpService(IEmpFactory empFactory) =>
_empFactory = empFactory;
private BaseEmployee CreateMyEmployee() =>
_empFactory.CreateEmployeeType<ContractEmp>();
public string GetEmployeeBonus() =>
return CreateMyEmployee().GetBonus();
}
public class PermEmpService : IEmpService
{
private readonly IEmpFactory _empFactory;
public PermEmpService(IEmpFactory empFactory) =>
_empFactory = empFactory;
private BaseEmployee CreateMyEmployee() =>
_empFactory.CreateEmployeeType<PermEmp>();
public string GetEmployeeBonus() =>
CreateMyEmployee().GetBonus();
}
Added these concrete types in the config -
"ConfigurationProps": {
"EmpServices": {
"PermEmp": "SimpleFactoryWithoutSwitchCase.Service.PermEmpService",
"ContractEmp": "SimpleFactoryWithoutSwitchCase.Service.ContractEmpService"
}
}
Created the class to create a instance of the concrete type based on the type i.e, PermEmp or ContractEmp dynamically -
public class EmployeeTypeRouter : IEmployeeTypeRouter
{
private readonly ConfigurationProps _props;
public EmployeeTypeRouter(ConfigurationProps props)
{
_props = props;
}
public IEmpService GetInstance(string key)
{
string className = _props.EmpServices
.Where(k => k.Key.Equals(key)).FirstOrDefault().Value;
Type t = Type.GetType(className);
return (IEmpService)Activator.CreateInstance(t);
}
}
This is my calling method -
[HttpGet(Name = "GetEmployeeBonus")]
public string Get()
{
string type = "PermEmp";
IEmpService empService = _empRouter.GetInstance(type);
return empService.GetEmployeeBonus();
}
based on the type passed here i want to fetch the concrete type and call the method.
I am getting the error like this on CreateInstance method -
System.MissingMethodException: `Cannot dynamically create an instance of type 'SimpleFactoryWithoutSwitchCase.Service.PermEmpService'. Reason: No parameterless constructor defined.'
Which is very clear, but I don't want to create a parameterless constructor.
Since I am registering the dependencies in .NET Core, do I need to pass it again here? (which does not make sense for me)
Any help is really appreciated or if you feel I am doing something wrong please let me know.
Your EmployeeTypeRouter class tries to replicate the creation process that your DI Container can do more eloquently. So instead of calling Activator.CreateInstance, forward the resolution to the DI Container.
This means the following things:
Register all known IEmpService at startup.
Resolve the expected type from the IServiceProvider from inside the EmployeeTypeRouter.
In other words, change the startup code to the following:
var dictionary = props.EmpServices
.ToDictionary(p => p.Key, p => Type.GetType(p.Value));
foreach (string pair in dictionary)
{
services.AddTransient(pair.Value);
}
services.AddTransient<IEmployeeTypeRouter, EmployeeTypeRouter>();
services.AddTransient<Func<string, IEmpService>>(sp =>
key => (IEmpService)sp.GetRequiredService(dictionary[key]));
And change EmployeeTypeRouter to the following:
public class EmployeeTypeRouter : IEmployeeTypeRouter
{
private readonly Func<string, IEmpService> _factory;
public EmployeeTypeRouter(Func<string, IEmpService> factory)
{
_factory = factory;
}
public IEmpService GetInstance(string key) =>
_factory.Invoke(key);
}
In the previous code snippet, EmployeeTypeRouter makes use of the Func<string, IEmpService> delegate, which functions as factory. Under the covers the delegate calls back into the IServiceProvider.
There are of course several ways to skin a cat. You could also move some of the startup logic into EmployeeTypeRouter, or even remove the IEmployeeTypeRouter altogether and let application code depend directly on Func<string, IEmpService> delegate.

How to distinguish between multiple databases with the same structure and same context in the URL for an ASP.Net Core Web API

I'm trying to make a web api in asp.net core which can target multiple databases on the same server with the exact same structure. As such they should be able to share the same context and controllers. Making separate contexts and controllers for each database would quickly get out of hand and make it a pain to maintain. As such I should be able to do this in Startup.cs.
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db1")));
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db2")));
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db3")));
The problem I'm running into is how I can distinguish which database is being queried. Ideally I would like to have it such that the url can be ...{database}[controller]... where the database parameter can be used to determine which database is being queried. I've tried looking into the multi-tenant approach however I can't work out how to adapt it to my specific use case.
Any help would be greatly appreciated.
Take a look at this:
https://entityframeworkcore.com/knowledge-base/58123230/connect-multiple-databases-to--net-core-project-via-entity-framework-core
You can do it with multiple DB Contexts from inheriting the principal DB Context where you define the DbSets.
Create base context and including all settings into this, DBSET:
public abstract class BaseContext : DbContext
{
public BaseContext(DbContext options)
: base(options)
{ }
public DbSet<object> FirstDbSet { get; set; }
...
}
inherit from BaseContext for both DBs(Databases):
public class NavaContext : BaseContext
{
public NavaContext (DbContext<NavaContext> options) : base(options)
{
}
}
public class StackContext : BaseContext
{
public StackContext(DbContext<StackContext> options) : base(options)
{
}
}
and register both in Startup.cs:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<NavaContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
services.AddDbContext<StackContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));
// Autofac
var builder = new ContainerBuilder();
// needed only if you plan to inject ICollection<BaseContext>
builder.RegisterType<NavaContext>().As<BaseContext>();
builder.RegisterType<StackContext>().As<BaseContext>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
add connection strings in appsettings.json:
"ConnectionStrings": {
"NavaConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
"StackConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
and now you can inject both contexts:
public class ReportRepository : IReportRepository
{
private readonly NavaContext latamDbContext;
private readonly StackContext euDbContext;
public ReportRepository(NavaContext latamDbContext, StackContext euDbContext)
{
this.latamDbContext = latamDbContext;
this.euDbContext = euDbContext;
}
}
or if you plan to inject collection of contexts:
public class ReportRepository : IReportRepository
{
private readonly ICollection<BaseContext> dbContexts;
public ReportRepository(ICollection<BaseContext> dbContexts)
{
this.dbContexts = dbContexts;
}
}
to access specific context:
var _stackContext= dbContexts.FirstOrDefault(x => x is StackContext) as StackContext;
var _navaContext= dbContexts.FirstOrDefault(x => x is NavaContext) as NavaContext;
The best way to create connection when there are multiple databases in dot net core is with IDesignTimeDbContextFactory
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
// logic to determine which connection string to use
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("connectionString");
return new BloggingContext(optionsBuilder.Options);
}
}
Inject BloggingContextFactory using register services and pass args[] for logic to use connection string

Same Policy but different required parameter for each action method

In a .Net core Webapi 2.1 project, I have a tons of action methods.
All action methods should be authorized against the same policy (named FooPolicy) but with a different required argument.
Based on Microsoft's docs: Policy-based-Authorization
One way would be to declare a tons of policies based on different input argument:
services.AddAuthorization(options =>
{
options.AddPolicy("FooPolicy1", policy =>policy.Requirements.Add(new FooRequirement(1)));
options.AddPolicy("FooPolicy2", policy =>policy.Requirements.Add(new FooRequirement(2)));
options.AddPolicy("FooPolicy3", policy =>policy.Requirements.Add(new FooRequirement(3)));
//... May be 30 more same policies here ...
});
As i earlier mentioned, only different part is in new FooRequirement(diffArgs). The other challenge for this solution would be to add each FooPolicy on it's corresponding action method and you may miss a couple of theme:
[Authorize(Policy = "FooPolicy1")]
public IActionResult ActionMethodFoo1(...) {...}
[Authorize(Policy = "FooPolicy2")]
public IActionResult ActionMethodFoo2(...) {...}
[Authorize(Policy = "FooPolicy3")]
public IActionResult ActionMethodFoo3(...) {...}
...List still goes on...
Is there any solution like: declare a policy once but use it with different instance of FooRequirement (which is of type IAuthorizationHandler)? like so:
services.AddAuthorization(options =>
{
options.AddPolicy("FooPolicy", policy =>policy.Requirements.Add(?));
});
And on the action methods:
[Authorize(Policy = "FooPolicy", required = new FooRequirement(1))]
public IActionResult ActionMethodFoo1(...) {...}
[Authorize(Policy = "FooPolicy", required = new FooRequirement(2))]
public IActionResult ActionMethodFoo2(...) {...}
[Authorize(Policy = "FooPolicy", required = new FooRequirement(3))]
public IActionResult ActionMethodFoo3(...) {...}
The main idea is to declare policy once. Two recent code blocks are psudo-code, Does any body knows practical solution with similar concept?
You could implement your own IAuthorizationFilter
custom IAuthorizationFilter
public class CustomAuthorize : IAuthorizationFilter
{
private readonly int _input;
public CustomAuthorize(int input)
{
_input = input;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//custom validation rule
if (_input == 1)
{
context.Result = new ForbidResult();
}
}
}
Custom CustomAuthorizeAttribute
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
public CustomAuthorizeAttribute(int input) : base(typeof(CustomAuthorize))
{
Arguments = new object[] { input };
}
}
Use
[CustomAuthorizeAttribute(1)]
public IActionResult About()

Validating enums with FluentValidation

I'm using FluentValidation.WebApi 6.2.1.0 in Web API project. Is there a way to validate enum with FluentValidation and return custom message?
my controller action is as following,
public IHttpActionResult Get([FromUri]CheckUpdateVM info)
{
...
}
My Model,
[Validator(typeof(CheckUpdateVMValidator))]
public class CheckUpdateVM
{
public DeviceTypes Device { get; set; }
}
I'm looing for something like this,
public class CheckUpdateVMValidator : AbstractValidator<CheckUpdateVM>
{
public CheckUpdateVMValidator()
{
RuleFor(x => x.Device).Must(x => Enum.IsDefined(typeof(DeviceTypes), x)).WithMessage("xxx");
}
}
With above code, Model binder validate the value of "Device" parameter and response with an error. but I can't customize the error message. (If I set the "Device" property type to string, this works fine.)
Creating custom validator could be better approach in this scenario.
public class DeviceEnumValidator<T> : PropertyValidator {
public DeviceEnumValidator()
: base("Invalid Enum value!") { }
protected override bool IsValid(PropertyValidatorContext context) {
DeviceTypes enumVal= (DeviceTypes) Enum.Parse(typeof(DeviceTypes), context.PropertyValue);
if (!Enum.IsDefined(typeof(DeviceTypes), enumVal)
return false;
return true;
}
}
To use DeviceEnumValidator you can call SetValidator when defining a validation rule.
public CheckUpdateVMValidator()
{
RuleFor(x => x.Device).SetValidator(new DeviceEnumValidator<DeviceTypes>());
}

Is there a way to get the current controller instance in ASP.NET 5?

Is there a way to do this using DI? I tried IScopedInstance<Controller> but this gives me null. Poked around aspnet's source code but didn't win. Any ideas?
I have a controller that accepts different IPaymentMethods. The IPaymentMethod can be a ViewComponent that can render Views. If the IPaymentMethod is a ViewComponent, I want it to use MVC's built-in model binding on post back.
public class XController : Controller
{
// ctor, props, ...
public IActionResult Checkout()
{
return View(new Model
{
PaymentMethodId = 1,
PaymentMethodType = typeof(MyPaymentMethod) // The razor file will use this type to render it as a ViewComponent
});
}
[HttpPost]
public IActionResult Checkout(Model model)
{
var paymentMethod = _paymentService.GetPaymentMethodById(model.PaymentMethodId);
paymentMethod.ProcessPayment();
// ..
}
}
This is where I need the controller to be injected. I wanted to make use of the built-in MVC validation and model binding.
public class MyPaymentMethod : IPaymentMethod
{
private Controller _currentController;
public MyPaymentMethod(IScopedInstance<Controller> controller)
{
_currentController = controller.Value;
}
public void ProcessPayment()
{
var model = new PaymentModel();
_currentController.TryUpdateModel(model, typeof(PaymentModel), null);
if (!_currentController.ModelState.IsValid)
{
return; // or exception
}
// Process Payment using model
}
public Task<IViewComponentResult> InvokeAsync()
{
// returns View
}
}
public interface IPaymentMethod
{
void ProcessPayment();
}
Since the model instance is required in the ProcessPayment method, why not simply pass it as a parameter?
[HttpPost]
public IActionResult Checkout(PaymentModel model)
{
var paymentMethod = _paymentService.GetPaymentMethodById(model.PaymentMethodId);
if (!ModelState.IsValid)
{
return; // or exception
}
paymentMethod.ProcessPayment(model);
// ..
}
public void ProcessPayment(PaymentModel model)
{
// Process Payment using model
}
Your service is taking on responsibilities that belong to the controller - namely checking ModelState.IsValid.
public interface IPaymentMethod
{
void ProcessPayment(PaymentModel model);
}
You may wish to also pass just the properties that are needed from the payment model, or you may wish to make an IPaymentModel interface to decouple your model from your PaymentService. In that case, your IPaymentModel would go into a shared layer.
public interface IPaymentMethod
{
void ProcessPayment(IPaymentModel model);
}
This no longer works with beta7
At this time of writing (beta6), this probably isn't supported and there is a good reason for it: Controllers in ASP.NET 5 does not need to inherit from the Controller class. I have, however, found a way for this to work using ActionFilters.
public class ScopeControllerActionFilterAttribute : ActionFilterAttribute
{
private readonly IScopedInstance<Controller> _controller;
public ScopeControllerActionFilterAttribute(IScopedInstance<Controller> controller)
{
_controller = controller;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (_controller.Value == null)
{
_controller.Value = context.Controller as Controller;
}
}
}
Note that depending on the stage of the http request lifecycle, the Value of IScopedInstance<Controller> may still be empty.

Resources