fluentvalidation for partial class - model-view-controller

I have a customer class like this:
[Validator(typeof(CustomerValidator))]
public partial class Customer {
public string FirstName { get; set; }
public string LastName { get; set; }
}
And my Validation class is:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(x => x.FirstName)
.NotEmpty()
.WithMessage("FirstName is required."));
RuleFor(x => x.LastName)
.NotEmpty()
.WithMessage("LastName is required."));
}
}
Everything works fine, the code did validate fields.
I planned to extend the Customer class and add Email field. I cannot edit my old code file. I create new partial Customer class and new validation for Email field.
I can create partial customer class like this:
public partial class Customer {
public string Email { get; set; }
}
But I don't know how to validate this field via another class. The code below is what i expected but it I dont know how to bind it in the Customer Email field:
public class CustomerEmailValidator : AbstractValidator<Customer>
{
public CustomerEmailValidator()
{
RuleFor(x => x.Email)
.EmailAddress()
.WithMessage("Email address is not valid."));
}
}
All helps are appreciated.
Thanks in advance.

Put [Validator(typeof(CustomerValidator))] annotation on the partial class as well.

Related

StrawberryShake GraphQl Dto constructor can't be empty

I'm having some problem with one of my data in strawberry shake. It's a simple query but when I try to create an object of it, the generated code dtoData ask for a type in the constructor.
All my other query don't required anything in the constructor.
I use the Dto for model in the ViewModel for mapping.
Example of a working one.
public clas ProjectModelVM : ViewModelBase
{
//The ProjectDtoInput class is created by the Generation code.
// If I create a new Instance of ProjectDtoInput the constructor is empty and it's working
// var project = new ProjectDtoInput()
public ProjectDtoInput _projectModel;
public ProjectModelVM(ProjectDtoInput projectModel)
{
_projectModel = projectModel;
}
}
the query is
query GetActiveProject{
activeProject{
cL_PROJET_NO,
cL_PROJET_NOM
}
}
And the Dto in the server side is
public class QmProdFormDto
{
public int? FormID { get; set; }
public string? FormName { get; set; }
public string? ProjectNo { get; set; }
public string? ProjectName { get; set; }
public string? DivName { get; set; }
public string? SubDivName { get; set; }
}
Example of a NON working one
public class PaintBrandModelVM : ViewModelBase
{
// The QmProdPaintDtoData class is created by the Generation code.
// If I create a new Instance of QmProdPaintDtoData the constructor ask me for some __type input
public QmProdPaintDtoData _paintBrandModel;
public PaintBrandModelVM(QmProdPaintDtoData paintBrandModel)
{
_paintBrandModel = paintBrandModel;
}
}
the query is
query GetPaintLst{
paintLst{
paintBrandID,
paintBrandName
}
}
And the Dto on the server side is
public class QmProdPaintDto
{
public int? PaintBrandID { get; set; }
public string? PaintBrandName { get; set; }
}
I don't understand why one of the DTO ask me for mendatory input.
Can someone give me a hand on this.
Tell me if you need more of the code.
Thanks.
Jc

How to create a custom filter at .net core

I try one of the following without any success.
1. Validate a property's (username) value in the model binding with another property's value in the model (id, to find the user).
2. Validate all the sent model to a put request in the controller.
How can i create a custom filter to catch all the model to one of the property's value by use another value in the sent model?
You can use Fluent Validator in .NET Core for such validations
Step 1 :- Register it in the startup
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddFluentValidation(fvc =>
fvc.RegisterValidatorsFromAssemblyContaining<Startup>());
}
Step 2 :-
Define the validation rules like this
public class RegistrationViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class RegistrationViewModelValidator : AbstractValidator<RegistrationViewModel>
{
readonly IUserRepository _userRepo;
public RegistrationViewModelValidator(IUserRepository userReo)
{
RuleFor(reg => reg.FirstName).NotEmpty();
RuleFor(reg => reg.LastName).NotEmpty();
RuleFor(reg => reg.Email).NotEmpty();
RuleFor(reg => reg.FirstName).Must(DoesnotExist);
}
bool DoesnotExist(string userName)
{
return _userRepo.FindByUserName(userName) != null;
}
}
Step 3:-
IN the controllers
[HttpPost]
public IActionResult FormValidation(RegistrationViewModel model)
{
if (this.ModelState.IsValid) {
ViewBag.SuccessMessage = "Great!";
}
return View();
}
Refer this link for the complete documentation

Validating complex class in MVC

Consider the following code:
public class AccountNumber
{
[AccountNumber] //This validator confirms the format of the account number
public string Value {get; set;}
public int Format { get; set;}
public string ToString()
{
return Value + " is format " + Format;
}
}
public class MyViewModel
{
public MyViewModel()
{
SourceAccount = new AccountNumber();
DestinationAccount= new AccountNumber();
}
[Required]
AccountNumber SourceAccount {get; set;}
AccountNumber DestinationAccount {get; set;}
}
And then, in my View:
#Html.EditorFor(model => model.SourceAccount.Value)
#Html.EditorFor(model => model.DestinationAccount.Value)
Basically, I want to say that the user must enter a Source Account, and that they optionally enter a Destination Account. However, if they do enter a Destination Account it must conform to a certain format.
The problem with the code above is that the required validator on the SourceAccount will always return valid, as SourceAccount is never null. What would be a good approach for implementing what I am trying to achieve?
Please note that in real-life the setter for Value is more complex than shown, as it reformats the account number in a canonical format.
Edit Please note that we have to use inbuilt MVC validation, as that is what the rest of the project is currently using.
See Extending the Model Binder for Enhanced Validation.
This is fully compatible with built-in MVC validation.
You can - of course - customize this solution by using your own interface for validation.
A simple approach could be to add simple string properties for the SourceAccount and DestinationAccount numbers as follows:
public class MyViewModel
{
public MyViewModel()
{
}
[Required]
[AccountNumber]
public string SourceAccountNumber { get; set; }
[AccountNumber]
public string DestinationAccountNumber { get; set; }
public AccountNumber SourceAccount
{
get
{
return new AccountNumber
{
Value = SourceAccountNumber,
Format = 0 // Set Format appropriately
};
}
}
public AccountNumber DestinationAccount
{
get
{
return new AccountNumber
{
Value = DestinationAccountNumber,
Format = 0 // Set Format appropriately
};
}
}
}
Maybe you'd like to try FluentValidation, it's a model validation alternative to data annotation attributes, which allows you to add more complex model validation logic.
The code is still pretty concise and straightforward:
[Validator(typeof(PersonValidator))]
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
public class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Id).NotNull();
RuleFor(x => x.Name).Length(0, 10);
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).InclusiveBetween(18, 60);
}
}

Code first DbContext with current user filter

I'm building an ASP.NET MVC3 website with an code first database and have the following question:
Is it possible to make an instance of MyDbContext class with an additional argument set which will be used for filtering the results of calls to mydbcontext.
I want to use this for restricting the resultset to the current user that is logged in on my asp.net mvc website.
Any directions would be great!
I don't see why that should be a problem. Something like this should work:
public class Northwind : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class FilteredNorthwind : Northwind
{
public IQueryable<Products> GetFilteredProducts(string userRole)
{
return Products.Where(product => product.UserRole == userRole);
}
}
Update
To make it impossible for your MyDbContext to be abused, you could put all your database code and models into a separate project/assembly. Then make your DbContext an internal class (instead of public), then create a public class (FilteredDbContext) that wraps your MyDbContext and exposes methods that allow you to only grab the data your allowed to see. Then in your main assembly (your web project), you will only be able to use FilteredDbContext.
So, for example:
internal class Northwind : DbContext // note: internal class
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class FilteredNorthwind // note: does not inherit from `Northwind`
{
private readonly _dbContext = new Northwind();
public IQueryable<Products> GetProducts(string userRole)
{
return _dbContext.Products.Where(product => product.UserRole == userRole);
}
}
If Northwind and FilteredNorthwind are in a separate assembly from your web app, you can instantiate only FilteredNorthwind from your web app.
Update 2
If you use a ViewModel, then your web app can't get back to the list of all products for a category because you extract out only the properties you need (and only the properties the user is allowed to see).
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public IEnumerable<Products> GetProducts(string userRole)
{
return _dbContext.Products
.Where(product => product.UserRole == userRole)
.Select(product => new ProductViewModel
{
Id = product.Id,
Name = product.Name,
Price = product.Price
};
}
You could make a layer above and hide the generated one and create a your own DbContext which derives from the generated MyDbContext. Just a wild guess but it seems logical to me and so you can implement your own argument set and still use the generated one.
I would do this:
public interface IUserContext {
string User { get; set; }
}
public class Database : DbContext {
public IDbSet<Product> Products { get; set; }
}
public class AuthorizedDatabase {
private readonly Database _database;
private readonly IUserContext _userContext;
public AuthorizedDatabase(Database database, IUserContext userContext) {
_database = database;
_userContext = userContext;
}
private bool Authorize<TEntity>(TEntity entity) {
// Some code here to look at the entity and the _userContext and decide if it should be accessible.
}
public IQueryable<Product> Products {
get {
return _database.Products.Where(Authorize);
}
}
}
This would allow me to cleanly abstract the actual logic around the authorization (and your IUserContext interface can be as simple or complex as required to suite your exact needs.)
To ensure that the user is unable is circumvert this protection using a navigation property (Product.Category.Products, for example.) you might need to turn off lazy loading and explicitly load the required related entities.
Have a look at this post from ADO.NET Team Blog for ideas: loading related entities

Convert a string value to an entity in Automapper

I am trying to figure out how to use Automapper when my entity has a field of type entity.
I've got 3 classes like these:
public abstract class Entity<IdK>
{
public virtual IdK Code { get; protected set; }
}
public class Contact : Entity
{
public virtual string Name { get; set; }
public virtual Company Company { get; set; }
}
public class Company : Entity
{
public virtual string Name { get; set; }
}
My class Contact contain an element of type Company.
I've also created a ViewModel to trasfer some infos to my view:
public ContactViewModel()
{
public Guid Code { get; set; }
public int Version { get; set; }
[DisplayName("Contact")]
public string Name { get; set; }
[DisplayName("Company")]
public string Company { get; set; }
}
In my viewmodel I've defined a field Company of type string. This is going to contain a value the user will chose from a dropdown (list of companies).
I've defined a bootstrapper when my App starts:
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x => {
x.CreateMap<Domain.Contact, ViewModels.ContactViewModel>();
x.CreateMap<ViewModels.ContactViewModel, Domain.Contact>()
});
}
}
When I try to remap my ViewModel to my entity I get a conversion error (AutoMapper.AutoMapperMappingException).
Automapper can't figure out how to convert my Company (string) into an object of type Company, member of Contact.
Is it possible to define a rule so that Automapper know how to transform the string (company) into the code of my Company object, member of Contact?
You need to use a Resolver. Something like:
public class CompanyTypeResolver : ValueResolver<string, Company>
{
protected override Company ResolveCore(string name)
{
return new Company {Name = name};
}
}
Then in mapping code you call it like:
.ForMember(dto => dto.Company, opt => opt.ResolveUsing<CompanyTypeResolver>().FromMember(src => src.Name))

Resources