I have a bunch of commonly used Lists whcih need to populate dropdownlists. Instead of defining ViewModels with Lists here is what I am doing.
#Html.DropDownListFor(model => project.TypeID, new SelectList(#PSS.Helpers.ProjectTypes.ProjectTypesList(),"id","name"))
where the Helper class is defined as follows
namespace PSS.Helpers
{
public class ProjectTypes
{
public static List<ProjectType> ProjectTypesList()
{
MyContext db = new MyContext();
return db.ProjectTypes.ToList<ProjectType>();
}
}
}
Is there anything wrong with doing this? am I breaking any rules?
With this code you are likely to hit your database more times than you would want to. Because every time you hit this helper you are creating a new Entity Framework context and hitting the database to get your list of ProjectTypes. To me, that is bad.
Related
I have two models: Reptile and Species. A Reptile has a Species, stored as an ID in the database:
How should I set up the details controller action/view for Reptile so that it displays the Title property of the Species instead of the ID that the Reptile uses?
My initial thought was just to grab the data in the controller and pass it in the ViewBag, but this seems inappropriate, and overly complex when it's time to setup the list action.
What's the proper way to do this?
It seems like I need to make a view model, but what confuses me is how to properly design it so that there aren't too many database calls.
Here is my initial attempt at a ViewModel:
public class ReptileDetailsModel
{
[Required]
public String Species { get; set; }
//etc...
public ReptileDetailsModel(Reptile reptile)
{
this.Species = reptile.Species.Title;
// etc...
}
}
Another way to achieve the same thing in more generic way is to use AutoMapper
Few advantages I can think of:
Automatically map exact properties (you only need specify anything that is exception to the rule)
Centralized in one class / method, whatever
Ability to ignore, map to another classes properties, even custom logic
Non intrusive, it is up to you how / when you want to use it.
In your particular instance I would create a mapper something like
Mapper.CreateMap<Reptile, ReptileDetailsModel>()
.ForMember(dest => dest.Species,
options => options.MapFrom(source => source.Species.Title));
This mapper info need to be registered somewhere. In MVC projects I have been involved, I would register a mapper into global.asax.
Then in your controller, you would want to invoke the mapper to map your reptile instance to your model
ReptileDetailsModel model = Mapper.Map<ReptileDetailsModel>(reptile);
There are many ways to use the AutoMapper within MVC, but this is probably a start.
I didn't realize it at the time, but I was using:
public ActionResult Index()
{
using (var db = new ModelsContainer())
{
return View(db.Reptiles.ToList());
}
}
This was causing the database (and thus model property) to expire before the view was rendered, causing this error (adding for search engines):
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Set the Species class as a model for your strongly typed Reptile View. Then display the Title property of it. Your action method should look like this:
public ActionResult Reptile(Reptile rep)
{
return View(db.Species.Where(x=>x.ID == rep.SpeciesID).Single());
}
this way you would only need to call database once in order to generate the view.
I'm trying to update a record in a database with the values in a ViewModel via Linq To SQL. I had it working but it has since stopped (more on this later).
I have a Customers domain object mapped to a table. I don't need all the fields so I use AutoMapper to map it to a ViewModel (CustomerEditVM) that has a subset of the Customer fields. I do this in my service layer:
public CustomerEditVM GetCustomerEditVMById(int custId)
{
var domainCustomer = _repository.GetCustomerById(custId);
Mapper.CreateMap<Customer, CustomerEditVM>();
CustomerEditVM customer = Mapper.Map<Customer, CustomerEditVM>(domainCustomer);
return customer;
}
I send the CustomerEditVM ViewModel to my view and the user edits the record. In my service layer I map it back to a Customer object and call the Update method in my repository:
public void SaveCustomer(CustomerEditVM customer)
{
Mapper.CreateMap<CustomerEditVM, Customer>();
Customer newCust = Mapper.Map<CustomerEditVM, Customer>(customer);
_repository.Update(newCust);
}
Here is my repository and Update method:
namespace AuctionAdmin.Models.Repositories
{
public interface ICustomerRepository
{
Customer GetCustomerById(int custId);
void Update(Customer customer);
}
public class CustomerRepository : ICustomerRepository
{
private AuctionAdminDataContext _dataContext;
public CustomerRepository()
{
_dataContext = new AuctionAdminDataContext();
}
public Customer GetCustomerById(int custId)
{
var customer = _dataContext.Customers.SingleOrDefault(c => c.CustomerID == custId);
return customer;
}
public void Update(Customer customer)
{
_dataContext.Customers.Attach(customer);
_dataContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer);
_dataContext.SubmitChanges();
}
}
}
The Update used to work fine but now fails with this error:
Unable to refresh the specified object. The object no longer exists
in the database.
I'm not sure why this worked so well before and now doesn't but clearly I'm not using Linq to update the database properly. How should I be doing this?
Thanks
So my understanding is that Automapper wasn't really designed to work this way. It flattens objects like you are doing to get your view model but it doesn't really do things the other way. I believe this is by design because Jimmy & Crew are using more of a command pattern with messaging to save things back into the database.
However, I know that doesn't solve your problem. So here are a few things.
With Linq2Sql You need to pull the object out, then update it, then save it. This is
because linq2sql is tracking the changes of the object. However, between requests you no longer have the linq2sql object.
public void SaveCustomer(CustomerEditVM customer)
{
//Get the customer from repo
var domainCustomer = _repository.GetCustomerById(customer.Id);
Mapper.CreateMap<CustomerEditVM, Customer>();
Customer newCust = Mapper.Map<CustomerEditVM, Customer>(domainCustomer);
_repository.Update(newCust);
}
However, that most likely won't work because of the way linq2sql and automapper work. Even if the mapping does work, linq2sql might not show that changes have been made to the object. You are going to be better off mapping this by hand.
Also, there is really no such thing as Update in Linq2Sql.
public void Update(Customer customer)
{
_dataContext.Customers.Attach(customer);
_dataContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, customer);
_dataContext.SubmitChanges();
}
All you need to do is get the object from linq2sql update it and call SubmitChanges(); on the _dataContext. It takes care of it for you. I have seen some repository interfaces include a Update method but it doesn't do anything in a Linq2Sql implementation. Also, its probably not the best idea to call SubmitChanges in the update method as you may want to update may items then submit all the changes at once, which is kind of the purpose of submitchanges (ie unit of work)
I have a simple database from which I am generating Linq2SQL classes using a datacontext. In one part of my application I would like to load the entire relationship such that I get child records. In another part of the application I am passing that relation across the boundary between model and view and I would like to not pass the entire thing since the set of children is pretty large. Is there a way to not have these child classes exported in one section and be exported in another?
I am aware of setting the child property to False in the datacontext but that is a global change.
You can do it with the DataLoadOptions setting on the data context. You'll probably have some sort of builder class somewhere in your application. For the quickest and dirtiest solution, you could do something like the following...
public class SqlContextBuilder
{
public SqlContextBuilder(MyDataContext dataContext)
{
_dataContext = dataContext;
}
private readonly MyDataContext _dataContext;
public MyDataContext CreateEagerLoadingContext()
{
var options = new DataLoadOptions();
// set those options!
_dataContext.LoadOptions = options;
return _dataContext;
}
public MyDataContext CreateLazyLoadingContext()
{
// lazy loading happens by default
return _dataContext;
}
}
One of the solutions is to pass the relation as IQuerable. This will make sure that the relation is not executed until is it required. If you loop over the relation then it will be executed for each child.
Another technique might be to use DTO objects to create a ViewModel of which you like to pass. This means your ViewModel might be very similar to the interface.
For those that create ViewModels (for use by typed views) in ASP.NET MVC, do you prefer to fetch the data from a service/repository from within the ViewModel, or the controller classes?
For example, we started by having ViewModels essentially being DTOs and allowing our Controllers to fetch the data (grossly oversimplified example assumes that the user can only change employee name):
public class EmployeeViewModel
{
public String Name; //posted back
public int Num; //posted back
public IEnumerable<Dependent> Dependents; //static
public IEnumerable<Spouse> Spouses; //static
}
public class EmployeeController()
{
...
public ActionResult Employee(int empNum)
{
Models.EmployeeViewModel model = new Models.EmployeeViewModel();
model.Name = _empSvc.FetchEmployee(empNum).Name;
model.Num = empNum;
model.Dependents = _peopleSvc.FetchDependentsForView(empNum);
model.Spouses = _peopleSvc.FetchDependentsForView(empNum);
return View(model);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Employee(Models.EmployeeViewModel model)
{
if (!_empSvc.ValidateAndSaveName(model.Num, model.Name))
{
model.Dependents = _peopleSvc.FetchDependentsForView(model.Num);
model.Spouses = _peopleSvc.FetchDependentsForView(model.Num);
return View(model);
}
this.RedirectToAction(c => c.Index());
}
}
This all seemed fine until we started creating large views (40+ fields) with many drop downs and such. Since the screens would have a GET and POST action (with POST returning a view if there was a validation error), we'd be duplicating code and making ViewModels larger than they probably should be.
I'm thinking the alternative would be to Fetch the data via the Service within the ViewModel. My concern is that we'd then have some data populated from the ViewModel and some from the Controller (e.g. in the example above, Name would be populated from the Controller since it is a posted value, while Dependents and Spouses would be populated via some type of GetStaticData() function in the ViewModel).
Thoughts?
I encountered the same issue. I started creating classes for each action when the code got too big for the action methods. Yes you will have some data retrieval in classes and some in the controller methods. The alternative is to have all the data retrieval in classes, but half the classes you won't really need, they will have been created for consistency sake or have all the data retrieval in the controller methods, but again, some of those methods will be too complex and needed to have been abstracted into classes... so pick your poison. I would rather have a little inconsistency and have the right solution for the job.
As for putting behavior into the ViewModel, I don't, the point of the ViewModel is to be a thin class for setting and extracting values from the View.
There have been cases where I've put conversion methods in the ViewModel. For instance I need to convert the ViewModel to the corresponding entity or I need to load the ViewModel with data from the Entity.
To answer your question, I prefer to retrieve data from with in the controller/action methods.
Typically with DropDowns, I create a dropdown service. DropDowns tend to be the same data that spans views. With the dropdowns in a service I can use them on other views and/or Cache them.
Depending on the layout, 40 plus fields could create a cluttered view. Depending the type of data, I would try to span that many fields across multiple views with some sort of tabbed or wizard interface.
There's more than that ;-) You can fetch in model binder or action filter. For the second option, check Jimmy Bogard's blog somewhere around here. I personally do it in model binders. I use ViewModel like this: My custom ASP.NET MVC entity binding: is it a good solution?. It is processed by my custom model binder:
public object BindModel(ControllerContext c, BindingContext b)
{
var id = b.ValueProvider[b.ModelName]; // don't remember exact syntax
var repository = ServiceLocator.GetInstance(GetRepositoryType(b.ModelType));
var obj = repository.Get(id);
if (obj == null)
b.ModelState.AddModelError(b.ModelName, "Not found in database");
return obj;
}
public ActionResult Action(EntityViewModel<Order> order)
{
if (!ModelState.IsValid)
...;
}
You can also see an example of model binder doing repository access in S#arp Architecture.
As for static data in view models, I'm still exploring approaches. For example, you can have your view models remember the entities instead of lists, and
public class MyViewModel
{
public MyViewModel(Order order, IEmployeesSvc _svc)
{
}
public IList<Employee> GetEmployeesList()
{
return _svc.GetEmployeesFor(order.Number);
}
}
You decide how you inject _svc into ViewModel, but it's basically the same as you do for controller. Just beware that ViewModel is also created by MVC via parameterless constructor, so you either use ServiceLocator or extend MVC for ViewModel creation - for example, inside your custom model binder. Or you can use Jimmy Bogard's approach with AutoMapper which does also support IoC containers.
The common approach here is that whenever I see repetative code, I look to eliminate it. 100 controller actions doing domain-viewmodel marshalling plus repository lookup is a bad case. Single model binder doing it in generic way is a good one.
I wouldn't be fetching data from the database in your ViewModel. The ViewModel exists to promote separation of concerns (between your View and your Model). Tangling up persistance logic in there kind of defeats the purpose.
Luckily, the ASP.NET MVC framework gives us more integration points, specifically the ModelBinder.
I've got an implementation of a generic ModelBinder pulling information from the service layer at:-
http://www.iaingalloway.com/going-further-a-generic-servicelayer-modelbinder
It doesn't use a ViewModel, but that's easily fixed. It's by no means the only implementation. For a real-world project, you're probably better off with a less generic, more customised solution.
If you're diligent, your GET methods don't even need to know that the service layer exists.
The solution probably looks something like:-
Controller action method:-
public ActionResult Details(MyTypeIndexViewModel model)
{
if( ModelState.IsValid )
{
return View(model);
}
else
{
// Handle the case where the ModelState is invalid
// usually because they've requested MyType/Details/x
// and there's no matching MyType in the repository
// e.g. return RedirectToAction("Index")
}
}
ModelBinder:-
public object BindModel
(
ControllerContext controllerContext,
BindingContext bindingContext
)
{
// Get the Primary Key from the requestValueProvider.
// e.g. bindingContext.ValueProvider["id"]
int id = ...;
// Get an instance of your service layer via your
// favourite dependancy injection framework.
// Or grab the controller's copy e.g.
// (controllerContext.Controller as MyController).Service
IMyTypeService service = ...;
MyType myType = service.GetMyTypeById(id)
if (myType == null)
{
// handle the case where the PK has no matching MyType in the repository
// e.g. bindingContext.ModelState.AddModelError(...)
}
MyTypeIndexViewModel model = new MyTypeIndexViewModel(myType);
// If you've got more repository calls to make
// (e.g. populating extra fields on the model)
// you can do that here.
return model;
}
ViewModel:-
public class MyTypeIndexViewModel
{
public MyTypeIndexViewModel(MyType source)
{
// Bind all the properties of the ViewModel in here, or better
// inherit from e.g. MyTypeViewModel, bind all the properties
// shared between views in there and chain up base(source)
}
}
Build your service layer, and register your ModelBinder as normal.
Here's another solution: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/29/how-we-do-mvc-view-models.aspx
Main points there:
Mapping is done by a mediator - in this case it is AutoMapper but it can be your own class (though more to code). This keeps both Domain and ViewModel concentrated on the domain/presentation logic. The mediator (mapper) will contain (mostly automatic) logic for mapping, including injected services.
Mapping is applied automatically, all you do is tell the action filter the source/destination types - very clean.
(Seems to be important for you) AutoMapper supports nested mappings/types, so you can have your ViewModel combined of several independent view models, so that your "screen DTO" is not messy.
Like in this model:
public class WholeViewModel
{
public Part1ViewModel ModelPart1 { get; set; }
public Part2ViewModel ModelPart2 { get; set; }
}
you re-use mappings for specific parts of your View, and you don't write any new line of code, since there're already mappings for the partial view models.
If you don't want AutoMapper, you have have IViewModelMapper interfaces, and then your IoC container will help your action filter to find appropriate
container.Resolve(typeof(IViewModelMapper<>).MakeGenericType(mysourcetype, mydesttype))
and it will also provide any required external services to that mapper (this is possible with AutoMapper, too). But of course AutoMapper can do recursions and anyway, why write additional AutoMapper ;-)
Consider passing your services into the custom ViewModel on its constructor (ala Dependency Injection). That removes the model population code from your controller and allows it to focus on controlling the logical flow of the application. Custom ViewModels are an ideal place to abstract the preparation of things like SelectLists that your droplists will depend on.
Lots of code in the controller for things like retrieving data isn't considered a best practice. The controller's primary responsibility is to "control" the flow of the application.
Submitting this one late... Bounty is almost over. But...
Another mapper to look at is Automapper: http://www.codeplex.com/AutoMapper
And overview on how to use it: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01/22/automapper-the-object-object-mapper.aspx
I really like it's syntax.
// place this somewhere in your globals, or base controller constructor
Mapper.CreateMap<Employee, EmployeeViewModel>();
Now, in your controller, I would use multiple viewmodels. This enforces DRY by allowing you to reuse those viewmodels elsewhere in your application. I would not bind them all to 1 viewmodel. I would refactor to something like:
public class EmployeeController()
{
private IEmployeeService _empSvc;
private ISpouseService _peopleSvc;
public EmployeeController(
IEmployeeService empSvc, ISpouseService peopleSvc)
{
// D.I. hard at work! Auto-wiring up our services. :)
_empSvc = empSvc;
_peopleSvc = peopleSvc;
// setup all ViewModels here that the controller would use
Mapper.CreateMap<Employee, EmployeeViewModel>();
Mapper.CreateMap<Spouse, SpouseViewModel>();
}
public ActionResult Employee(int empNum)
{
// really should have some validation here that reaches into the domain
//
var employeeViewModel =
Mapper.Map<Employee, EmployeeViewModel>(
_empSvc.FetchEmployee(empNum)
);
var spouseViewModel =
Mapper.Map<Spouses, SpousesViewModel>(
_peopleSvc.FetchSpouseByEmployeeID(empNum)
);
employeeViewModel.SpouseViewModel = spouseViewModel;
return View(employeeViewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Employee(int id, FormCollection values)
{
try
{
// always post to an ID, which is the employeeID
var employee = _empSvc.FetchEmployee(id);
// and bind using the built-in UpdateModel helpers.
// this will throw an exception if someone is posting something
// they shouldn't be posting. :)
UpdateModel(employee);
// save employee here
this.RedirectToAction(c => c.Index());
}
catch
{
// check your domain model for any errors.
// check for any other type of exception.
// fail back to the employee screen
RedirectToAction(c => c.Employee(id));
}
}
}
I generally try to stay away from saving multiple entities on a controller action. Instead, I would refactor the employee domain object to have AddSpouse() and SaveSpouse() methods, that would take an object of Spouse. This concept is known as AggregateRoots, controlling all dependancies from the root - which is the Employee() object. But, that is just me.
Currently I'm passing my domain objects to my views, and binding directly to them from POSTs. Everyone says this is bad, so I'm attempting to add in the ViewModel concept.
However, I can't find a way to do this very elegantly, and I'd like to know what other people's solutions are to not ending up with a very messy controller action.
the typical process for say some "add person" functionality looks like this:
make a GET request for a view representing a blank Person viewmodel
post back (in)valid data
controller binds posted data onto a person viewmodel
if binding fails, i need to do the same action as in (1) but with some data, not a blank object and errors
if the binding suceeded, i need to map the properties from the VM onto a real model
validate the model
if validation passed: save the person, commit, map the users details to a display VM and return it in a view
if validation failed, do the same actions as in (1) but with some data and errors
Doing all this in a controller action (ignoring the GET) certainly isnt SRP or DRY.
Im trying to think of a way of breaking this process up so that it does abide by SRP, is clean, modular and above all testable.
What are peoples solution to this?
I've been experimenting with custom controller-action-invokers to separate the concerns up into individual methods, smart modelbinders and just plain brute force but i havent yet come across a solution in happy with.
P.S. as it adds so much complexity, convince me why i even need to bother
I've felt the same discomfort. My only way around it has been to do the following:
Create a binder to bind and validate the view model
Create a binder to get the entity from the database (or just do this in the controller)
Call an inherited Save method in the superclass. This method takes the viewmodel and the entity that will be updated, and does all the work you listed in your steps.
The action method looks like this:
public ActionResult Whatever(TViewModel viewModel, TEntity entity)
{
return Save(viewModel, entity);
}
The base controller has a generic definition, like so:
public abstract BaseController<TEntity, TViewModel>
where TEntity : Entity
where TViewModel : ViewModel
The constructor has two dependencies, one for the entity repository and another for the model mapper, like so:
protected BaseController(IRepository<TEntity> repository, IMapper<TEntity, TViewModel> mapper)
With this in place, you can then write a protected Save method that can be called from the controller actions in the subclass, like so:
protected ActionResult Save(TViewModel viewModel, TEntity entity)
{
if (!ModelState.IsValid)
return View(viewModel);
_mapper.Map(viewModel, entity);
if (!entity.IsValid)
{
// add errors to model state
return View(viewModel);
}
try
{
_repository.Save(entity);
// either redirect with static url or add virtual method for defining redirect in subclass.
}
catch (Exception)
{
// do something here with the exception
return View(viewModel);
}
}
As far as testability, you can test the save method passing in valid/invalid view models and entities. You can test the implementation of the model mapper, the valid state of the view model, and the valid state of the entity separately.
By making the base controller generic, you can repeat this pattern for each entity/viewmodel combo in your domain, if you're creating many controllers to do the same thing.
I'm very interested to hear what others have to say about this. Great question.
The MVVM (ViewModel) pattern is definitely the one to go for, I had a similar question about POSTing back to an action a few days back - here is the link: MVVM and ModelBinders in the ASP.NET MVC Framework
The result was that you can use the Bind attribute to post back the complex type you want.
I have many good solutions in the asp.net mvc sample application which is in the download of valueinjecter (mapper that I use to map ViewModels to/from Entities, you can also map FormCollection/Request to Entities)
here's one:
public class TinyController :Controller
{
private readonly IModelBuilder<Person, PersonViewModel> modelBuilder;
public TinyController()
{
modelBuilder = new PersonModelBuilder();
}
public ActionResult Index()
{
return View(modelBuilder.BuildModel(new PersonRepository().Get()));
}
[HttpPost]
public ActionResult Index(PersonViewModel model)
{
if (!ModelState.IsValid)
return View(modelBuilder.RebuildModel(model));
var entity = modelBuilder.BuildEntity(model);
...
//save it or whatever
}
}