Is it okay to hit the database from a custom model binder? - asp.net-mvc

Say I have an object that gets some data from HttpPost and some from the database. I think I want to allow the ModelBinder to go to the database/repository for the that data missing from the post. In practice, is this a good or bad idea?

I've decided to edit my original answer given my thinking on these types of things has evolved since early 2010.
In my original answer, I basically expressed that, while my instincts told me you shouldn't do this, I was uncomfortable saying we shouldn't without being able to articulate why.
Now, I'd recommend against this on the grounds that the responsibility of a Model Binder is to translate a user request into a Request Model and that retrieving data outside of what can be derived from the request goes beyond this scope of responsibility.

I would say a bad idea. The idea of the model binder is that it takes the parameters from the request and creates your model from those. If your model binder, behind the scenes, fills in some of the details from the database this breaks the paradigm. I'd much rather expose the database call in my controller by explicitly fetching the required extra data from the database directly. Note that this could be refactored into a method if used frequently.

I think this is perfectly fine and use this technique all the time.
The only arguments against are very pedantic and amount to arguing over philosophy. IMHO you can put "fill in missing posted data" code into you MVC app as a method in your base controller vs. method in you ActionFilter vs method in you ModelBinder. It all depends on who get what responsibility. To me the model binder can do a lot more than simply wire up some properties from posted values.
The reason I love doing database calls in my modelbinder is because it helps clean up your action methods.
//logic not in modelbinder
public ActionResult Edit( KittyCat cat )
{
DoSomeOrthagonalDatabaseCall( cat );
return View( new MODEL() );
}
vs.
//logic in model binder
public ActionResult Add( KittyCat cat )
{
return View( new MODEL() );
}

It violates the way MVC is supposed to work. ModelBinder is for binging Models from the data that comes from the view. Populating missing info from the database is something that is supposed to be handled by the controller. Ideally, it would have same data layer/repository class that it uses to do this.
The reason it should be in the controller is because this code is business logic. The business rules dictate that some data may be missing and thus it must be handled by the brains of the operation, the controller.
Take it a step further, say you want to log in the DB what info the user isn't posting, or catch an exception when getting the missing data and email admins about it. You have to put these in your model binder this way and it gets more and more ugly with the ModelBinder becoming more and more warped from its original purpose.
Basically you want everything but the controller to be as dumb and as specialized as possible, only knowing out how to carry out its specific area of expertise which is purely to assist the controller.

I would say, no.
Here's why: It would create a dependency on your database for testing your controller actions that would not be easy to abstract out.

I would say it is ok. The argument that creates dependency to database is a false argument for 2 reasons:
1- Database access should be abstracted via repository interfaces. Repository interfaces are part of the domain model and their implementation is part of the infrastructure/data access layer. So there is no dependency to the database.
2- Model Binders and Controllers are both part of presentation layer implemented using ASP.NET MVC Framework. If Controllers are allowed to access database using repository interfaces, how come Model Binders are not allowed?
Also, there are situations that you'd "better" fill the missing data in your model from Model Binders. Consider the scenario where you have a drop-down list on your view. The first time the view is loaded, the drop-down list is populated. The user submits the form but the validation fails. So you'll need to return the form again. At this stage, you'll have to re-populate the list in the Model for the drop-down list. Doing this in Controller looks ugly:
public ActionResult Save(DocumentViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Categories = _repository.GetAll();
return View(viewModel);
}
}
I believe the initialization of Categories here is ugly and like a code smell. What if you had a few properties that needed to be filled out from database? What if you had more than 1 action that had DocumentViewModel as an argument? You'd have to repeat this ugly step over and over. A better approach is to fill all the properties of the model using the Model Binder and pass it to the Controller. So the object that is passed to the controller is in a "consistent" state.

Related

MVC4 Action method AutoMap actionfilter fails to convert the view model to domain model

so, I've seen this working on a previous project in MVC3, so wondering if a) i've screwed it up, or b) MVC4 is doing something different (can't see it would be).
I have a model bound Razor view which submits to a controller action method (as is the way with MVC)
post action method:
[HttpPost]
[AutoMap(typeof(MyViewModel), typeof(MyDomainObj))]
public void PostAction(MyDomainObj obj)
{... etc.. etc..
The action filter eventually does something like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
NOTE: In Jimmy Bogard's example he used OnActionExecuted which I also tried..
The key issue I'm having is that at the pint where we get the "model" variable from the context, it's null. If I look at the filterContext.ActionParameters whilst debugging I can see a MyDomainObj instance!! which appears to (because it happens to have a prop name in common with the MyViewModel type) have been mapped from my form data!
So.. yes if I had MyViewModel type as the parameter to this method, then the param would be properly populated from the submitted form. But. I don't want to do that, I want to (and have done before based on JB's succinct how-to) converted the view model to domain model as part of the action executed/ing and then been able to just hit save on my domain model.
Summary - why is my ViewData.Model null on the post action filter?
Jimmmy also has/had a couple of ideas on how to implement post actions, along with another guy Matt Honeycutt who shares his view on how to do posts. I also believe Jimmy has gone in the direction of using explicit mapping in his get requests instead of attributes, as it can be hard to inject any extra code you need after mapping.
http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/
http://trycatchfail.com/blog/post/Cleaning-up-POSTs-in-ASPNET-MVC-the-Fail-Tracker-Way.aspx
For a post you really want a couple of things imo, the original Entity and the Form Data. You could load the entity like you do for the GET request and do normal model binding to get the form data (remember you can accept a different model for post backs than you spit out in your view) then make the changes in the action.
Of course this would require using AutoMapper in your action, which you seem to be trying to avoid. But unless you write a custom model binder then you're not going to magically get the formdata in a model as the built in one looks at the action paramters to figure out what to bind. For this reason i'd recommend not using a domain model as a parameter for an action, as it may fill out fields that you don't wish it to.
I've also seen Jimmy using a ModelBinder to do something similar to your AutoMapGet, which may be another alternative method, but I'm guessing you've seen that post.
My standard post takes Matt's approach, moving the validation out into a global attribute so it can't be forgotten (there are some downsides to this) then accepting a new view model explicity for the form data, then I explicity load the entity, use automapper to update it and call save. Most the actions only end up being about 5 lines long.
I do avoid using the static methods on AutoMapper and pass a IMapper in via constructor injection. This allows me to make it a bit more testable if I really need to, however the methods are normally so simple the tests don't add all that much value.

Moving Model Validation to Service Class - ASP.NET MVC

I want to be able to perform validation from within my Service classes. I have a Controller action that looks something like this:
public ActionResult Edit(Post post)
{
if(!ModelState.IsValid)
return View();
_postDataService.SavePost(post);
return View("Index");
}
I don't like the fact that my _postDataService.SavePost() can save invalid data and I want to move the model validation to my _postDataService.SavePost() method. My question is what is the most elegant way to do this? And if I move my model validation to my Service method, how do I return my model errors back to my controller? Lastly, where would model validation like uniqueness of the email address go since it require's some data access? Of all the similar questions i've looked at, none of them give a straight forward way to do this.
I also considered this solution but this article is old and I have a feeling it's not up-to-date.
I assume you are doing validation by putting attributes on properties in your Post model/entity class. If so, you can validate in your service layer by doing this:
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(post,
new ValidationContext(post, null, null), results, true);
This is essentially what the default modelbinder does when it validates and configures the ModelState object for the controller / action.
The beauty of this approach is that you don't have to return validation errors from the service layer. You will just rely on the default modelbinder to do the above code automatically. If someone ever tries to invoke that action without checking ModelState.IsValid, just have your service method throw an exception to remind them.
Update after comment
Yes, my answer recommends doing the validation twice.
How do I feel about it? I don't mind. We use Entity Framework 4.1 with MVC, and do not use entities in MVC. Instead we use automapper to DTO the entities into a separate viewmodel layer. Our EF entities are also decorated with ValidationAttributes, which EF evaluates automatically during any DbContext.SaveChanges() operation. We apply very similar validation attributes on properties of our viewmodel classes. This might not seem DRY, and there is definitely overlap, but in some cases the validation attributes on the UI side can be different than the validation attributes in the domain model.
We do not do validation in a service layer. Our service layer is simply an application flow coordinator, and takes no responsibility for business rules. However, validation still happens twice in our application. First, by the default model binder, against the viewmodel validation rules. Then if the transaction makes it to EF, validation performed against the entities. So we are actually validating 2 separate layers.
If you think about it though, you really are tackling 2 different concerns here. In the UI, you want MVC to display validation messages to users. ModelState is great for this, since it hooks nicely with MVC validation (model binding / jquery / unobtrusive / client-validation / etc).
Conversely in the domain, you are protecting your data integrity and enforcing business rules. The domain doesn't care about displaying messages to a user. For all it knows, the client may be a machine, WCF service, or something else. The role of the domain is to prevent a transaction from occurring, and (in our case) throws an exception rather than quietly trying to "work with" the client.

ASP.NET MVC View Model pattern - validation and database operation

At the start of the development I faced with problem called "an impedance mismatch between domain model and the view". To solve this problem I decide to use ViewModel pattern - for every view (that is strongly typed) we create viewmodel class. But where is the validation logic is locate - in viewmodel classes or in our domain model objects? And where we need to perform operations to query database - in controller action, and then populate viewmodel or straight in viewmodel?
Thank you.
You should have validation logic for the viewmodel. This is what the view sends and what should be validated. As far as populating the viewmodel is concerned here's how to proceed: write a repository which queries the database and returns models. Then map those models to viewmodels (AutoMapper can help you here). Finally return viewmodels to the view. This also works the other way around: the users POSTs some data to a controller action as the form of a viewmodel which once validated is mapped back to a model and passed to the repository for update.
As an alternative to Data Annotations you may take a look at FluentValidation for validating your view models. It integrates nicely with ASP.NET MVC.

ModelFactory in ASP.NET MVC to solve 'RenderPartial' issue

The 'RenderPartial()' method in ASP.NET MVC offeres a very low level of functionality. It does not provide, nor attempt to provide a true 'sub-controller' model *.
I have an increasing number of controls being rendered via 'RenderPartial()'. They fall into 3 main categories :
1) Controls that are direct
descendants of a specific page that
use that page's model
2) Controls that are direct
descendants of a specific page that
use that page's model with an
additional key of some type.
Think implementation of
'DataRepeater'.
3) Controls that represent unrelated
functionality to the page they appear
on. This could be anything from a
banner rotator, to a feedback form,
store locator, mailing list signup.
The key point being it doesn't care
what page it is put on.
Because of the way the ViewData model works there only exists one model object per request - thats to say anything the subcontrols need must be present in the page model.
Ultimately the MVC team will hopefully come out with a true 'subcontroller' model, but until then I'm just adding anything to the main page model that the child controls also need.
In the case of (3) above this means my model for 'ProductModel' may have to contain a field for 'MailingListSignup' model. Obviously that is not ideal, but i've accepted this at the best compromise with the current framework - and least likely to 'close any doors' to a future subcontroller model.
The controller should be responsible for getting the data for a model because the model should really just be a dumb data structure that doesn't know where it gets its data from. But I don't want the controller to have to create the model in several different places.
What I have begun doing is creating a factory to create me the model. This factory is called by the controller (the model doesn't know about the factory).
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
So my actual question is how are other people with this same issue actually creating the models. What is going to be the best approach for future compatibility with new MVC features?
NB: There are issues with RenderAction() that I won't go into here - not least that its only in MVCContrib and not going to be in the RTM version of ASP.NET-MVC. Other issues caused sufficent problems that I elected not to use it. So lets pretend for now that only RenderPartial() exists - or at least that thats what I've decided to use.
Instead of adding things like MailingListSignup as a property of your ProductModel, encapsulate both at the same level in a class like ProductViewModel that looks like:
public class ProductViewModel() {
public ProductModel productModel;
public MailingListSignup signup;
}
Then get your View to be strongly-typed to the ProductViewModel class. You can access the ProductModel by calling Model.productModel, and you can access the signup class using Model.signup.
This is a loose interpretation of Fowler's 'Presentation Model' (http://martinfowler.com/eaaDev/PresentationModel.html), but I've seen it used by some Microsoft devs, such as Rob Conery and Stephen Walther.
One approach I've seen for this scenario is to use an action-filter to populate the data for the partial view - i.e. subclass ActionFilterAttribute. In the OnActionExecuting, add the data into the ViewData. Then you just have to decorate the different actions that use that partial view with the filter.
There's a RenderPartial overload I use that let's you specify a new ViewData and Model:
RenderPartial code
If you look at the previous link of the MVC source code, as well as the following (look for RenderPartialInternal method):
RenderPartialInternal code
you can see that if basically copies the viewdata you pass creating a new Dictionary and sets the Model to be used in the control. So the page can have a Model, but then pass a different Model to the sub-control.
If the sub-controls aren't referred directly from the main View Model, you could do the trick Marc Gravell mentions to add your custom logic.
One method I tried was to use a strongly typed partial view with an interface. In most situations an agregated ViewModel is the better way, but I still want to share this.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>
The Viewmodel implements the interface
public class ProductViewModel:IMailingListSignup
Thats not perfect at all but solves some issues: You can still easily map properties from your route to the model. I am not shure if you can have a route parameter map to the properties of MailingListSignup otherwise.
You still have the problem of filling the Model. If its not to late I prefer to do it in OnActionExecuted. I dont see how you can fill a Model in OnActionExecuting.

ASP.NET MVC - User Input and Service/Repository - Where to do Validation?

This might be too opinionated a question, but looking for help!
I have been trying to refine my ASP.NET MVC program structure. I just started using it at preview 5 and it is my first foray into business application development -- so everyting is new!
At the controller level, I have a service object responsible for talking to the repository and taking care of all business logic. At the action level, I have an object that holds all view data -- user input and generated output -- that I'll call view object (is there a general term for this?). Unlike most examples I see, this object is not a database object, but an object specific to the view.
So now I want to add user validation. The problem is, I'm not sure where to put it. It makes the most sense to me to do it in the Service layer. The Service layer is responsible for all the business logic and validation is business logic. On the other hand, most validation frameworks that I see are for validating an object, which makes me think the view object should be validation aware. Finally, there are some validation methods that would require a database connection (checking if a user input field has a corresponding database record for example), and the view object has no concept of a database, only the Service.
So some options I see are:
Do validation in the Service.Method on the parameters passed to the method.
Do validation in the view object before calling Service.Method.
Do validation in the view object but make the Service.Method require a view object reference so it is initiating the validation on the object.
I'm sure there are more. I'm curious of how other people handle user input validation in the MVC sense. I've previously used the Enterprise Validation Block and liked being able to use stock validators for everything, but I'm not sure how to make it fit into a seperate view object and service layer. It would be easy if they (view object / service) were the same object, which is maybe what people do? Like I said, its all new to me and I'm looking for best practice / patterns.
I typically do basic validation (required fields, email format, etc.) in the controller action when the form is submitted. I then let the business layer handle validation that requires business knowledge. I usually double check the basic stuff in the business layer as well, so if I expose that logic through web services or use it in another application later, I still have validation where it is most important (IMO).
There are some interesting links on this
MVC & MS Validation Application Block
MVC & Data Annotation Validators
Form Validation video
Personally, i've added validation to my Service layer objects (first two links). This way, if any method in any controller decides to call my service method .. the logic is all checked and boxed in one location. DRY.
That said, i also have some UI validation (3rd link) .. to reduce the roundtrip time.
Lastly, the current MVC dll's have the ability to pass error messages back to the UI .. so the view can display them nicely. Check out :-
ViewData.ModelState.AddModelError(key, message)
hth!
Check the following blog posts
http://blog.codeville.net/2008/09/08/thoughts-on-validation-in-aspnet-mvc-applications/
http://www.emadibrahim.com/2008/09/08/client-server-side-validation-in-aspnet-mvc/
Take a look at the S#arp Architecture project. Validation is handled on the model to ensure that no entity is persisted to the database in an invalid state. It does this by using NHibernate.Validator and attaching it to NHibernate's save and update events.
Personally, this approach makes the most sense to me since you don't have to duplicate your validation logic in multiple controllers.
I was afraid I'd get no replies for my post, happy to be wrong!
I've read those links before, but probably a month or more ago, and re-reading them with what I understand now has been very helpful. I really like Steve Sanderson's post with the sliding scale, but wish he would show an example of validating something at the right-end of the spectrum.
As an example in his blog he gives: " 'usernames must be unique' will probably be enforced in your database". So would this be something like:
public static void SavePerson(Person person)
{
// make sure it meets some format requirement
// in this case the object is responsible for validation and the service layer is the caller
person.EnsureValid();
// todo: action to verify username is unique by checking database
// in this case the service layer is responsible for calling and implementing validation
// todo: action to save to database
}
This makes sense, and would show my trouble grasping where to put validation as it is inside both the service layer (very unique name) and view-object (verify formats).
Another concern I have is the service layer starts to balloon with validation logic. Maybe split it out to a different class or something? In my case some validation logic might be shared between services, so I would like to think of a DRY way to implement this. Fun stuff to think about!
Emad Ibrahim's link is great in that once I start to understand this process a bit more I was going to look for a way to generate javascript client-side validation using the same set of rules without having to repeat code. He already has that :)
I have heard about S#arp but not sat down and seen how it works (I'm not sure if there is much in the way of demos on it, or if downloading the code is the demo!). I'm not sure if doing validation on the database model only would be sufficient. It seems to me there would be plenty of valid model states with regards to the database that business logic would say are invalid (such as date ranges / must be before / after / etc). Those are the cases that are wracking my brain :)
Also, a link I liked (googled it after I saw Emad reply to Steves post with BLL and no idea what it meant... duh):
http://en.wikipedia.org/wiki/Business_logic_layer
So I didn't know it, but I think this is the model I'm writing to: Business Process object that handles data interactions, and Business Entities that are logical models rather than database models. I think I need to start reading some more fundamental patterns and practices with this stuff to better understand the concepts (it seems like a lot of this is stuff Java people write vs. .NET people). It might be time to take a step back :)
I have come across this same issue in a recent project. First, to restate the problem, I am trying to follow the domain-centric approach of DDD. I have entities composed into aggregates that can validate themselves, and the repositories verify validity on save. The UI can also get validity information from an aggregate in order to display error feedback to the client. The general approach is to leverage as much as possible ASP.NET MVC's model binding, and validation/form UI helpers. This creates the simple UI flow: 1) bind, 2) validate, 3) if valid, save, else re-populate view.
However, it is not directly obvious how to do leverage ASP.NET MVC and this simple flow when DDD services are involved. Originally, I developed my services as such:
public class SomeProcessService
{
public Result Execute(int anAggregateID, int anotherAggregateID, string someData)
{
// validate input
// if invalid, return failures
// else
// modify aggregates
// using (transaction)
// {
// save aggregates
// commit
// }
// return success
}
}
The problem is that the validation and the save are inextricably linked in the method. To leverage the MVC model binding, we need something that serves as a model to bind to. I am refactoring to this:
public class SomeProcessService
{
public class Request : IValidateable
{
public int AggregateID {get;set;}
public int AnotherAggregateID {get;set;}
public string SomeData {get;set;}
public Result Validate()
{
// validation
}
}
public void Execute(Request request)
{
// validate input by calling request.Validate()
// if invalid, throw new ValidationException(request)
// else
// modify aggregates
// using (transaction)
// {
// save aggregates
// commit
// }
// return success
}
}
This repurposes the Parameter Object pattern to separate method input validation. I can bind to a SomeProcessService.Request object in my controller, as well as get validation information there. If all is well, from my controller I initiate the service call using the Request object as the parameter. This approach seems to happily marry DDD services with ASP.NET MVC validation requirements.

Resources