I'm using the Fluent Validation framework in my ASP.net MVC 3 project. So far all of my validations have been very simple (make sure string is not empty, only a certain length, etc.) but now I need to verify that something exists in the database or not.
Should Fluent Validation be used in this case?
If the database validation should be done using Fluent Validation, then how do I handle dependencies? The validator classes are created automatically, and I would need to somehow pass it one of my repository instances in order to query my database.
An example of what I'm trying to validate might:
I have a dropdown list on my page with a list of selected items. I want to validate that the item they selected actually exists in the database before trying to save a new record.
Edit
Here is a code example of a regular validation in Fluent Validation framework:
[Validator(typeof(CreateProductViewModelValidator))]
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : AbstractValidator<CreateProductViewModel>
{
public CreateProductViewModelValidator()
{
RuleFor(m => m.Name).NotEmpty();
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
As you can see, I never create the Validator myself. This works because of the following line in Global.asax:
FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure();
The problem is that now I have a validator that needs to interact with my database using a repository, but since I'm not creating the validators I don't know how I would get that dependency passed in, other than hardcoding the concrete type.
Can't you just create your own validation method where in you would kick-off the database validation?
RuleFor(m => m.name)
.Must(BeInDatabase)
private static bool BeInDatabase(string name)
{
// Do database validation and return false if not valid
return false;
}
I'm using FluentValidation for DataBase validations. just pass the Validation class the session in the Ctor. and do the validation inside the action something like:
var validationResult = new ProdcutValidator(session).Validate(product);
Update: Based on your example I add my example...
public class CreateProductViewModel
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator(ISession session)
{
_session = session;
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
Controller:
public ActionResult Create(CreateProductViewModel model)
{
var validator = new CreateProductViewModelValidator();
var validationResult =validator.Validate(model);
if(!validationResult.IsValid)
{
// You will have to add the errors by hand to the ModelState's errors so the
// user will be able to know why the post didn't succeeded(It's better writing
// a global function(in your "base controller" That Derived From Controller)
// that migrate the validation result to the
// ModelState so you could use the ModelState Only.
return View(model);
}
var product = new Product { Name = model.Name, Price = model.Price };
repository.AddProduct(product);
return RedirectToAction("Index");
}
Second update:
If you insist using parameterless constructor you will have to use some Inversion Of control container, a static class that is something like the Factory of your objects.
use it like this:
public class CreateProductViewModelValidator : abstractValidator<CreateProductViewModel>
{
private readonly ISession _session;
public CreateProductViewModelValidator()
{
_session = IoC.Container.Reslove<ISession>();
RuleFor(m => m.Name).NotEmpty();
RuleFor(m => m.Code).Must(m, Code => _session<Product>.Get(Code) == null);
}
}
You can find many IoC containers, most famous are Windsor and Ninject,
You will need to register- instruct the container once to resolve all the ISession to return your's session object.
The other way this could work for you is using Constructor injection. While this method isn't as clear cut as using an IoC library, it may help if you have a static way of accessing or fetching your session.
public class CreateProductViewModelValidator
{
private ISession _session;
public CreateProductViewModelValidator()
:this(SessionFactory.GetCurrentSession()) //Or some other way of fetching the repository.
{
}
internal CreateProductViewModelValidator(ISession session)
{
this._session = session;
RuleFor(m => m.Name);//More validation here using ISession...
}
}
I have been spending quite a bit of time thinking about this exact same issue. I am using ninject to inject my repository into my web UI layer so that my web UI only accesses the database through an interface.
I am wanting to be able to validate things that access the database such as checking for duplicate names and hence my validation needs to access the injected repository. I think that the best way to do this is to just setup Fluent Validation via the manual method rather than the MVC integrated way. For Example:
Create your validation Class (can pass in repository Interface):
public class CategoryDataBaseValidation : AbstractValidator<CategoryViewModel>
{
private IRepository repository;
public CategoryDataBaseValidation (IRepository repoParam)
{
repository = repoParam;
RuleFor(Category => Category.Name).Must(NotHaveDuplicateName).WithMessage("Name already exists");
}
private bool NotHaveDuplicateName(string name)
{
List<Category> c = repository.Categories.ToList(); //Just showing that you can access DB here and do what you like.
return false;
}
}
}
Then in your controller you can just create an instance of above class and pass in the repository (that ninject would have injected in the controller constructor)
[HttpPost]
public ActionResult Create(CategoryViewModel _CategoryViewModel )
{
CategoryDataBaseValidation validator = new CategoryDataBaseValidation (repository);
ValidationResult results = validator.Validate(_CategoryViewModel );
if (results.IsValid == false)
{
foreach (var failure in results.Errors)
{
//output error
}
}
return View(category);
}
Both the above files can live in the Web UI project and you can then also just use the standard MVC DataAnnotations for client side validation.
Just thought that I would put this up for comment / help someone.
Related
I have a class that implements the IValidatableObject interface, in order to validate the incoming data introduced by the user. The problem is that in order to validate that data, I need to use a class that implements the data repository pattern, which is in another assembly. Something like this:
public class SelectedFilteringCriteria : IValidatableObject
{
private IFiltersRepository _filtersRepository;
public SelectedFilteringCriteria(IFiltersRepository filtersRepository)
{
_filtersRepository = filtersRepository;
}
public int? SelectedValue { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
var valueOk = _filtersRepository.GetFilters().Any(
filter => filter.Value == SelectedValue
);
if (!valueOk)
{
results.Add(new ValidationResult("Not good :("));
}
return results;
}
}
The dependency container I'm using is Ninject. I would like to know if there's a way to tell MVC to inject the repository class into the IValidatableObject when it's going to be created.
Nope, it seems it's not possible because the MutableObjectModelBinder class, which is the one MVC 5 uses to create the corresponding object (SelectedFilteringCriteria in my case) from the action parameters, uses System.Activator instead of resolving the dependencies SelectedFilteringCriteria could have using the current DependencyResolver.
A workaround for this could be to do this inside the constructor of SelectedFilteringCriteria:
public SelectedFilteringCriteria()
{
_filtersRepository = DependencyResolver.Current.GetService<IFiltersRepository>();
}
But that could drive to the Service Locator Antipattern. Your choice.
I'm new to Dapper or even ASP.NET MVC and I'm trying to write what should be a very simple CRUD app. Basically I have two tables User and File. User table stores some details about the User and when you click details it should display some more details and any files that user will upload (there can be none or up to 10).
File table stores the filenames. How do I create a model and then view for something like this using Dapper. It seems simple but I can't seem to figure this out. Can I put both models on my view and then loop through the file model to display the files if any. if so then how?
here is my details controller.
public ActionResult Details(int id)
{
Users user = new Users();
using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myconn"].ConnectionString))
{
user= db.Query<Users>("SELECT * FROM Users As t LEFT JOIN Files AS f ON t.EID = f.EID WHERE t.EID=" +id, new{ id }).SingleOrDefault() ;
}
return View(trade);
}
First of all try to read more about architecture, learn how to organize your code at the first place. For instance calling database directly from controller is a bad idea. I would do something like this:
Move all database calls to separate repository classes according to responsibilities.
public class UsersRepository
{
public User GetUser(int id)
{
User user = new User();
using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myconn"].ConnectionString))
{
user= db.Query<User>("SELECT * FROM Users where EID=#id", new{ id }).SingleOrDefault();
}
return user;
}
public List<File> GetUserFiles(int id)
{
List<File> files = new List<File>();
using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myconn"].ConnectionString))
{
files = db.Query<File>("SELECT * FROM Files where UserID=#id", new{ id });
}
return files;
}
}
Create model to store your data for detail view
public class UserDetails
{
public User User { get; set; }
public List<File> Files { get; set; }
}
Create service or engine to organize you business logic
public class UsersService
{
private UsersRepository _usersRepository;
public UsersService()
{
_usersRepository = new UsersRepository();
}
public UserDetails GetUserDetails(int userId)
{
var details = new UserDetails();
details.User = _usersRepository.GetUser(id);
details.Files = _usersRepository.GetUserFiles(id);
return details;
}
}
Call it in controller
public class UsersController : Controller // or whatever the base class you have
{
private UsersService _usersService;
public UsersController()
{
_usersService = new UsersService();
}
public ActionResult Details(int id)
{
var details = _usersService.GetUserDetails(id);
return View(details);
}
}
But keep in mind that its very simplified example. For instance it is better to use dependency injection rather than initialize services or repositories in constructor. Also in many cases it is not very smart to use same classes for view and repository logic, consider using DTO and domain classes insead. For simple apps and demonstraion it should be ok though.
Hi I have model class which is written in MVC.I am using Ef database first approach. In model class I have some queries which deals with database. I have following questions :
1) Is it right way to use database related queries in Model and call that in controller or view?
2)If yes where I should call this model? In Controller or in view ??
3)How I should call this model? Say for example I have class called class1.cs in model.How I should call this model?
Your model contains classes that define the different objects troughout your project. This includes properties with their basic information and methods to perform actions on this object.
1)
Do you really need queries? Why not use the Entity Framework to do it for you? Create the mapping for your domain classes (either trough annotations or fluent api) and use the DbContext to retrieve and save the data stored in your database
2)
Ideally people create repositories that are injected into your controllers (Dependency Injection). These repositories can for example contain something like GetPersonById(int id). Inside this method there would be two things:
Perform an action on the domain object
Save it to the DbContext
For example:
public void Subscribe(int userID, Show show) {
var user = GetUserByID(userID);
if (!user.IsSubscribedTo(show.ShowID)) {
user.Subscribe(show);
_dbContext.SaveChanges();
}
}
Controller -> Method call in repository -> Perform action on corresponding domain object -> Save changes to the database
If you need something that doesn't require an object mutation, it's even more simple:
public User GetUserByID(int id) {
return _dbContext.Users.FirstOrDefault(x => x.ID == id);
}
3)
Trough repositories (see above). Your DbContext will have a bunch of DbSets that contain objects that correspond with every data entry in your database. Trough repositories you can work with these objects and manipulate them. When you call the DbContext.SaveChanges() method, it will look at what has changed in these lists and commit the changes to your database.
Repository example:
class User {
public int ID { get; set; }
public string Name { get; set; }
}
class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
public interface IUserRepository {
User GetUserByID (int id);
bool UsernameExists (string name);
}
public class UserRepository : IUserRepository {
private DatabaseContext _db;
public UserRepository(DatabaseContext db){
_db = db;
}
public User GetUserByID(int id) {
return _db.Users.FirstOrDefault(x => x.ID == id);
}
public User GetUserByUsername(string username) {
return _db.Users.FirstOrDefault(x => x.Name == username);
}
}
public class UserController : Controller {
private IUserRepository _userRepository;
public UserController(IUserRepository userRepository) {
_userRepository = userRepository;
}
public ActionResult Details(int id){
return View(_userRepository.GetUserByID(id);
}
}
// Ninject settings (install this extension, you want it):
private void AddBindings(){
kernel.Bind<DatabaseContext>().ToSelf().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
}
You could use some sort of Unit Of Work pattern which you inject in your controller constructor using an inversion of control container (IOC), for instance autofac.
Your unit of work class could hold a reference to repositories, where you would query/insert your data.
Roughly;
public class BackendController : Controller
{
private UnitOfWork _worker;
public BackendController(UnitOfWork worker)
{
this._worker = worker;
}
public ActionResult Admin()
{
var items = _worker.MyRepository.GetAll();
return View(items);
}
}
public class UnitOfWork
{
private ContentRepository _contentRepository;
public UnitOfWork()
{
}
public ContentRepository MyRepository
{
get
{
if (_contentRepository != null)
return _contentRepository;
else
return _contentRepository = new ContentRepository();
}
}
}
public class ContentRepository
{
// holds an object context and methods to retrieve and put data (EF or similar)
}
You would have to register your instance with the IOC container in global.asax, application_start for example, something like this (Using autofac as IOC):
UnitOfWork worker = new UnitOfWork();
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(worker).SingleInstance();
var container = builder.Build();
...
1) Is it right way to use database related queries in Model and call that in controller or view?
I would recommend not directly accessing the database in your model classes, as you have to remember that MVC is strictly a presentation layer pattern. If you do put your database access logic in your model classes, then you will not be able to have any other client use this functionality, such as a web service. Instead have logic that translates your business objects, defined outside of your ASP.NET MVC project, into your ASP.NET MVC model classes.
This is where the power of n-tier architecture shines, if you create a business and data-access layer, then I could write an ASP.NET MVC front-end, WebForms front-end, WPF front-end, WinForms front-end and all of them could access data using the same service. By putting the logic into the ASP.NET MVC model classes, then you are effectively forcing any other client to duplicate that logic again in their classes.
I have my Entity Framework Entities split out into a separate class library from my web project and data access layer. In my controller I make a call to my repository to get an IEnumerable<RobotDog.Entities.Movie> and then try to serialize into json using JavaScriptSerializer but I get a circular reference even though I'm using the [ScriptIgnore] attribute.
IMPORTANT: Originally I had my entities, data access and web all under one project and I was able to successfully serialize my entites without a circular reference. When I created separate layers that's when I started having problems. I did not change any of the entities.
An example of one of my entities in the RobotDog.Entities namespace:
namespace RobotDog.Entities {
public class Character {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(200)]
public string Name { get; set; }
public virtual Person Person { get; set; }
[ScriptIgnore]
public virtual Movie Movie { get; set; }
}
}
My controller:
namespace RobotDog.Web.Controllers {
public class MoviesController : Controller {
private UnitOfWork _unitOfWork = new UnitOfWork();
[HttpGet]
public ActionResult Index() {
var user = Membership.GetUser(User.Identity.Name);
if(user != null) {
var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(movies);
return View(json);
}
return View();
}
}
}
My Repository:
namespace RobotDog.DataAccess.Movies {
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
internal MovieContext Context;
internal DbSet<TEntity> DbSet;
public Repository(MovieContext context) {
if (context == null)
throw new ArgumentNullException("context");
Context = context;
DbSet = Context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
IQueryable<TEntity> query = DbSet;
if (predicate != null)
query = query.Where(predicate);
return orderBy != null ? orderBy(query).ToList() : query.ToList();
}
}
}
Maybe kinda late response, but I had similar problem with POCO Classes for Entity Framework Code-Firts. The problem was that may properties were declared as virtual. In this case EF creates proxy class which overrides the virtual property. It seems that ScriptIgnore attribute is not by default applied on overriden properties, unless you use it like this:
[ScriptIgnore(ApplyToOverrides=true)]
Circular object graphs cannot be JSON serialized. And when you give it a second thought it actually makes sense. The correct way to handle this is to use view models. You should never pass your domain entities directly to your views. Always define a view model containing only the necessary properties that you want to be exposed.
I am sure that the client consuming this JSON doesn't care about having this circular object graph. So simply define a view model breaking this circular dependency and including only the properties you need.
Then all you have to do is map your domain model to the view model and pass this view model to a JsonResult (yeah that's another issue in your code - you are manually JSON serializing and writing plumbing code in your controller action instead of delegating this to the framework).
So:
[HttpGet]
public ActionResult Index()
{
var user = Membership.GetUser(User.Identity.Name);
if(user != null)
{
IEnumerable<Movie> movies = _unitOfWork
.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey)
.Select(m => m.Movie);
IEnumerable<MovieViewModel> moviesVm = ... map the domain model to your view model
return Json(moviesVm, JsonRequestBehavior.AllowGet);
}
// return an empty movies array
var empty = Enumerable.Empty<MovieViewModel>();
return Json(empty, JsonRequestBehavior.AllowGet);
}
The important thing you should be focusing right now on is defining the MovieViewModel class which will contain only the information that you want to expose to the client as JSON. Break all circular references. Feel free to have additional view models that this main view model is referencing in order to map other entities.
And most importantly : never pass your domain models to the view. Always define view models. This way your application is completely independent of the underlying data access technology you are using. You could modify your DAL layer as much as you like without impacting the UI part because this UI is represented by view models.
I'm working on a asp.net mvc3 solution that has 3 projects Data, Service, and Web. I've been using interfaces to abstract the service layer as much as possible so the web only knows about the service layer, and not the Data where the true domain models are held. The web project uses view models and simply passes things to the service model as broken out parameters vs a domain object. For example creation of a user I'd use an interface like this.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
}
But after thinking about it for a while something like GetUsers I'd need to return a domain object of some type, and this would require me adding a data reference in the web project.
public interface IUserService
{
void CreateUser(string userName, string firstName, string lastName....);
**IEnumerable<User>** GetUsers();
}
So I think I have two choices, either break my domain objects into their own project which all projects then have reference to or possibly add the data reference to the web project. I think the first option is the best but I'm curious if there are other options. Thanks
Instead of returning User, I would:
// MyCompany.Data Project
public interface IUserService
{
IUserServiceResult<IUser> CreateUser(IUser User);
IUserServiceResult<IEnumerable<IUser>> GetUsers();
}
public interface IUserServiceResult<T>
{
bool IsSuccessful { get; }
string UserErrorMessage { get; }
T Data { get; }
}
public interface IUser
{ // Some Getter Properties
}
// MyCompany.Service
public class UserService : IUserService
{
public UserServiceResult<User> CreateUser(IUser User)
{
var result = new UserServiceResult<User>();
if (User == null)
{
// log the error AND
result.UserErrorMessage = "User information was not valid.";
// or
throw new ArgumentNullException("User");
}
// example only
result.IsSuccessful =
(Context.Users.FirstOrDefault(x => x.Email == User.Email) == null)
if (result.IsSuccessful)
{
User newUser;
// create user...
result.Data = newUser;
}
return result;
}
public IUserServiceResult<IEnumerable<IUser>> GetUsers()
{
// Similar to above, can check for authentication
// Maybe return IsSuccessful = false,
// UserErrorMessage = "Requires administrative privileges".
// or result.Data = new List<User>();
}
}
public class UserServiceResult<T> : IUserServiceResult<T>
{
bool IsSuccessful { get; set; }
string UserErrorMessage { get; set; }
T Data { get; set; }
}
public class User : IUser { } //
I like having the service or data tier always return a result type with a generic typed data. I find it especially helpful when passing it back to jQuery.
One way to do it is to have two separate projects, one for you Data classes, and one for your Models/ViewModels.
Controller makes a request to the service
Service retrieves data objects (I.E. User) with your repository
Either manually map a User to a UserModel or use http://automapper.codeplex.com/
Return the IEnumerable to the controller.
Now the controller works with the UserModel instead of the User. Which keeps your web application out of messing with your data classes.
You can also put the interfaces for your service into the models project and allow consumers of the Rest service access to the models and interfaces.