MVC 3 - How is this ever going to work? - c#

I have made this post over a year ago, and I think it makes sense to update it as it's getting quite a few views.
I'm either missing something out or Microsoft has really messed up MVC. I worked on Java MVC projects and they were clean and simple. This is however a complete mess IMO. Examples online such as NerdDinner and projects discussed on ASP.Net are too basic, hence why they "simply" work. Excuse if this sounds negative, but this is my experience so far.
I have a repository and a service that speaks to the repository. Controllers call service.
My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet.
*Update: Of course Microsoft hasn't messed anything up - I did. I didn't fully understand the tools that were at my disposal. The major flaw in what I have done, was that I have chosen a wrong technology for persisting my entities. LINQ to SQL works well in stateful applications as the data context can be easily tracked. However, this is not a case in stateless context. What would be the right choice? Entity Framework code first or code only work pretty well, but what's more importantly, is that it shouldn't matter. MVC, or front end applications must should not aware of how data is persisted. *
When creating entites I can use object binding:
[HttpPost]
public ActionResult Create(Customer c)
{
// Persistance logic and return view
}
This works great, MVC does some binding behind the scene and everything is "jolly good".
It wasn't "Jolly Good". Customer was a domain model, and what was worse, it was dependent on persistence medium, because it was generated by SQL metal. What I would do now, is design my domain model, which would be independent of data storage or presentation layers. I would then create view model from my domain model and use that instead.
As soon as I'd like to do some more complex, e.g. - save Order which is linked to the customer everything seems to break:
[HttpPost]
public ActionResult Create(Order o)
{
// Persistance logic and return view
}
To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId. I don't fancy sitting around debugging MVC code as I won't be able to change it in a hosting envrionment either way.
Ok, a bit of moaning here, sorry. What I would do now, is create a view model called NewOrder, or SaveOrder, or EditOrder depending on what I'm trying to achieve. This view model would contain all the properties that I'm interested in. Out-of-the-box auto binding, as the name implies, will bind submitted values and nothing will be lost. If I want custom behaviour, then I can implement my own "binding" and it will do the job.
Alternative is to use FormCollection:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
// Here I use the "magic" UpdateModel method which sometimes works and sometimes doesn't, at least for LINQ Entities.
}
This is used in books and tutorials, but I don't see a point in a method which has an alternative: TryUpdateModel - if this crashes or model is invalid, it attempts to update it either way. How can you be certain that this is going to work?
Autobinding with view models will work the most of the time. If it doesn't, then you can override it. How do you know it will always work? You unit test it and you sleep well.
Another approach that I have tried is using ViewModel - wrapper objects with validation rules. This sounds like a good idea, except that I don't want to add annotations to Entity classes. This approach is great for displaying the data, but what do you do when it comes to writing data?
[HttpPost]
public ActionResult Create(CustomViewWrapper submittedObject)
{
// Here I'd have to manually iterate through fields in submittedObject, map it to my Entities, and then, eventually, submit it to the service/repository.
}
** View model is a good way forward. There would have to be some mapping code from view model to the domain model, which can then be passed to the relevant service. This is not a correct way, but it's one way of doing it. Auto mapping tools are you best friends and you should find the one that suits your requirements, otherwise you'll be writing tons of boilerplate code.**
Am I missing something out or is this the way Microsoft MVC3 should work? I don't see how this is simplifying things, especiialy in comparisson to Java MVC.
I'm sorry if this sounds negative, but this has been my experience so far. I appreciate the fact that the framework is constantly being improved, methods like UpdateModel get introduced, but where is the documentation? Maybe it's time to stop and think for a little bit? I prefer my code to be consistent throughout, but with what I have seen so far, I have no confidence whatsoever that this is a right way forward.
I love the framework. There is so much to learn and it's not a lot more exciting then it has ever been. Should probably make another post regarding web forms. I hope this is helpful.

1) For the case of saving an order, and not having CustomerId present. If Order has a CustomerId property on it, and you have a stongly typed view, then you can persist this back to your controller action by adding
#Html.HiddenFor(model => model.CustomerId)
Doing this will have the default model binder populate things for you.
2) With respect to using a view model, I would recommend that approach. If you utilize something like AutoMapper you can take some of the pain out of redundant mapping scenarios. If you use something like Fluent Validation then you can separate validation concerns nicely.
Here's a good link on a general ASP.NET MVC implementation approach.

I don't think your issue is with asp.net MVC but with all the pieces You Choose to use together.
You want it raw and simple?
Use POCOs all around, and implement the repository where you need it.
I haven't used Java MVC, but it'd make the whole question look less like a rant if you include how you solved the particular problem in there.
Let's clear some misconceptions or maybe miscommunication:
You can pass complex objects through a post to the view. But you only want to do so if it makes sense, see next bullet
The sample you picked there rings some alarms. Accepting Customer data or CustomerID for an order and not checking authorization can be a Big security hole. The same could be said for an Order depending on what you are accepting/allowing. This is a Huge case for the use of ViewModels, regardless of POCOs, LINQ, Asp.net MVC or Java MVC.
You can pass simple values not being showed through a post to the view. It's done with hidden fields (which asp.net MVC supports very simply to use the model value), and in some scenarios it generates the hidden fields for you.
You are in no way forced to use linq2sql with Asp.net MVC. If you find it lacking for how you intend to use it, move away from it. Note I love linq2sql, but how it is tied to your view of what you can do with asp.net mvc is weird.
" I worked on Java MVC projects and they were clean and simple". Working on a project is not the same as designing the project yourself. Design skills does affect what you get out of anything. Not saying is your case, but just wanted to point that out given the lack of specifics on what you're missing from Java MVC.
"My data layer is NOT persistence independent, as the classes were generated by SQL metal. Because of this I have a lot of unnecessary functionality. Ideally I'd like to have POCO, but I didn't find a good way to achieve this yet". You picked the wrong technology, linq2sql is Not meant to fit that requirement. It haven't been a problem in the projects I've used it, but everything is designed in such a way that way less tied to its specifics than you seem to be. That said, just move to something else. btw, You should have shared what you used with Java MVC.
"CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId." If the property is in Order, You can bet your code has the bug. Now, that'd have been a totally different Real question, why it isn't using the CustomerId / such question would come with: your Customer class, the View, what you are passing to the View ... answers would include, but not be limited to: inspect the HTML source in the browser to see what value you are really posting with the source (alternatively use fiddler to see the same), make sure that CustomerId really has the value when you pass it to the View.
You said: ""magic" UpdateModel method which sometimes works and sometimes doesn't". It's not magic, you can see what it does and certainly find information on it. Something is off in the information you are posting, my bet is non optional fields or wrong values for information that's parsed ... views support adding validations for that. Without the validations, this can be lacking.
You said in a comment: "After UpdateModel is called, i can't explicitly set the CustomerId, I'll have to retrieve a customer object and then assign it to the order, which seems like an overhead as all that I need is CustomerId" ... you are accepting a CustomerId that is user input (even if it is a hidden field), you really want to Validate that input. Additionally you are contradicting yourself, you claim to just need CustomerId, but then you say you need the full Customer Object related to the order bound. Which is it, if you are only binding the CustomerId, you still need to go get that Customer and assign it to the property. There is no magic besides the scenes ...
Also in a comment: "Update model is something I'm avoiding completely now as I don't know how it will behave with LINQ entities. In the view model class I have created constructor that converts LINQ entity to my view model. This decreased amount of code in controller, but still doesn't feel right". Reason to use ViewModel (or EditModel) is not because it is linq2sql ... it is because, among many other reasons, you are exposing a model that allows to manipulate way beyond what you actually want to allow the user to modify. Exposing the raw model, if it has fields the user shouldn't be allowed to modify, is the real issue.

If your view is correctly defined then you can easily do this >
[HttpPost]
public ActionResult Create(Order o, int CustomerId)
{
//you got the id, life back to jolly good (hopefully)
// Persistance logic and return view
}
EDIT:
as attadieni mentioned, by correct view I meant you have something like this inside the form tag >
#Html.HiddenFor(model => model.CustomerId)
ASP.NET MVC will automatically bind to the respective parameters.

I must be missing the problem.
You have a controller Order with an Action of Create just like you said:
public class OrderController()
{
[HttpGet]
public ViewResult Create()
{
var vm = new OrderCreateViewModel {
Customers = _customersService.All(),
//An option, not the only solution; for simplicities sake
CustomerId = *some value which you might already know*;
//If you know it set it, if you don't use another scheme.
}
return View(vm);
}
[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
// Persistance logic and return view
}
}
The Create action posts back a view model of type OrderCreateViewModel that looks like such.
public class OrderCreateViewModel
{
// a whole bunch of order properties....
public Cart OrderItems { get; set; }
public int CustomerId { get; set; }
// Different options
public List<Customer> Customers { get; set; } // An option
public string CustomerName { get; set; } // An option to use as a client side search
}
Your view has a dropdown list of customers which you could add as a property to the viewmodel or a textbox which you wire up to to searching on the server side via JQuery where you could set a hidden field of CustomerId when a match is made, however you decide to do it. And if you already know the customerId ahead of time (which some of the other posts seems to imply) then just set it in the viewmodel and bypass all the above.
You have all of your order data. You have the customer Id of the customer attached to this order. You're good to go.
"To persist an order I need Customer or at least CustomerId. CustomerId was present in the view, but by the time it has got to Create method, it has lost CustomerId."
What? Why? If CustomerId was in the view, set, and posted back, it's in the model for the HttpPost Create method which is exactly where you need it. What do you mean it's being lost?
The ViewModel gets mapped to a Model object of type order. As suggested, using AutoMapper is helpful...
[HttpPost]
public ActionResult Create(OrderCreateViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// Persistance logic and return view
var orderToCreate = new Order();
//Build an AutoMapper map
Mapper.CreateMap<OrderCreateViewModel, Order>();
//Map View Model to object(s)
Mapper.Map(model, orderToCreate);
//Other specialized mapping and logic
_orderService.Create(orderToCreate);
//Handle outcome. return view, spit out error, etc.
}
It's not a necessity, you can map it manually, but it just makes things easier.
And you're set. If you don't want to use data annotations for validation, fine, do it in the service layer, use the fluent validation library mentioned, whatever you choose. Once you call the Create() method of your service layer with all the data, you're good to go.
Where's the disconnect? What are we missing?
ataddeini's answer is correct, I'm just trying to show a bit more code. Upvote ataddeini

If the Customer Id is already in the Order model (in this example) it should be available without extending the method signature. If you view the source on the rendered view, is the customer id correctly emitted in a hidden field within the form? Are you using the [Bind] attribute on the Order model class and inadvertently preventing the Customer Id from being populated?

I would think the Order table would include a CustomerID field, if so, the only problem is maybe you are not including any control in the view to keep that value, then is lost.
Try to follow this example.
1) GET action before sending to the View, let's say you assign the CustomerID at this point.
public ActionResult Create()
{
var o = new Order();
o.CustomerID = User.Identity.Name; // or any other wher you store the customerID
return View(o);
}
2) The View, if you don't use any control for the CustomerID, like textbox, combobox, etc, you must use a hidden field to keep the value.
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.CustomerID)
<label>Requested Date:</label>
#Html.TextBoxFor(m => m.DateRequested)
...
}
3) Finally, the POST action to get and persist the order. In here, as CustomerID was kept in the hidden value, the Model Binder will automatically put all the Form values into the Order object o, then you just need to use CRUD methods and persist it.
[HttpPost]
public ActionResult Create(Order o)
{
return View();
}
Can be two approaches for this, one to implicit save all Model values even if not used in the View, and the other is to keep only those values used. I think MVC is doing the right thing to follow the later, avoid unnecessary keep a lot of junk for bigger models, when the only think is, to name one, a CustomerName, somehow it can give you control on what data to keep through the whole cycle action-view-action and save memory.
For more complex scenarios, where not all fields are in the same model, you need to use ViewModels. For example for mater-detail scenarios you would create a OrderViewModel that has two properties: Order o, and IEnumerable< OrderDetail > od, but again, you will need explicit use the values in the View, or use hidden fields.
In recent releases now you can use POCO classes and Code-First that makes all cleaner and easier, You may want to try EF4 + CTP5.

if you are using services (aka; service layer, business facade), to process lets say the OrderModel, you can extract an Interface, and get your ViewModel/DTO to implement it, so that you can pass back the ViewModel/DTO to the service.
If you are using Repositories to directly manage the data (without a servie layer) in the controller, then you can do it the good old way of Loading the object from a repository and then doing an UpdateModel on it.
[HttpPost]
public ActionResult Create(string customerCode, int customerId, Order order)
{
var cust = _customerRepository.Get(customerId);
cust.AddOrder(order);//this should carry the customerId to the order.CustomerId
}
Also, URLs might help a bit where it makes sense, I mean you can add the customer identifier in the url to create the order for.
UpdateModel should work, if your FormCollection has values for non-nullable properties and they are empty/null in the FormCollection, then UpdateModel should fail.

Related

MVC - validation - should ViewModel have access to DB

I have a view model which should check that label of a new entity is unique (not in DB yet).
At the moment I've done it in the view model class:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PowerOrDuty != null)
{
if (PowerOrDuty.Identifier == null)
{
using (var db = new PowersAndDutiesContext())
{
var existingLabels = db.PowersAndDuties.Select(pod => pod.Label);
if (existingLabels.Contains(PowerOrDuty.Label))
{
yield return new ValidationResult("Cannot create a new power or duty because another power or duty with this label already exists");
}
}
}
......
Please note that this is a small internal app with small DB and my time is limited, so the code is not perfect.
I feel that DB access from view models might be a bad practice. Should view model have direct DB access? Should it be able to call a repository to get the available labels? Should validation requiring DB access be done in a controller instead?
Should view model have direct DB access?
I think this should be avoided at all cost
Should it be able to call a repository to get the available labels ?
This is not the concern of a ViewModel.
This would introduce some complexity in the testing of your ViewModel (which should almost need none) I guess it is a sign of trouble coming.
Should validation requiring DB access be done in a controller instead ?
Maybe, if by "DB" you mean "Repository". But what comes to mind is a separate custom validation class that you will be able to (un)plug, test, and reuse, in another controller for ajax validation, etc
I think that accessing DB from VM is not wrong... AFAIK it is not breaking MVC concept (since it is a presentation layer concept). Said that, it could be better if you have the Validate method provided by a Service Layer.
But all the logic related to the content of the ViewModel, it is better kept in the VM than in the Controller. Cleaner controllers is better.
Your view model should not be tied to your context, it only cares about displaying data and validating it after a submit. You can perform validation like a required field or a value in range, but you can't know if a label already exists in your database.
You can't also fetch a list of "forbidden labels" before displaying your form, in order to test your label afterwards, because that list could have changed during this time (another user updating you database).
In my opinion, validation at model level should focus on what it can validate without knowledge of the data source, and let your database notify you errors like submitting a duplicate value in a field which has an unique constraint. You'll catch exceptions coming from your database for errors like those, and manage them accordingly.
Anyway, i think there's no straightforward answer for a problem like this.
I personally like the ViewModels to be anemic -- simply classes with properties.
For custom server-side validation like this, I prefer it go either in a service, with the consumption of the service in your controller, or even behind a custom validator.
With a custom validator, you could even (optionally) execute the validation remotely. That gets a little more complex though, but I've done it using a generic remote validator that consumes an Ajax action method to perform the validation, and wire that up through both the client validator and remote validator (to ensure you have your validation logic in a single method).
But which ever way you go, I think it is more common -- and in my opinion, more clean -- to keep all logic out of your ViewModel. Even in a simple app, your ViewModel should be dumb to your database context. Ideally, only services (not necessarily web services, but just an abstraction layer) are aware of your database context.
This, to me, should be done regardless of the size of application. I think the effort and complexity (it only adds another assembly to your solution) is worth the abstraction you get. Down the road, if you happen to decide to consume your services from another application, or if you decide to swap out your database context, it's much easier with that abstraction in place.

ASP.NET MVC Design Issues

Whats the difference between Model and ViewModel? I should use both of them or I better skip one of them? who grabs the data from the database?
I wonder whats the best/right way to take my data from the database.
One option is to have a DAL (Data Access Layer) and instantiate it in every controller,
fill with it the viewmodels like:
var viewmodel = Dal.GetArticles();
Another option is to let the model itself grab the information from the Database:
var model = new ArticlesModel();
model.GetArticles();
public void GetArticles()
{
var context = new DbContext();
_articles = context.Articles
}
Another similar option is to have a static DAL so you can access it inside every model,
so each model will have a method to grab the data using the static DAL class (Which contain a DbContext class inside to access the Database)
public void GetArticles()
{
_articles = DAL.GetArticles();
}
So the general question is if the model itself needs to grab the data from the database or the controller itself can have access to the DAL.
While someone is writing a more useful answer, I will quickly address your points.
Model is the data you want to display.
More often than not, you will want to use object relational mapping so most of your business object classes correspond to database tables and you don't have to manually construct queries.
There are plenty of ORM solutions available, including Entity Framework, NHibernate and (now dying) LINQ to SQL.
There is also an awesome micro-ORM called Dapper which you may like if bigger frameworks feel unneccessarily bloated for your solution.
Make sure you learn about the differences between them.
DAL is more idiomatic in .NET than classes that “know” how to load themselves.
(Although in practice your solution will very likely be a mixture of both approaches—the key is, as usual, to keep the balance.)
My advice is to try keeping your models plain old CLR objects as long as your ORM allows it and as long as this doesn't add extra level of complexity to the calling code.
These objects, whenever possible (and sensible—there are exceptions for any rule!), should not be tied to a particular database or ORM implementation.
Migrating your code to another ORM, if needed, will be just a matter of rewriting data access layer.
You should understand, however, that this is not the main reason to separate DAL.
It is highly unlikely you'll want to change an ORM in the middle of the project, unless your initial choice was really unfit for the purpose or you suddenly gained a traction of 100,000 of users and your ORM can't handle it. Optimizing for this in the beginning is downright stupid because it distracts you from creating a great product capable of attracting even a fraction of hits you're optimizing for. (Disclaimer: I've walked this path before.)
Rather, the benefit of DAL is that you database access becomes always explicit and constrained to certain places where you want it to happen. For example, a view that received a model object to display will not be tempted to load something from the database, because in fact it is the job of controller to do so.
It's also generally good to separate things like business logic, presentation logic and database logic. Too often it results in better, less bug-ridden code. Also: you are likely to find it difficult to unit-test any code that relies on objects being loaded from the database. On the other hand, creating a “fake” in-memory data access layer is trivial with LINQ.
Please keep in mind that again, there are exceptions to this rule, like lazy properties generated by many ORMs that will load the associated objects on the go—even if called within a view. So what matters is you should make an informed decision when to allow data access and why. Syntaxic sugar might be useful but if your team has no idea about performance implications of loading 20,000 objects from ORM, it will become a problem.
Before using any ORM, learn how it works under the hood.
Choosing between Active Record-style objects and a DAL is mostly a matter of taste, common idioms in .NET, team habits and the possibility that DAL might eventually have to get replaced.
Finally, ViewModels are a different kind of beast.
Try to think of them like this:
You shouldn't have any logic in views that is more sophisticated than an if-then-else.
However, there often is some sophisticated logic in showing things.
Think pagination, sorting, combining different models in one view, understanding UI state.
These are the kinds of thing a view model could handle.
In simple cases, it just combines several different models into one “view-model”:
class AddOrderViewModel {
// So the user knows what is already ordered
public IEnumerable<Order> PreviousOrders { get; set; }
// Object being added (keeping a reference in case of validation errors)
public Order CurrentOrder { get; set; }
}
Models are just data, controllers combine the data and introduce some logic to describe data to be shown in view models, and views just render view models.
View model also serves as a kind of documentation. They answer two questions:
What data can I use in a view?
What data should I prepare in controller?
Instead of passing objects into ViewData and remembering their names and types, use generic views and put stuff in ViewModel's properties, which are statically typed and available with IntelliSense.
Also, you'll likely find it useful to create ViewModel hierarchies (but don't take it to extremes!). For example, if your site-wide navigation changes from breadcrumbs to something else, it's cool to just replace a property on base view model, a partial view to display it and the logic to construct it in the base controller. Keep it sensible.
A model represents the structure you like your data in and is not concerned about the view which may consume it. A model's intend is purely that of representing the structure.
A model may contain properties irrelevant to the view consuming it.
A view-model is designed with the view in mind. A view-model is intended for a 1-to-1 relationship to a view. A view-model only contains the basic fields and properties the view it is intended for requires.
In general you would have your controller contact a repository (In your example your DAL) obtaining the data and then populating either a model or view-model with the results, sending it down to the view.
Model (Domain Model): is the heart of the application, representing the biggest and most important business asset because it captures all the complex business entities, their relationships and their functionality.
ViewModel: Sitting atop the Model is the ViewModel:The two primary goals of the ViewModel are
1. to make the Model easily consumable by the View and
2. to separate and encapsulate the Model from the View.
Eg.
Model:
public class Product
{
...............
}
public class Category
{
...........
}
ViewModel:
public class ProductViewModel
{
public ProductViewModel(List<Product> products, List<Category> categories)
{
this.Products = products;
this.Categories = categories;
}
public List<Product> Products { get; set; }
public List<Category> Categories { get; set; }
}

Preparing models for ASP.NET MVC views

When returning strongly typed models for views such as Create and Edit (when validation of the object we are editing fails) I usually prepare the models like this:
//
// GET: /Invoice/Create
public virtual ActionResult Create()
{
// prepare the empty model
Invoice model = new Invoice();
model.Client = new Client();
model.Client.PostCode = new PostCode();
return View(model);
}
//
// POST: /Invoice/Create
[HttpPost]
public virtual ActionResult Create(Invoice document,
FormCollection collection)
{
// check for errors
if (!ViewData.ModelState.IsValid)
{
document.Client = new Client();
document.Client.PostCode = new PostCode();
return View(document);
}
Now I know that this is how others do it too, in fact you can see this same approach in MVC Music Store sample and others. However, this is very error prone because one might accidentally left out a referenced entity which is required in the view. It also requires too much thinking about view/model interaction. What I would want is some sort of automatism. Value typed properties in models usually aren't the problem because they default either to zero or empty strings. Reference types however should be initialized with new..but sooner or later we end up with code blocks that are being repeated, reference type properties being left out, etc..And I don't think it's good coding practice either.
What are other options we could take?
UPDATE:
Because replies kinda missed the point (they do not relief us of thinking about models in any way and require additional code in model classes), I was thinking if this option would work:
Use custom Action filter,
override OnActionExecuted()
use Reflection inside this method to take out the object from the Model and enumerate its public properties and try to initialize them.
I have steps 1, 2 and 3 partially implemented but I cannot figure out how to do "... = new Client();" programatically with Reflection.
Make the properties of your model return a new instance if it is null
private Client client;
public Client Client
{
get
{
if (client == null)
client = new Client();
return client;
}
}
I suggest that you use a Strongly typed view bound to a ViewModel that is distinct from the Domain Model you're trying to create, and put whatever necessary logic into the constructor of the ViewModel
I'm not sure I fully understand your question. You want what automated? ViewModels and Views? Are you creating strongly typed views?
I have created a T4 template that I point to a database and it generates a ViewModel for every table. Foreign keys become drop down lists, long strings get a TextArea instead of TextBox, etc. I then delete the ones I don't need and modify the ones I want to keep. It's not a totally automated process, but it does 80 to 90 percent of the work, depending upon the project.
Then I generate strongly typed Views from those ViewModels.
It also sounds like you might be interested in AutoMapper.

What is the preferred model configuration for CRUD?

I am attempting to perform crud operations within a simple content management website. In attempting to create my CRUD views for the entering of a piece of content, there are several drop-downs that need to be populated, and in the case of an edit operation they need to have specific values pre-selected. I have been reading a textbook on it and absorbing as much as I can through articles on the web, but I'm having trouble in determining where the best place is for the information belonging to these drop-downs. I could easily create model classes to identify them, and then I would have an option of either getting the data to fill them one at a time or have this information populated as properties in my content model class so that the value of the class is selected, but an IEnumerable property would be available to bind to directly.
Either way seems to work with using templates to create the drop-downs, but I'm trying to eliminate some of the "Select N+1" issues of retrieving these things individually, but I also don't want to pack my model full of too much junk that really doesn't belong there as considered against the MVC architecture.
So the basic question is: Does supporting information like drop-downs, filters, etc belong as sub-classes in the primary model class or should these be retrieved individually and presented as separate items by themselves? Or is there some other aspect to the architecture that should be used and I'm just missing the boat completely?
Articles, links, redirects are all welcomed. I have Googled this, and what I have found has either not answered this question or the answer is hiding within the mass of results.
example: Books and Authors entities
when creating a new book in a view, you need a select control that has its options populated as all the available authors.
the Book model should be clean and contain only the relevant fields e.g. Title, Author
the controller should have an IAuthorRepository _authorRepository; field that could have been set by a DependencyResolver or manually in the controllers constructor. IAuthorRepository would have a method such as IEnumerable GetAvailableAuthors();
the [HttpGet] Create() action could return an empty Book model directly and then stuff the _authorRepository into the dynamic ViewBag. ViewBag.AuthorRepository = _authorRepository;
The view would then pass the ViewBag.AuthorRepository to a partial view or a custom editor. Your model is kept clean in this scenario.
Some people don't like any use of ViewBag.Xxx (or ViewData["Xxx"]) because it's less than perfect MVC. I've seen examples that would Create a new type like BookViewModel. BookViewModel would then contain Book and IAuthorRepository in itself. the [HttpGet] Create() action would then return a BookViewModel object and the view would render its Author Select partial view by passing it the model.AuthorRepository instead of the ViewBag.AuthorRepository. This sort of starts to look more like MVVM here rather than MVC. Your instinct to keep any such collections or repositories out of the actual model (Book) is right. A clean model is very important and will give you the most flexibility in any pattern.
Not sure if this is the thing you are after but I use my own class library called Web.Shared which holds all my helper methods. I have a SelectListHelper class which I use to populate all my dropdownlists. That way my code is seperated from the main domain model and can be reused through this and any other MVC app which is part of my solution.
// Return days of the month for a dropdownlist
public static class SelectListHelper
{
public static SelectList DayList()
{
return NumberList(1, 31);
}
}
// Use in view
#Html.DropDownListFor(m => m.Day, SelectListHelper.DayList())
// Another one for selecting genders
public static SelectList GenderList(string selectedValue = null)
{
IList<KeyValuePair<string, string>> genders = new List<KeyValuePair<string, string>>();
genders.Insert(0, new KeyValuePair<string, string>("F", "Female"));
genders.Insert(0, new KeyValuePair<string, string>("M", "Male"));
genders.Insert(0, new KeyValuePair<string, string>("", "Choose Gender"));
return new SelectList(genders, "Key", "Value", selectedValue);
}
// Use in my edit view
#Html.DropDownListFor(m => m.Gender, SelectListHelper.GenderList())
Failing this take a look at MVC Scaffolding for creating data bound CRUD Views.
I agree with Tion's answer but my response can't fit in a comment.
First, the simple solution if you're using NHibernate: you can setup batching on has-many collections to load many entities in one query (instead of N!). We use a batch size of 100 with very noticeable performance gains. This won't help if you're just loading everything from a single table.
Now the trickier, but still very worthwhile solution.
If you have fairly static content that gets queried often (drop down lists, account name lookups, etc) you should really think about caching it in memory. If you're using IOC it's very easy to swap in a CachingRepository implementation for IRepsoitory<>. At my company we borrowed FubuCache from FubuMVC, but I think it's just a dictionary behind the scenes. If you have a server farm or multiple servers accessing the same data, you can use Memcached to share data.
The important thing about caching is knowing when to clear it. (ie, reload content from the database.) For us that means
1) every 5 minutes no matter what (other applications interact with the db so we need to pick up their changes.
2) any time an entity is inserted or updated we clear all the relevant caches.
Since most of our applications are reporting over large datasets with many joins we cache nearly everything. As long as your server has enough RAM you'll be fine.
ps http://axisofeval.blogspot.com/2010/11/numbers-everybody-should-know.html

Creating a large form with multiple dropdowns and text fields in ASP.NET MVC

In my continuing journey through ASP.NET MVC, I am now at the point where I need to render an edit/create form for an entity.
My entity consists of enums and a few other models, created in a repository via LINQtoSQL.
What I am struggling with right now is finding a decent way to render the edit/create forms which will contain a few dropdown lists and a number of text fields. I realize this may not be the most user-friendly approach, but it is what I am going with right now :).
I have a repository layer and a business layer. The controllers interface with the service layer.
Is it best to simply create a viewmodel like so?
public class EventFormViewModel
{
IEventService _eventService;
public IEvent Event { get; private set; }
public IEnumerable<EventCampaign> Campaigns { get; private set; }
public IEnumerable<SelectListItem> Statuses { get; private set; }
// Other tables/dropdowns go here
// Constructor
public EventFormViewModel(IEventService eventService, IEvent ev)
{
_eventService = eventService;
Event = ev;
// Initialize Collections
Campaigns = eventService.getCampaigns().ToSelectList(); //extn method maybe?
Statuses = eventService.getStatus().ToSelectList(); /extn for each table type?
}
So this will give me a new EventFormViewModel which I'll bind to a view. But is this the best way? I'd essentially be pulling all data back from the database for a few different tables and converting them to an IEnumerable. This doesn't seem overly efficient, but I suppose I could cache the contents of the dropdowns.
Also, if all I have is methods that get data for a dropdown, should I just skip the service layer and go right to the repository?
The last part of my question: For the ToSelectList() extension method, would it be possible to write one method for each table and use it generically even if some tables have different columns ("Id" and "Name" versus "Id" and "CampaignName").
Forgive me if this is too general, I'm just trying to avoid going down a dead-end road - or one that will have a lot of potholes.
I wouldn't provide an IEventService for my view model object. I prefer to think of the view model object as a dumb data transfer object. I would let the controller take care of asking the IEventService for the data and passing it on to the view model.
I'd essentially be pulling all data
back from the database for a few
different tables and converting them
to an IEnumerable
I don't see why this would be inefficient? You obviously shouldn't pull all data from the tables. Perform the filtering and joining you need to do in the database as usual. Put the result in the view model.
Also, if all I have is methods that
get data for a dropdown, should I just
skip the service layer and go right to
the repository?
If your application is very simple, then a service layer may be an unneeded layer of abstraction / indirection. But if your application is just a bit complex (from what you've posted above, I would guess that this is the case), consider what you will by taking a shortcut and going straight to a repository and compare this to what you will win in maintainability and testability if you use a service layer.
The worst thing you could do, would be to go through a service layer only when you feel there is a need for it, and go straight to the repository when the service layer will not be providing any extra logic. Whatever you do, be consistent (which almost always means: go through a service layer, even when your application is simple. It won't stay simple).
I would say if you're thinking of "skipping" a layer than you're not really ready to use MVC. The whole point of the layers, even when they're thin, is to facilitate unit testing and try to enforce separation of concerns.
As for generic methods, is there some reason you can just use the OOB objects and then extend them (with extension methods) when they fail to meet your needs?

Categories

Resources