Bind attribute or ViewModel? - model-view-controller

I'm learning about the Bind attribute and I have a doubt.
I can use the Bind attribute to include/exclude the data that will be posted, so.
Would it not be better to use a specific ViewModel instead of the Bind attribute?

Think about what happened if your entity changes overtime, then you might force to change all your different viewModels which you have created instead of using Include or Exclude. it will get hard to maintain your code.
Suppose you have this :
public class PersonalViewModel
{
private int PersonalID { get; set; }
public string PersonalName { get; set; }
public string PersonalFamily { get; set; }
public byte? GenderID { get; set; }
public string PersonalPhone { get; set;}
}
Consider these :
public string ShowPersonalToAll(
[Bind(Exclude = "PersonalPhone")]PersonalViewModel newPersonal)
{...}
OR
public class PersonalViewModel
{
private int PersonalID { get; set; }
public string PersonalName { get; set; }
public string PersonalFamily { get; set; }
public byte? GenderID { get; set; }
}
Now What if saving personal's mobile become important! and if you have created different customized ViewModel for several action (depends on application's business)?
Then you have to change the main ViewModel and all the other Customize ViewModel, While by using Exclude there is no need to change ViewModels, no need to change actions and the main ViewModel just changes.

Related

Map two identical models, nested with automapper

I did some research but I couldn't find exactly what I wanted.
I have an endless menu. I have a MenuDTO and a MenuViewModel that I use for this menu. I had no problem matching between model and DTO, but am having trouble mapping DTO to ViewModel. Obviously I couldn't find the solution, can you help?
My MenuDTO Object
public class MenuDto : BaseDto
{
public string Name { get; set; }
public string Icon { get; set; }
public string Order { get; set; }
public string Url { get; set; }
public bool IsVisible { get; set; }
public int ParentId { get; set; }
public MenuDto ParentMenu { get; set; }
public List<MenuDto> Menus { get; set; }
}
And MenuViewModel
public class MenuViewModel
{
public int Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public string Order { get; set; }
public string Url { get; set; }
public bool IsVisible { get; set; }
public int ParentId { get; set; }
public MenuViewModel ParentMenu { get; set; }
public List<MenuViewModel> Menus { get; set; }
}
This is how I mapped the MenuDTO and MenuViewModel objects.
public class WebProfile : Profile
{
public WebProfile()
{
CreateMap<MenuDto, MenuViewModel>();
CreateMap<MenuViewModel, MenuDto>();
}
}
I call this way in the controller
var navMenuItems = _mapper.Map<List<MenuViewModel>(_menuService.GetNavMenus());
Although all fields are mapped, I get an error on the Menus field.
The error message I get is;
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
MenuDto -> MenuViewModel
BiPortal2020.Business.ServiceDTOs.Menu.MenuDto -> BiPortal2020.WebUI.Areas.Admin.Models.Menu.MenuViewModel
lambda_method(Closure , MenuDto , MenuViewModel , ResolutionContext )
AutoMapperMappingException: Error mapping types.
Mapping types:
Object -> List`1
System.Object -> System.Collections.Generic.List`1
The error message implies - AutoMapper, either cannot map between MenuDto and MenuViewModel, or it cannot locate the defined mappings.
I've tested your mappings and they are totally fine. So, what possibility remains is AutoMapper cannot locate your mappings.
I'm Assuming the Business Layer and UI Layer you mentioned in the comment section are two separate projects. Since the WebProfile is defined in the UI Layer, you have to tell AutoMapper that it should search that assembly to find the mappings. Since your mappings between Models and DTOs are working, I can guess you've already done the same for BusinessProfile which is defined in the Business Layer.
I don't know about your existing code, but you could do something like this - in the Startup.Configure method add/modify the following line -
services.AddAutoMapper(typeof(IDtoMapping), typeof(IViewModelMapping));
where IDtoMapping and IViewModelMapping are two marker interface (empty interface, used only to identify the assembly they are declared in) declared in the Business Layer and UI Layer, respectively.

How can I mark properties required to show up different in intellisense

Let's say we have a class like so:
public class Plan
{
public string PlanCode { get; set; } //Required
public string Name { get; private set; }
public string Description { get; set; }
public string SuccessUrl { get; set; }
}
Is there a way to make intellisense show required fields/properties different, such as italicized or a shade of red?
One would be able to determine what properties would be required quickly if calling a Create() method for instance.
Note: When I say show up different in intellisense I don't mean the tool-tip text that you see when the member is highlighted. I specifically mean the text of the member itself.
No, I don't believe you can. You should design your objects with required fields in mind, i.e. constructors.
So any fields that the object requires should be parameters in a constructor.
public class Plan
{
public string PlanCode { get; set; } //Required
public string Name { get; private set; }
public string Description { get; set; }
public string SuccessUrl { get; set; }
public Plan(string planCode)
{
PlanCode = planCode;
}
}
This is allows your code to clearly express its intention. Any developer using the Plan class will know that PlanCode is required, as it is enforced by the constructor.

scaffolding seems not to work properly

I created a new asp.net MVC3 application (internet application), and then I added a new model with 3 classes:
public class BizCard
{
[Required]
public string BizCardID { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public List<string> PhoneNumbers { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public BizType type { get; set; }
public List<BizService> OfferedServices { get; set; }
public string Description { get; set; }
}
public class BizType
{
public int BizTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Price { get; set; }
}
public class BizService
{
public int BizServiceID { get; set; }
public List<BizType> AllowedBizTypes { get; set; }
public string Name { get; set; }
}
After that, I created a new controller, using the template "Controller with read/write actions and views using entity framework", I set the Model class to be "BizCard" and the data context class to be a new class which is called "BizDB". I was expecting to get a new class named BizDB that inherits from DbContext and includes 3 instances of DbSet:
DbSet<BizCard>, DbSet<BizType>, DbSet<BizService>.
In spite of that, I get the class with only one:
DbSet<BizCard>.
Am I missing something?
You are doing this using EF Code First approach.
1. So, you have to create a context class which should inherit DbContext containing required models as DbSet
2. Build the solution. Otherwise it will not be displayed at controller creation
Then you can create the controller using necessary model and its dbcontext.

MVC3 same ViewModel used for two cases with Required attribute in only one case

I have a ViewModel. something like this
public class ViewModel
{
public int Id { get; set; }
public int? Value { get; set; }
}
I have a table of existing ViewModels, and below that I have a form where you can add a new ViewModel
For existing ViewModels that are fetched from DB i want no validation on the Value property, but for the case when adding a new ViewModel I want required validation.... The real model is more complex then this one so I want to use the same model in both cases.. Is it possible?
edit: this works
public class AddNewViewModel : ViewModel
{
public new int Value { get; set; }
}
Is it better to use new or virtual/override and why?
Required attributes are compiled into the class. You could do something like this:
public class BaseViewModel
{
public int Id { get; set; }
public virtual int? Value { get; set; }
}
public class CreateViewModel : BaseViewModel
{
[Required]
public override int? Value { get; set; }
}
This way, you only add the validation attribute to the properties where you need them.

asp.net mvc 3 entity framework, passing model info in Get request of create action

I'm having trouble passing view information from my Get/Create action to my view. Here are my three model classes;
public class Competition
{
public int Id { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Prize { get; set; }
}
public class CompetitionEntry
{
public int Id { get; set; }
public int CompetitionEntryId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int CompetitionId { get; set; }
}
public class CompetitionEntryViewModel
{
public int Id { get; set; }
public Competition Competitions { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Here is my Get/Create action in CompetitionEntry Controller;
public ActionResult Create(int id)
{
CompetitionEntryViewModel competitionentryviewmodel = db.CompetitionEntriesView.Find(id);
return View(competitionentryviewmodel);
}
I know this doesn't work. The id parameter goes into the URL fine. How to I get access to my Competition class in th Get action? I need to be able to show the competion name on my Create Competition entry view.
Thanks in advance!
public ActionResult Create(int id)
{
var data = db.CompetitionEntriesView.Find(id);
CompetitionEntryViewModel competitionentryviewmodel = new CompetitionEntryViewModel();
competitionentryviewmodel.CompetitionName = data.Name;
return View(competitionentryviewmodel);
}
What you are trying to do is build an object graph and display it through a view model. In order to do this, you need to map your domain model(s) to your view model.
You can do the mapping yourself by writing a lot of code (re-inventing the wheel), or, you could consider using third party tools to do this for you. I recommend you use an AutoMapper as it is very simple to use imo.
The other problem is that your view model contains a domain model. This is likely to cause you a lot of headache in near future. If I were you, I would replace Competition with CompetitionViewModel.
I would also consider creating a view model for a list of competitions, i.e. CompetitionsViewModel. Look into partial views to see how you can display a list of competitions.
Good luck

Resources