Domain Model Object to View Model Object in MVC - c#

I want to use view model for displaying instead of domain model. I have got these view models classes:
public class ArticleDescriptionViewModel
{
public string Title { get; set; }
public DateTime DateCreated { get; set; }
}
public class HomePage
{
public List<ArticleDescriptionViewModel> Articles { get; set; }
}
In the domain model i have got:
public class ArticleDescription
{
public string Title { get; set; }
public DateTime DateCreated { get; set; }
}
And this service method:
public List<ArticleDescription> GetArticlesDescription()
{
var articleDescription= from a in _ctx.Articles
select new ArticleDescription
{ Title = a.Title, DateCreated = a.DateCreated };
return articleDescription.ToList();
}
in the controller i want to match my list inside of my view model class with the list returned by my domain model class.
public ActionResult Index()
{
HomePage HomePageInstance = new HomePage();
HomePageInstance.Articles = _repo.GetArticlesDescription();
return View(HomePageInstance);
}
I have got an error:
"Cannot implicitly convert type System.Collections.Generic.List (DBayonaCode.Domain.Services.Models.ArticleDescription)' to 'System.Collections.Generic.List(DBayonaCode.Models.ArticleDescriptionViewModel)'"
But these two classes are equivalent? I am doing something wrong. I appreciate your help?

ArticleDescription and ArticleDescriptionViewModel are two different types, so there's no implicit conversion between them. You need to map your Domain Model object to your View Model object, you can do that either manually or with a tool like AutoMapper.
You could write extension methods like these to do the mapping:
public static class Mappings
{
public static ArticleDescriptionViewModel ConvertToView(this ArticleDescription article)
{
// Mapping Code
// return new ArticleDescriptionViewModel { ... }
}
public static List<ArticleDescriptionViewModel> ConvertToViews(this List<ArticleDescription> articles)
{
List<ArticleDescriptionViewModel> articleViews = new List<ArticleDescriptionViewModel>();
foreach (ArticleDescription article in articles)
{
articleViews.Add(article.ConvertToView())
}
return articleViews;
}
}

While MVC default project template offer just one model folder, thus implicitly presenting the idea that models are one thing, in fact There are three types of data models potentially involved in an ASP.NET MVC application:
- Domain model objects will be passed from and to a middle tier services interfacing with databases.
- View Model objects are those that the Controller pass to the View.
- Input model objects are those that the default modelBinder or some custom modelBinder generates from the view, although in many cases the input models are the same view model objects.
Hope it helps.

Related

MVC - Nested models with interfaces and annotations

I have basic class:
public abstract class AbstractBaseModel : IModel
{
[Display(Name = "Some Name")]
[DisplayFormat(DataFormatString = "{0:d0}")]
[RegularExpression(#"[0-9]{1,10}", ErrorMessage = "error")]
public virtual string SomeName{ get; set; }
}
The IModel interface is just simple declaration of properties:
public interface IModel
{
string SomeName{ get; set; }
}
From the base model I have 2 derived models
public class ClientModel : AbstractBaseModel
{
[Required(ErrorMessage = "Some error message for customer only")]
public override string SomeName{ get; set; }
}
public class PowerUserModel : AbstractBaseModel
{
[Required(ErrorMessage = "Different message for the admin")]
public override string SomeName{ get; set; }
}
This model, or rather interface is part of another model that combines multiple models:
public class ComboEndModel
{
public IModel Model { get; set; }
public IDifferentModel DifferentModel { get; set; }
}
Depending on the View/Controler that is currently used, I pass new ClientModel or PowerUserModel as a Model in ComboEndModel
When the view is rendered, I'm only getting the annotations from the base, abstract model, not the ones added in the derivative type. I suspect that's because I'm using interface as a nested model property instead of type.
Whats the correct way of implementing this relation, or working around the issue with incorrect annotations? Should I try with custom binding?
One thing that might work for you would be to create editor templates for each derived model.
If you define your ComboEndModel like this
var model = new ComboEndModel() { Model = new PowerUserModel() };
return View(model);
and in your view you use EditorFor
#model WebApplication.Models.ComboEndModel
#Html.EditorFor(m => m.Model)
depending on what Type Model is, it will pick the associated editor template and apply the annotations for that derived type. In this case you'd need a partial view in your EditorTemplates folder named PowerUserModel.cshtml with a model type of PowerUserModel
Ok I have some problems with that too, and what I understood so far is (someone correct me if I'm wrong):
Why this problem occurs?
Because the DataAnnotation that is retrieved are retrived from the type of the model. Let me show you some samples:
If you have in your .cshtml file:
Sample 1:
#model AbstractBaseModel
// The type that will be retrived is `AbstractBaseModel`.
Sample 2:
#model IModel
// The type that will be retrived is `IModel`.
Or in other case if you have actions:
public ActionResult SomeAction(AbstractBaseModel model) { /* ... */ }
Sample 2:
public ActionResult SomeAction(IModel model) { /* ... */ }
So what matters is what type you specified in #model or in the action parameter. Doesn't matter if is interface, abstract class, base class or other type of class, matter only the type you described in your use.
In your example specifically you wrote:
public class ComboEndModel
{
public IModel Model { get; set; }
// ...
}
So the DataAnnotation will be retrive from IModel, but IModel don't have a RequiredAttribute defined so you get one step further in the chain of inheritance/implementation and get AbstractBaseModel. (Try this to confirm what I'm writing: put a required in IModel.SomeName with a different message and see what message will get).
Solution/Suggestion
If I'm right, there is no solution for your problem without change the strategy. So here some suggestions about what you can do:
Remove Required attribute and do yourself the validation (in action or javascript, depending of how type of validation you're using).
Replace the error message after validation occurs, (I did this in my case).
Give up of this inheritance and make independent models.

Calling a constructor on custom view model changes output type to JSON

I'm developing a WebAPI service and have been confronted with a curious problem. When calling a ViewModel with a constructor why is the return type changed to JSON from XML?
Code from controller;
// GET api/Product/5
public MyViewModel GetProduct(Int64 id)
{
// without a constructor this returns an xml
//return new MyViewModel() { Name = "123" };
// this changes type to json
Product product = new Product();
return new MyViewModel(product) { Name = "123" };
}
View Model class;
[XmlRoot(ElementName = "ARequest", Namespace = "http://myschema.com/schemas/myviewmodel.xsd")]
public class MyViewModel : Product
{
public string Name { get; set; }
public MyViewModel(Product product)
{
// this constructor causes the type to switch from
// xml to json - why?
}
}
It seems that this is some weird behavior of the serializer. Add a default empty constructor to your model along with the other constructor:
public MyViewModel()
{
}
public MyViewModel(Product product)
{
}
But personally I would use a view model. A real one. Not some hybrid to which you are passing your domain model. Just have a simple POCO as view model. And a mapping layer that will map from the domain model.

Model inheritance - Repository Pattern with IoC

I am new to IoC and Repository Pattern. I was able to do some test project and it works. But, I am not so sure if what I implemented is a good practice. The test project I have created have all the repositories in place as well as a working interface with a dummy data. But what I want is that my project should not be able to know the concrete types of my models because the initial version should be implemented using MSSQL, and the second version would be a mix of MSSQL and NoSQL(for reads and logging). The models might have different properties or structures from MSSQL to NoSQL (or whatever i might use in the future)
So I tried to create an interface for each model:
public interface ISearchResult
{
string Id { get; set; }
string Name { get; set; }
string Description { get; set; }
string Url { get; set; }
}
And here's the repository:
public interface ISearchRepository<T> where T: class, ISearchResult
{
IEnumerable<T> Search<T>(string keyword, IEnumerable<string> regions, IEnumerable<string> industries,IEnumerable<string> countries, IEnumerable<string> cities, int offset);
}
And here's the service:
public interface ISearchService
{
IEnumerable<T> Search<T>(string keyword, IEnumerable<string> regions, IEnumerable<string> industries,IEnumerable<string> countries, IEnumerable<string> cities, int offset);
}
Because I want to have a working GUI even without MSSQL or NoSQL entities, I have created a View Model that inherited the ISearchResult:
public class SearchResultViewModel : ISearchResult
{
[Display(Name="Reference Id")]
public string Id { get; set; }
[Display(Name = "Company")]
public string Name { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Display(Name = "Website")]
public string Url { get; set; }
}
And here's how it looks on my controller:
[SearchQueryFilter]
[GeoTargetFilter]
public ActionResult Query(SearchQueryModel searchQuery)
{
searchQuery.Results = this._searchService.Search<SearchResultViewModel>(searchQuery.Keyword,searchQuery.Region, new List<string>() { searchQuery.Industries }, new List<string>() { searchQuery.Countries}, new List<string>() {searchQuery.City}, searchQuery.Offset)
.ToList<ISearchResult>();
return View(searchQuery);
}
And my view would look like this:
#foreach (SearchResultViewModel result in Model.Results)
{
//code to display
}
My question is: Is it fine to use this approach? I don't want my web application to be dependent on my data entities so that's why I came up of making my view models inherit an interface. And because I was new to IoC and Repository Pattern and only have a test project, I don't know if my solution would be more of a problem in the long run.
Any advise is highly appreciated.
You shouldn't need to implement an interface in your view model in order to create a separation between your web application and your data entities. Your view model should belong to your web application and should itself be independent of your data entity.
So, instead of:
_searchService.Search<SearchResultViewModel>(x);
You should have, in your controller:
var result = _searchService.Search<SomeEntity>(x);
var model = new SearchResultsViewModel
{
Name = result.Name,
Desc = result.Desc,
Url = result.Url
};
return View(model);
The view model belongs to the web application and is responsible for containing the data passed from controller to view (and back) - it should have nothing to do with your service layer (or any other layer of your application).
SomeEntity is a concrete class, in the form of whatever your search service exposes. Your controller will consume this in the same way as any other application would and then compile a view model for passing to and from views. You might even find that SomeEntity is more or less identical to SearchResultsViewModel initially; however, they are still distinct entities as the requirements of the view might change independently of the search service.

Passing DTO to my ViewModels constructor to map properties

In my solution I have two projects.
Project 1 (Core)
Mapping SQL to DTO using Dapper
Project 2 (WebUI - ASP.NET MVC 4)
Here I use a ViewModel per View.
Examples of a Controller
[HttpGet]
public ActionResult Edit(int id)
{
// Get my ProductDto in Core
var product = Using<ProductService>().Single(id);
var vm = new ProductFormModel(product);
return View(vm);
}
Examples of a ViewModel
public class ProductFormModel : BaseViewModel, ICreateProductCommand
{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
public string ArtNo { get; set; }
public bool IsDefault { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public string Unit { get; set; }
public string Account { get; set; }
public decimal NetPrice { get; set; }
public ProductFormModel(int productGroupId)
{
this.ProductGroupId = productGroupId;
}
public ProductFormModel(ProductDto dto)
{
this.ProductId = dto.ProductId;
this.ProductGroupId = dto.ProductGroupId;
this.ArtNo = dto.ArtNo;
this.IsDefault = dto.IsDefault;
this.Description = dto.Description;
this.Specification = dto.Specification;
this.Unit = dto.Unit;
this.Account = dto.Account;
this.NetPrice = dto.NetPrice;
}
public ProductFormModel()
{
}
}
Explanation:
I'll get my DTOs in my controller using a service class in the project (Core).
Then i create my ViewModel and pass the DTO to the constructor in ViewModel.
I can also use this view to add a new Product because my ViewModel can take a empty constructor.
Does anyone have experience of this. I wonder if I am in this way will have problems in the future as the project gets bigger?
I know this has nothing to do with Dapper. But I would still like a good way to explain my solution.
I think you will be fine using your current approach. More importantly, start out like this and refactor if you start to encounter problems related to your object mapping code (instead of thinking too much about it beforehand).
Another way to organize mapping logic that I use sometimes is to employ extension methods. That way, the mapping code is kept separate from the view model itself. Something like:
public static class ProductMappingExtensions
{
public static ProductFormModel ToViewModel(this ProductDto dto)
{
// Mapping code goes here
}
}
// Usage:
var viewModel = dto.ToViewModel();
Yet another approach would be to use a mapping framework like AutoMapper - this is a good fit in particular if your mapping logic is simple (lots of 1:1 mappings between properties).
But again, start simple and refactor when you need to.
I realize that this is a little bit late answer, but maybe it will help someone in the future.
This way of doing mapping between objects breaks the 'S' of the SOLID principles, because the responsibility of the ViewModel is to prepare data in its properties to be ready to use by the view and nothing else, therefore, mapping objects should not be on it's responsibilities.
Another drawback of this way is that it also breaks the 'Loose Coupling' OO principle as you ViewModel is strongly coupled with your DTO.
I think, even when we are in the very first step of the project, there are some importants OO principles that we should never break, so using mapper classes, either auto (AutoMapper, ValueInjecter ...) or manual, is definitely better.

Is it OK to have some logic codes inside a property of a data model class?

I am learning MVC 3 and I have not found people using some logic codes inside a property of a data model class.
They do the data model class as follows (for example):
public class Customer
{
public int CustomerId {get;set;}
//other properties without any logic code.
}
Is it ok to have logic codes inside a property as follows?
public class Customer
{
private int customerId;
public int CustomerId {
get{return customerId;}
set
{
customerId=value;
// some logic codes go here.
}
}
//other properties go here.
}
Edit 1:
This is my real scenario:
Child table data model:
namespace MvcApplication1.Models
{
public class Choice
{
public int ChoiceId { get; set; }
public string Description { get; set; }
public bool IsCorrect { get; set; }
public QuizItem QuizItem { get; set; }
}
}
Parent table data model:
namespace MvcApplication1.Models
{
public class QuizItem
{
public int QuizItemId { get; set; }
public string Question { get; set; }
private IEnumerable<Choice> choices;
public IEnumerable<Choice> Choices
{
get { return choices; }
set
{
choices = value;
foreach (var x in choices)
x.QuizItem = this;
}
}
}
}
Consumer:
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
var data = new List<QuizItem>{
new QuizItem
{
QuizItemId = 1,
Question = "What color is your hair?",
Choices = new Choice[]{
new Choice{ ChoiceId=1, Description="Black.", IsCorrect=true},
new Choice{ ChoiceId=2, Description="Red.", IsCorrect=false},
new Choice{ ChoiceId=3, Description="Yellow.", IsCorrect=false}
}
},
new QuizItem
{
QuizItemId = 2,
Question = "What color is your noze?",
Choices = new Choice[]{
new Choice{ChoiceId=1, Description="Pink.", IsCorrect=false},
new Choice{ChoiceId=2, Description="Maroon.", IsCorrect=true},
new Choice{ChoiceId=3, Description="Navy Blue.", IsCorrect=false}
}
}
};
return View(data);
}
}
}
This calls for a method. Two reasons why:
I don't recommend setters for Collections
Property Usage Guidelines - Setting a property for each item in collection every time property is set is expensive and should not be in a property. A method is preferred instead.
Code (that you have in your case) in setter causes enough side-effects to disqualify use of property
Setters for collection type properties - A discussion on StackOverflow regarding setters for collections.
I suggest following:
public class QuizItem
{
public int QuizItemId { get; set; }
public string Question { get; set; }
private IEnumerable<Choice> choices;
public IEnumerable<Choice> Choices
{
get { return choices; }
}
public void SetChoices(IEnumerable<Choice> choices)
{
foreach (var x in choices)
x.QuizItem = this;
this.choices = choices;
}
}
I think this logic you should implement in controller. However I always define POCO classes in my model and use ViewModel to implement such simple logic.
This is more of a realm of philosophical approach. As such it is up to a debate.
Today by far the most prevalent approach is to use strict layered approach of separation of concerns where "model" objects are only responsible for containing data and if you want to apply any sort of business logic on top of that, you need to implement that on a separate "business logic" layer, which handles application of such concerns as validation/vewrification of the integrity of data, mutation of data according to a business processes, etc.
Another approach is to use model layer to actually model (as in verb) the business of the target domain. In this case, the model acts as a direct definition of the business rules and should just as rich as rules of the business require it to be. (this approach has been taken to extreme by Naked Objects, that basically keeps data structures as well as business logic in the model and generates ORM, controller logic and views from the same model)
Generally the question of "how smart can/should be my model objects" is one to ask from the frameworks you use. Some frameworks simply don't care either way (ASP.NET MVC), others want you to never worry about coding this stuff, as long as you provide enough metadata so that they can do their job for you (NHibernate, Entity Framework). Others yet encourage you to express all your business rules and logic in the domain object model (e.g. Naked Objects)
In my opinion, a data model should be doing logic related to data (value) as in "is this value a valid data to...?". Also when doing hidden logic like in this case "attaching a parent", naming the method to just "set" is also wrong.
A sample of a more complex data model:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application

Categories