FluentValidation not using my Rules - c#

I'm using FluentValidation with Autofac and ValidatorFactoryBase
When I execute my project my Validator is executed, but when I send a post my rules not is used but the current validator is my own Validator.
My Validator:
public class UsuarioCadastrarValidator : AbstractValidator<UsuarioCadastrarVM>
{
public UsuarioCadastrarValidator()
{
RuleFor(a => a.Nome).NotEmpty().WithMessage("Campo obrigatório");
RuleFor(a => a.Nome).Length(4, 200).WithMessage("Digite seu nome completo");
}
}
My Model:
public class UsuarioCadastrarVM
{
public string Nome { get; set; }
public int CargoId { get; set; }
}
Global.asax(Works well):
...
FluentValidationModelValidatorProvider.Configure();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Validator"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(assembly);
builder
.RegisterType<FluentValidation.Mvc.FluentValidationModelValidatorProvider>()
.As<ModelValidatorProvider>();
builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
...
Controller(Works well):
[HttpPost]
public ActionResult Cadastrar(UsuarioCadastrarVM vm)
{
if(ModelState.IsValid)
{
}
}
My ValidatorFactoryBase (Works well):
public class AutofacValidatorFactory : ValidatorFactoryBase
{
private readonly IComponentContext _context;
public AutofacValidatorFactory(IComponentContext context)
{
_context = context;
}
public override IValidator CreateInstance(Type validatorType)
{
object instance;
if (_context.TryResolve(validatorType, out instance))
{
var validator = instance as IValidator;
return validator;
}
return null;
}
}
When I send Post with "Nome" and "CargoId" empty in ModelState has only one message "CargoId is required" and not exists that Rule, I think is because CargoId is a integer.
But, Why my Rules are not consider?

The problem was CargoId is a integer, so the MVC is not able to bind my post to my ViewModel, because in my tests I sended a empty value, if I send a value to CargoId or change to nullable (int?) the validation works well.

Related

Unable to cast object of type AsyncStateMachineBox System.Threading.Tasks.VoidTaskResult to type System.Threading.Tasks.Task

I'm very new to ASP.NET Web API and I'm trying to use Entity Framework Core's Dependency Injection to POST data to the API Controller using MediatR pattern. But every time I run my code and it opens Swagger UI, I get an error 500 response saying
Unable to cast object of type 'AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,S3E1.Repository.CartItemRepository+<Createitem>d__5]' to type 'System.Threading.Tasks.Task1[S3E1.Entities.CartItemEntity]'.
First, I added Dependency Injections to Program.cs
//Dependency Injection
builder.Services.AddDbContext<AppDataContext>(contextOptions => contextOptions.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
//Connection
builder.Services.AddSingleton<DataConnectionContext>();
These are the classes.
AppDataContext.cs
public class AppDataContext : DbContext
{
public AppDataContext(DbContextOptions<AppDataContext> contextOptions) : base(contextOptions) { }
public DbSet<CartItemEntity> CartItems { get; set; }
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<UserEntity> Users{ get; set; }
}
DataConnectionContext.cs
public class DataConnectionContext
{
private readonly IConfiguration _configuration;
private readonly string _connectionString;
public DataConnectionContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = _configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
}
Next is making a repository which holds the interface that has the create method.
public interface ICartItemRepository
{
//public Task<IEnumerable<CartItemEntity>> GetCartItems();
//public Task<CartItemEntity> GetCartItemEntity(Guid id);
public Task Createitem(CartItemEntity itemEntity);
}
Then a class that inherits the interface and calls the dependency constructors
public class CartItemRepository : ICartItemRepository
{
private readonly DataConnectionContext _connectionContext;
private readonly AppDataContext _appDataContext;
public CartItemRepository(DataConnectionContext connectionContext, AppDataContext appDataContext)
{
_connectionContext = connectionContext;
_appDataContext = appDataContext;
}
public async Task Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
await _appDataContext.CartItems.ToListAsync();
}
}
Next is a command for POST request MediatR pattern
public record AddCartItemCommand(CartItemEntity cartItem) : IRequest<CartItemEntity>;
and a Handler which manages and returns the method createitem
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
private readonly ICartItemRepository _cartItemRepository;
public AddItemsHandler(ICartItemRepository cartItemRepository) => _cartItemRepository = cartItemRepository;
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await (Task<CartItemEntity>) _cartItemRepository.Createitem(request.cartItem);
}
}
and lastly, in the controller
[Route("api/cart-items")]
[ApiController]
public class CartItemsController : ControllerBase
{
private ISender _sender;
public CartItemsController(ISender sender) => _sender = sender;
[HttpPost]
public async Task<CartItemEntity> Post(CartItemEntity cartItemEntity)
{
return await _sender.Send(new AddCartItemCommand(cartItemEntity));
}
}
I tried modifying the return object in the handler but every time I change anything it always get the error squiggly line, so I just casted the (Task) after the await. Is this where I went wrong? Thank you for any answers.
The exception is clear. You can't cast a VoidTaskResult to Task<CartItemEntity>.
To solve the problem:
In ICartItemRepository, modify the return type for Createitem as Task<CartItemEntity>.
In CartItemRepository, implement Createitem method from the ICartItemRepository interface. Return the inserted itemEntity in the method.
Since you have implemented Task<CartItemEntity> Createitem(CartItemEntity itemEntity) in the ICartItemRepository interface, the casting to (Task<CartItemEntity>) is no longer needed, and suggested to be removed.
public interface ICartItemRepository
{
...
public Task<CartItemEntity> Createitem(CartItemEntity itemEntity);
}
public class CartItemRepository : ICartItemRepository
{
...
public async Task<CartItemEntity> Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
return itemEntity;
}
}
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
...
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await _cartItemRepository.Createitem(request.cartItem);
}
}

Autofac not resolving interfaces in other project

I'm trying to write a generic command bus (Part of class library) that uses different commands and handlers in each of my services.
The following code produces the following exception:
System.Exception: Command does not have any handler RegisterUserCommand
I was under the impression passing the the ExecutingAssemblies of my UserService would allow the Container to resolve the handler in my UserService but apparently not.
Am I doing something wrong?
CommandBus:
public interface ICommandBus
{
void Send<T>(T Command) where T : ICommand;
}
public class CommandBus : ICommandBus
{
private IContainer Container { get; set; }
public CommandBus(Assembly assembly)
{
Container = new CommandBusContainerConfig().Configure(assembly);
}
public void Send<TCommand>(TCommand command) where TCommand : ICommand
{
var handlers = Container.Resolve<IEnumerable<ICommandHandler<TCommand>>>().ToList();
if (handlers.Count == 1)
{
handlers[0].Handle(command);
}
else if (handlers.Count == 0)
{
throw new System.Exception($"Command does not have any handler {command.GetType().Name}");
}
else
{
throw new System.Exception($"Too many registred handlers - {handlers.Count} for command {command.GetType().Name}");
}
}
}
ContainerBuilder:
public class CommandBusContainerConfig : IContainerConfig
{
public IContainer Configure(Assembly executingAssembly)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
return builder.Build();
}
}
In my UserService(ASP.Net Core 3), which is a different project that references the above CommandBus:
public class RegisterUserCommand : ICommand
{
public readonly string Name;
public readonly Address Address;
public string MobileNumber;
public string EmailAddress;
public RegisterUserCommand(Guid messageId, string name, string mobileNumber, string emailAddress, Address address)
{
Name = name;
Address = address;
MobileNumber = mobileNumber;
EmailAddress = emailAddress;
}
CommandHandler:
public class RegisterUserComnmandHandler : ICommandHandler<RegisterUserCommand>
{
public void Handle(RegisterUserCommand command)
{
Console.WriteLine($"Create user {command.Name} {command.MobileNumber} - handler");
}
}
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ICommandBus>(new CommandBus(Assembly.GetExecutingAssembly()));
}
Controller:
private readonly ICommandBus _commandBus;
public UsersController(ICommandBus commandBus) {
_commandBus = commandBus;
}
// POST api/values
[HttpPost]
public async Task<IActionResult> Post([FromBody]RegisterUserCommand command)
{
if (ModelState.IsValid)
{
CommandBus commandBus = new CommandBus(Assembly.GetExecutingAssembly());
commandBus.Send(command);
_commandBus.Send(Command); //Same result as above
// return result
return Ok(command);
}
return BadRequest();
}
Thanks,
The main error is here :
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsAssignableTo<ICommandHandler>())
.AsImplementedInterfaces();
RegisterUserComnmandHandler is not a ICommandHandler but a ICommandHandler<RegisterUserCommand>. Instead of IsAssignableTo<> method you can use the IsClosedTypeOf which is an Autofac extension which do exactly what you can.
builder.RegisterAssemblyTypes(executingAssembly)
.Where(x => x.IsClosedTypeOf(typeof(ICommandHandler<>)))
.AsImplementedInterfaces();
By the way, in your code sample you are using another Container. Most of the time it is always simple to have a single container for the whole application. To get things organised you can use autofac module. You are also resolving straight from the container and not using scope this means that your instance graph won't be disposed at the end of the operation but will stay for the whole lifetime of the container.
In your controller, I saw that you are building a new CommandBus for each request, which will create a new container. Building a new container is a heavy operation and you should avoid doing it often but only once of the startup of the application.
Also I don't get the point of this registration :
builder.Register<Func<Type, ICommandHandler>>(c =>
{
var ctx = c.Resolve<IComponentContext>();
return t =>
{
var handlerType = typeof(ICommandHandler<>).MakeGenericType(t);
return (ICommandHandler)ctx.Resolve(handlerType);
};
});
It doesn't looks you need it and it seems useless to me
This took me a while to figure out. But my CommandHandler interface was incorrectly defined. It should look like:
public interface ICommandHandler { }
public interface ICommandHandler<T> : ICommandHandler where T : ICommand
{
void Handle(T command);
}
}
When trying to resolve the CommandHandler in the Autofac configuration class, the .Where(x => x.IsAssignableTo<ICommandHandler>()) was failing because the class was assignable to ICommandHandle<T> not ICommandHandler

.net core 3.0 Constructor parameter problem

There is no argument given that corresponds to the required formal parameter 'userRoleService' of 'AuthorizeUserAttribute.AuthorizeUserAttribute(string, IUserRoleService, IModuleService, IUserService)'
AuthorizationController.cs
[AuthorizeUserAttribute("User.Edit")]
public ActionResult UserAuthorizationEdit()
AuthorizeUserAttribute.cs
public string Action { get; set; }
private IUserRoleService _userRoleService;
private IModuleService _moduleService;
private IUserService _userService;
public AuthorizeUserAttribute(IUserRoleService userRoleService, IModuleService moduleService, IUserService userService)
{
_userRoleService = userRoleService;
_moduleService = moduleService;
_userService = userService;
}
When I try to add constructor,controller side says write constructor as a parameter. How Can i change interface to a constructor
You need to use
[TypeFileter(typeof(AuthorizeUser),Arguments = new object[] { "User.Edit" }))]
public ActionResult UserAuthorizationEdit(int userId,
RoleRegisterDto authorizationModel)
in order to dependency injection can inject your services.
If you want to uses interfaces via class constructor using DI,you need to pass the parameter with the same type from custom attribute on controller side.
To avoid doing that, you could register your interfaces as services and get them using below code without constructor injection.For example:
1.Interface
public interface IUserRoleService
{
List<string> GetValues();
}
public class UserRoleService : IUserRoleService
{
private List<string> _privateList = new List<string>();
public List<string> GetValues()
{
_privateList.Add("test");
return _privateList;
}
}
2.In startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IUserRoleService, UserRoleService>();
}
3.Custom Authorization Attribute
public class AuthorizeUserAttribute:AuthorizeAttribute, IAsyncAuthorizationFilter
{
public string Action { get; set; }
public AuthorizeUserAttribute(string action)
{
Action = action;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
{
var x = authorizationFilterContext.HttpContext.RequestServices.GetRequiredService<IUserRoleService>();
var y = x.GetValues();
}
}
4.Action
[AuthorizeUserAttribute("User.Edit")]
public ActionResult UserAuthorizationEdit()

ASP.NET Core API, Mediatr send method raises exception unable to resolve service for type

I have a ASP.NET Core API, where I am trying to use FluentValidation with Mediatr.
Currently when the controller method is attempting to call Send on the mediatr instance it generates:
Exception thrown: 'System.InvalidOperationException' in
Microsoft.Extensions.DependencyInjection.dll: 'Unable to resolve
service for type 'GetApplicationQuery' while attempting to activate
'GetApplicationQueryValidator'.'
The query, validator and response class look like this:
public class GetApplicationQuery : IRequest<Response>
{
private string _name;
public GetApplicationQuery(string name)
{
_name = name;
}
public string Name { get { return _name; } }
}
public class GetApplicationQueryHandler : IRequestHandler<GetApplicationQuery, Response>
{
public GetApplicationQueryHandler() { }
public async Task<Response> Handle(GetApplicationQuery request, CancellationToken cancellationToken)
{
return new Response("yadda yadda");
}
}
public class GetApplicationQueryValidator : AbstractValidator<GetApplicationQuery>
{
public GetApplicationQueryValidator(GetApplicationQuery request)
{
RuleFor(m => m.Name).MinimumLength(30).WithMessage("Name must be greater than 30 characters, long");
}
}
public class Response
{
private readonly IList<string> _messages = new List<string>();
public IEnumerable<string> Errors { get; }
public object Result { get; }
public Response() => Errors = new ReadOnlyCollection<string>(_messages);
public Response(object result) : this() => Result = result;
public Response AddError(string message)
{
_messages.Add(message);
return this;
}
}
The configuration I have in the Startup class looks like this:
public void ConfigureServices(IServiceCollection services)
{
AddMediatr(services);
services.AddMvc().AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
private static void AddMediatr(IServiceCollection services)
{
const string applicationAssemblyName = "ApplicationApi";
var assembly = AppDomain.CurrentDomain.Load(applicationAssemblyName);
AssemblyScanner
.FindValidatorsInAssembly(assembly)
.ForEach(result => services.AddScoped(result.InterfaceType, result.ValidatorType));
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidatorHandler<,>));
services.AddMediatR(assembly);
}
I am guessing I have the configuration wrong but I have been changing configuration several times with no success.
Any guidance would be much appreciated
GetApplicationQueryValidator is taking GetApplicationQuery as a constructor dependency but the collection doesn't know about it to be able to inject it.
Also not seeing how it is to be used in that validator. I would suggest removing GetApplicationQuery from the constructor since it doesn't look like it is needed.
public class GetApplicationQueryValidator : AbstractValidator<GetApplicationQuery> {
public GetApplicationQueryValidator() {
RuleFor(m => m.Name).MinimumLength(30).WithMessage("Name must be greater than 30 characters, long");
}
}

Autofac property injection with MVC ValidationAttribute

I have found several questions on this subject, but have not found a clean and simple solution.
This is what I'm doing (using Autofac 3.3.0) for registering
builder.RegisterType<MerchantRepo>().As<IMerchantRepo>().PropertiesAutowired();
This is my validation class
public class MerchantMustBeUniqueAttribute : ValidationAttribute
{
public IMerchantRepo MerchantRepo { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
int merchantId = Convert.ToInt32(value);
if (MerchantRepo.Exists(merchantId))
{
return new ValidationResult(ErrorMessage);
}
else
{
return ValidationResult.Success;
}
}
}
My merchant repo is always null.
Edit:
This is part of my view model
public class MerchantCreationModel
{
[Required]
[MerchantMustBeUnique(ErrorMessage = "Already exists!")]
public int? NewMerchantId { get; set; }
}
Autofac registration
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
builder.RegisterFilterProvider(); // Inject properties into filter attributes
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<MerchantRepo>().As<IMerchantRepo>().PropertiesAutowired();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I solved my problem using the DependencyResolver class in ASP.NET MVC.
IMerchantRepo repo = DependencyResolver.Current.GetService<IMerchantRepo>();
I solved it in a way that doesn't end up littering the code with with Serice Location in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));

Categories