What is the proper way of using DTOs in this case? - asp.net-mvc

I have the following domain class:
public class Product
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Product> RelatedProducts { get; set; }
}
I have the following DTO class:
public class ProductDTO
{
public ProductDTO(Product product)
{
Id = product.Id;
Name = product.Name;
}
public Guid Id { get; private set; }
public string Name { get; private set; }
}
I have the following method in my service:
public ProductDTO GetBySlug(string slug)
{
Product product = productRepository.GetBySlug(slug);
return (product != null) ? new ProductDTO(product) : null;
}
I have the following action in my controller:
public ActionResult Details(string slug)
{
ProductDTO viewModel = productService.GetBySlug(slug);
return View("Details", viewModel);
}
After reading around a bit is my understanding that using a DTO as a viewmodel is ok as the current scenario is simple and straight forward. My confusion occurs when the data that I want to return gets a bit more complex. Let's assume that I also want to return the list of related products to the view as well. Where would I add this list?
I read that a DTO is a flattened version of your domain entity that is used to transfer data. Does that mean that a generic list containing the related products should not be allowed inside the DTO? The answer I received so far suggests so. How do I then get the related products to the controller?
One option is:
Instead of returning the ProductDTO in the service I would create a new class that holds ProductDTO and the List of type ProductDTO for the related products and return it from the service. In the controller I would then either pass the new class to the view or create a separate ProductViewModel that holds ProductDTO and the List of type ProductDTO for the related products, populate it and pass that to the view.
Is this a good or a bad idea? Why?
Thanks

I wouldn't place the list inside the DTO at all, because it does not naturally belong there. And I am also not sure what you mean with 'wrapper class'. All you need is a list of products, and it is perfectly OK to have another method on the service which returns this list.
Consequently, you would have something like this in your service:
public IList<ProductDTO> GetRelatedProducts(ProductDTO productDTO)
{
...
The most important idea behind a viewmodel (the thing that is called service above) is that it mediates between the UI and the business model. In other words: It orchestrates and aggregates the business model in a way that is relevant to the UI. And if the UI wants a list of related products at some point, then the service has to deliver it. It's really as simple as this, and it is completely irrelevant here whether the business model itself also has this concept.
HTH!
Thomas
P.S.
If your DTOs get larger and your lists longer, you might consider to introduce another (simplified) DTO with only the name and some sort of identifier to reduce the amount of unnecessary data you have to retrieve from the repository.

Related

With MVC/Entity Framework, how does one manage housekeeping tasks in the view?

My understanding is that only one model can be passed to the view at a time. The problem with this that I see is that I am being forced to pass the Entity Framework model, and not any model that will manage housekeeping in the view. Here is what I mean:
You need to make a page that allows someone to submit Cars to the database. Along with the form fields (e.g. CarName, CarMake, CarYear) you also need a checkbox at the bottom of the page called "Remember Values" which when checked will "remember" the form values when the user clicks the Submit button at the bottom, so when they return all of their form data is still in the form fields. Needless to say, this Remember Values variable is not part of the Entity Framework model- it is just a housekeeping variable for use in the view.
How would you guys handle adding this checkbox? It feels like it should be part of the model, but I can't send two models to the view. Am I just looking at this issue wrong? What would you recommend?
.NET 4.5/MVC 5/EntityFramework 6
This is a good situation to be using ViewModels.
Build your ViewModels with all properties that you'd want to send/retrieve to/from your view. For example:
EF Entity
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
}
View Model
public class AddCarViewModel {
public Car Car { get; set; }
public bool RememberValues { get; set; }
}
Controller
public class CarController : Controller {
// Constructor....
public ActionResult Add() {
var vm = new AddCarViewModel();
return View(vm);
}
[HttpPost]
public ActionResult Add(AddCarViewModel vm) {
if (ModelState.IsValid) {
_carService.Save(vm.Car);
}
return View(vm);
}
}
Another good approach is to create Domain Transfer Objects, which are POCO classes to hold data that is transferred through the pipes. For example, in your business layer you may want to audit any changes to your Car model. So you may have properties like CreatedBy, CreatedDate, UpdatedBy, UpdatedDate, etc. (These properties are generally never displayed to the end-user but are important to store).
So you'd create the following classes:
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User UpdatedBy { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime UpdatedDate { get; set; }
}
public class CarDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
public string Year { get; set; }
}
and you can use a library such as AutoMapper to map properties from Car -> CarDTO:
var car = _carService.GetCarById(id);
var carDTO = Mapper.Map<Car, CarDTO>(car);
This way, you can choose which properties you want exposed to your views by utilizing DTO's.
I always create an additional model that I can convert to and from between the EF model.
This additional model gets passed to the View and holds al the neccesary properties like CarName, Carmake, CarYear, Remember and probably most importantly, the Id of that particular object.
So when the user submits, this model gets passed to the Post method where you can extract all the required properties. You fetch the database model using the Id from your DbContext and update the properties with the values that were just passed through.
Technically you can send two models to the view, if the model is actually something like a Tuple:
#model Tuple<SomeEFModel, SomeViewModel>
Though that's kind of ugly. And if you're creating a view model anyway you might as well just make it a composite of the Entity Framework model. Something like:
public class SomeViewModel
{
public SomeEFModel EFModel { get; set; }
public string SomeOtherProperty { get; set; }
// other stuff...
}
Then just build an instance of that in the controller and send it to the model:
#model SomeViewModel
You could even just de-couple the EF model and the view model entirely, creating a custom view model that has everything for that view and then translating to/from that and the EF model at the controller level. Ultimately it comes down to what implementation looks cleaner and is easier to maintain, which can differ from one context to another.
Edit: Another option, if the models get unwieldy for whatever bits of the framework you're relying on, could be to separate your outgoing and incoming models. For pushing data to the view, you can use the composite view model above. But then when the data comes back from the view just use a normal Entity Framework model and a couple of additional parameters for your additional fields:
public ActionResult Edit(int id)
{
// build the view model with the EF model as a property
return View(someViewModel);
}
[HttpPost]
public ActionResult Edit(SomeEFModel model, string someOtherProperty)
{
// here you have an EF model from the view like normal
// plus the additional property (however many you need)
// you can even create a separate view model to collect the other properties
// as long as the names are well defined, the model binder should build both
}
First, you absolutely should NOT be passing your EF models directly to your view, and you should certainly NOT be posting directly to your EF models. This is essentially taking untrusted, unsanitized input and directly writing it to your data model with only bare minimal validation.
While this may work with simple models with no security or other ramifications, imagine a situation where you allowed a user to edit his profile information. Further, imagine that in his profile you also stored information relating to his subscription information. A specially crafted submit could alter his subscription information and give himself free access to your site, or worse...
Instead, you use view models. Apart from the security aspects, view models are good because other than in very simple CRUD style sites, your views requirements are typically different from your data models requirements. For instance, a particular field might be nullable in your data model, but you might want to make it required in your view. If you pass your model directly, then you can't do that easily.
Finally, Aggregate view models aggregate many different submodels to provide an overall model for the view, which is what you are getting at. You would then use a service layer, repository, or business logic layer to translate your view model to your data model, massaging data or applying logic as needed.

Using an MVC Model as a filter in the repository

I have a details view that is typed to IEnumerable. The view with a bunch of drop downs that let you add filters to the list of records rendered.
All these dropdowns correspond to properties on the MVC model:
public class Record
{
public string CustomerNumber { get; set; }
public string CustomerName { get; set; }
public string LineOfBusiness{ get; set; }
public DateTime? Date { get; set; }
}
Now, I'm using my model as my dto to shuffle data between my controller and my repo. Since all my drop down filters represent the model properties, I pass my model to a repo retrieval method, check its properties and filter based on its values? In other words:
public IEnumerable<TradeSpendRecord> Get(TradeSpendRecord record)
{
IQueryable<tblTradeSpend> query = _context.tblRecords;
if (!String.IsNullOrEmpty(record.CustomerName))
query = query.Where(x => x.CustomerNumber == record.CustomerNumber);
if (!String.IsNullOrEmpty(record.LineOfBusiness))
query = query.Where(r => r.LOB == record.LineOfBusiness);
SNIP
Hope this isn't too subjective, but I'm wondering if anyone has any input about whether this is a good/bad practice. I haven't seen a whole lot of examples of dynamic filtering like I need to do, and am looking for some guidance.
Thanks,
Chris
If you're doing what I think you're doing, I'm not sure this is the best way of doing it.
Keep your 'Models' in your MVC/presentation layer (whether this is one physical assembly or not) dedicated to your presentation layer. The only things that should be touching them are your Views and your Controllers. You don't want what should be independent entities to be so tightly coupled to your View Models.
I'd suggest creating a separate TradeSpendFilter class, which, at its simplest, exposes the filterable properties of your domain entity (likely more than any given View Model). You'd then pass this into your "filtering service" or whatever it may be. This also means you can extend your filtering functionality independent of both your domain models and your MVC app. For example, if you suddenly want to filter multiple objects, you can simply change...
public class TradeSpendFilter
{
public string CustomerName { get; set; }
...
}
...to...
public class TradeSpendFilter
{
public IEnumerable<string> CustomerNames { get; set; }
...
}
... without causing all sorts of problems for your MVC app.
Additionally, it will also mean you can make use of your filtering functionality elsewhere, without tying further components to your MVC app and ending up in a bootstrapped mess.

Repository and ViewModel in asp.net mvc 3

Here is the situation I am struggling with.
I have an Object Model:
public class MyModel
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
//etc
}
Then I have Object ModelView
public class MyModelView
{
public MyModel MyModelObject;
public SelectList PropToBeSelected1 {get; set;}
public SelectList PropTobeSelected2 {get; set;}
//etc
}
I have the MyModelRepository class as well that does the delete, update operations for MyModel.
All good and clear so far.
Question:
PropToBeSelected1 and PropTobeSelected2 are drop down lists whose contents come from the database. Should the methods retrieving these contents be put in my MyModelRepository? Or should I create another repository for ViewModel?
Thank you.
First you really don't want domian-ish objects in your viewModel. Your viewModel should be clean with only primitives (like strings, ints... etc). So I'd suggest using a AutoMapper to map your two string props to your viewModel.
With the select list, there are many ways to go about this but I can imagine if they are lists of properties then they are not actual entities, but value objects instead. In this case creating a repository for them is over kill and boarders bad design.
I'd put the 'get' of the property lists in your MyModelRepository. Something like
_myModelRepository.getProperties1For(myModel);
Then AutoMap again on to get your select list.
Edit:
Like #M.Radwan pointed out for complex domain models I'll make viewModels insdie viewModels for easy of mapping.
Domain Model--
public class User : Entity
{
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string Zip { get; set; }
}
would map to
public class DetailsViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public AddressViewModel Address { get; set; }
public class AddressViewModel
{
public string Street { get; set; }
public string Zip { get; set; }
}
}
which in our experience has been the only reason to add any complexity to your viewModel. We will put SelectLists in our viewModel though but lately we've been using IEnumerables of inner viewModels and calling custom EditorFor or DisplayFor to turn them into a dropdown / list of checkboxes / radio buttons.
The answer is NO, you should not make any repository for them if you really need them with this view. so they probably are value objects as #jasonhooten said and they should connected to the main aggregate object that used by the repository
Finally I don't decide the ViewModel structure until I finish the view and make it working first and this why I founder and create DevMagicFake, by using DevMagicFake you will delay all decisions of the design regarding the structure of the ViewModel or the repository or how you will use service layer, all this will be delayed after full complete your view and make it working first as BDD (Behavior Driven Development) and TDD (Test Driven Development) so you can take the right decisions of the design and the object model itself
So I just create the action method as the following
public ActionResult List(MyModelView myModelView)
{
FakeRepository<MyModelView> repository = new FakeRepository<MyModelView>();
repository.Add(myModelView);
}
This fake repository will enable me to save and retrieve my whole model even it's a complex model until I finish and complete the whole view and make it working first, and then I start thanking on how the real design and the real repository should looks like, and do on
For more information about DevMagicFake and this approach see this link
DevMagicFake on CodePlex

Mapping Validation Attributes From Domain Entity to DTO

I have a standard Domain Layer entity:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set;}
}
which has some kind of validation attributes applied:
public class Product
{
public int Id { get; set; }
[NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
public string Name { get; set; }
[NotLessThan0]
public decimal Price { get; set;}
}
As you can see, I have made up these attributes completely. Which validation framework (NHibernate Validator, DataAnnotations, ValidationApplicationBlock, Castle Validator, etc) in use here is not important.
In my client layer, I also have a standard setup where I don't use the Domain entities themselves, but instead map them to ViewModels (aka DTO) which my view layer uses:
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set;}
}
Let's then say that I want my client/view to be able to perform some basic property-level validations.
The only way I see I can do this is to repeat the validation definitions in the ViewModel object:
public class ProductViewModel
{
public int Id { get; set; }
// validation attributes copied from Domain entity
[NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
public string Name { get; set; }
// validation attributes copied from Domain entity
[NotLessThan0]
public decimal Price { get; set;}
}
This is clearly not satisfactory, as I have now repeated business logic (property-level validation) in the ViewModel (DTO) layer.
So what can be done?
Assuming that I use an automation tool like AutoMapper to map my Domain entities to my ViewModel DTOs, wouldn't it also be cool to somehow transfer the validation logic for the mapped properties to the ViewModel as well?
The questions are:
1) Is this a good idea?
2) If so, can it be done? If not, what are the alternatives, if any?
Thank you in advance for any input!
If you're using something supporting DataAnnotations, you should be able to use a metadata class to contain your validation attributes:
public class ProductMetadata
{
[NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
public string Name { get; set; }
[NotLessThan0]
public decimal Price { get; set;}
}
and add it in the MetadataTypeAttribute on both the domain entity & DTO:
[MetadataType(typeof(ProductMetadata))]
public class Product
and
[MetadataType(typeof(ProductMetadata))]
public class ProductViewModel
This won't work out of the box with all validators - you may need to extend your validation framework of choice to implement a similar approach.
The purpose of validation is to ensure that data coming into your application meets certain criteria, with that in mind, the only place it makes sense to validate property constraints, like those you have identified here, is at the point where you accept data from an untrusted source ( i.e. the user ).
You can use something like the "money pattern" to elevate validation into your domain type system and use these domain types in the view model where it makes sense. If you have more complex validation (i.e. you are expressing business rules that require greater knowledge than that expressed in a single property), these belong in methods on the domain model that apply the changes.
In short, put data validation attributes on your view models and leave them off your domain models.
Why not use an interface to express your intent? Eg:
public interface IProductValidationAttributes {
[NotEmpty, NotShorterThan10Characters, NotLongerThan100Characters]
string Name { get; set; }
[NotLessThan0]
decimal Price { get; set;}
}
It turns out that AutoMapper may be able to do this for us automagically, which is the best case scenario.
AutoMapper-users: Transfer validation attributes to the viewmodel?
http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&q=validation#db4e7f6c93a77302
I haven't got around to trying out the proposed solutions there, but intend to shortly.
If you use hand-written domain entities, why not put your domain entities in their own assembly and use that same assembly both on the client and server. You can reuse the same validations.
I've been considering this as well for a while now. I totally understand Brad's reply. However, let's assume I want to use another validation framework that is suitable for annotating both domain entities and view models.
The only solution I can come up with on paper that still works with attributes would be to create another attribute that "points" to a domain entity's property that you are mirroring in your view model. Here's an example:
// In UI as a view model.
public class UserRegistration {
[ValidationDependency<Person>(x => x.FirstName)]
public string FirstName { get; set; }
[ValidationDependency<Person>(x => x.LastName)]
public string LastName { get; set; }
[ValidationDependency<Membership>(x => x.Username)]
public string Username { get; set; }
[ValidationDependency<Membership>(x => x.Password)]
public string Password { get; set; }
}
A framework like xVal could possibly be extended to handle this new attribute and run the validation attributes on the dependency class' property, but with your view model's property value. I just haven't had time to flesh this out more.
Any thoughts?
First of all, there is no notion of "standard" domain entity. For me, standard domain entity does not have any setters to begin with. If you take that approach, you can have more meaningful api, that actually conveys something about your domain. So, you can have application service that processes your DTO, creates commands that you can execute directly against you domain objects, like SetContactInfo, ChangePrice etc. Each one of these can raise ValidationException, which in turn you can collect in your service and present to the user. You can still leave your attributes on the properties of dto for simple attribute/property level validation. For anything else, consult your domain. And even if this is CRUD application, i would avoid exposing my domain entities to presentation layer.
Disclaimer: I know this is an old discussion, but it was closest to what I was looking for: Keeping DRY by reusing validation attributes. I hope it is not too far from the original question.
In my situation I wanted to make error messages availible in .NET views and in other viewmodels. Our entities have little to no business logic and are mainly targeted for data storage. Instead we have a large viewmodel with validation and business logic were I want to reuse error messages. Since the users are only conserned with error messages, I find this to be relevant as that is what is important to maintain easily.
I could not find a feasible way to remove logic from the partial ViewModels, but I found a way to convey the same ErrorMessage, such that it can be maintained from a single point. Since ErrorMessages are tied to the view, it can just as well be part of the ViewModel. Consts are considered static members, so defining the error messages as public string constants, we can access them outside the class.
public class LargeViewModel
{
public const string TopicIdsErrorMessage = "My error message";
[Required(ErrorMessage = TopicIdsErrorMessage)]
[MinimumCount(1, ErrorMessage = TopicIdsErrorMessage)]
[WithValidIndex(ErrorMessage = TopicIdsErrorMessage)]
public List<int> TopicIds { get; set; }
}
public class PartialViewModel
{
[Required(ErrorMessage = LargeViewModel.TopicIdsErrorMessage]
public List<int> TopicIds { get; set; }
}
In our project we were using custom html for dropdownlists, such that we could not use #Html.EditorFor helper in razor, thus we could not use unobtrusive validation. With the error message availible we could now apply the necessary attributes:
#(Html.Kendo().DropDownList()
.Name("TopicIds")
.HtmlAttributes(new {
#class = "form-control",
data_val = "true",
data_val_required = SupervisionViewModel.TopicIdsErrorMessage
})
)
Warning: You might need to recompile all related projects that rely on const values...

ASP.NET MVC / DDD architecture help

I am creating a Web application using ASP.NET MVC, and I'm trying to use domain-driven design. I have an architecture question.
I have a WebControl table to store keys and values for lists so they can be editable. I've incorporated this into my business model, but it is resulting in a lot of redundant code and I'm not sure it belongs there. For example, in my Request class I have a property called NeedType. Because this comes from a list, I created a NeedType class to provide the values for the radio buttons. I'm showing just one example here, but the form is going to have probably a dozen or so lists that need to come from the database.
[edit, to clarify question] What's a better way to do this? Are these list objects really part of my domain or do they exist only for the UI? If not part of the domain, then they don't belong in my Core project, so where do they go?
public class Request : DomainObject
{
public virtual int RequestId { get; set; }
public virtual DateTime SubmissionDate { get; set; }
public virtual string NeedType { get; set; }
public virtual string NeedDescription { get; set; }
// etc.
}
public class NeedType : DomainObject
{
public virtual int NeedTypeId { get; set; }
public virtual string NeedTypeCode { get; set; }
public virtual string NeedTypeName { get; set; }
public virtual int DisplayOrder { get; set; }
public virtual bool Active { get; set; }
}
public class RequestController : Controller
{
private readonly IRequestRepository repository;
public RequestController()
{
repository = new RequestRepository(new HybridSessionBuilder());
}
public RequestController(IRequestRepository repository)
{
this.repository = repository;
}
public ViewResult Index(RequestForm form)
{
ViewData.Add("NeedTypes", GetNeedTypes());
if (form == null)
{
form = new RequestForm();
form.BindTo(repository.GetById(125));
}
}
private NeedType[] GetNeedTypes()
{
INeedTypeRepository repo = new NeedTypeRepository(new HybridSessionBuilder());
return repo.GetAll();
}
}
Create a seperate viewmodel with the data you need in your view. The Model in the M of MVC is not the same as the domainmodel. MVC viewmodels are dumb DTO's without behaviour, properties only. A domain model has as much behaviour as possible. A domain model with get;set; properties only is considered an anti-pattern called "anemic domain model". There are 2 places where most people put the viewmodels: in the web layer, close to the views and controllers, or in a application service layer.
Edit:
When you only need to display a list of all needtypes in the database and one request in your view, I would indeed create one viewmodel with the request and the list of needtypes as properties. I don't think a call to multiple repositories in a controller is a smell, unless you have a larger application and you might want a seperate application service layer that returns the whole viewmodel with one method call.
I think it might also be a good idea to follow the advise of Todd Smith about value object.
When the needtypes can be added or edited by users at runtime, needtype should be an entity. When the needtypes are hardcoded and only changed with new releases of the project, needtype should be a value object and the list of needtypes could be populated by something like NeedType.GetAll() and stored in the database by adding a column to the request table instead of a seperate needtype table.
If it comes from a list, then I'm betting this is a foreign key. Don't think about your UI at all when designing your domain model. This is simply a case where NeedType is a foreign key. Replace the string NeedType with a reference to an actual NeedType object. In your database, this would be a reference to an id.
When you're building your list of NeedType choices, you simply need to pull every NeedType. Perhaps keeping it cached would be a good idea if it doesn't change much.
Your NeedType looks like a value object to me. If it's read-only data then it should be treated as a value object in a DDD architecture and are part of your domain.
A lot of people run into the "omg so much redundancy" issue when dealing with DDD since you're no longer using the old Database -> DataTable -> UI approach.

Resources