Localizing ViewModel in ASP.NET MVC4 with Resources - localization

First, I want to clarify that I'm currently using the ASP.NET MVC's Model entities as ViewModel because my project is based on MVCVM, so I'm not simply confusing the two.
Anyway MVC automatically creates me a few attributes for ViewModel entities like the following (from the wizard, localized in Italian)
public class LoginModel
{
[Required]
[Display(Name = "Nome utente")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Memorizza account")]
public bool RememberMe { get; set; }
}
Replacing the Display attribute with [Display(Name = LoginViewModelResources.lblUsername)] causes compilation error: "Argument must be a constant expression, typeof expression or matrix creation expression". In a few words, a property reference is a no-no.
The Razor view uses tags such as the following for generating HTML
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
How can I localize the ViewModel in order to display the correct messages at front-end?

Like this:
[Required]
[Display(Name = "lblUsername", ResourceType = typeof(LoginViewModelResources))]
public string UserName { get; set; }
For this to work you must define a LoginViewModelResources.resx file with Custom Tool=PublicResXFileCodeGenerator (you set this in the properties of the resource file) and containing a label lblUsername which will hold the localized resource.

Related

Should I have each ViewModel for each entity in my ASP MVC project?

I have read many by many solution but i can't understand deeply about what or when i use View Model?
For example, when i have a Register form for User to register, i want to hava an field Confirm Password, but i don't think should add it into the User entity. So i have this ViewModel:
public class RegisterViewModel
{
public User User { get; set; }
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> Ward { get; set; }
[Required(ErrorMessage = "Bạn chưa nhập lại mật khẩu.")]
[StringLength(100, ErrorMessage = "Mật khẩu phải có ít nhất {2} ký tự.", MinimumLength = 6)]
[DataType(DataType.Password)]
[System.Web.Mvc.Compare("User.Password", ErrorMessage = "Mật khẩu không khớp.")]
public string ConfimPass { get; set; }
}
So after read this link How to properly implement "Confirm Password" in ASP.NET MVC 3? . I don't know why they should replace the Password field which is already in User entity. I'm using unobstrusive client validation so it does work if i use this Model View. In my View, i must use m=> m.User.Username but not m=>m.Username, etc... Because of this, my validation such as compare password, or just remote validation not work well with the name in my View like m=>m.User.Username. What is wrong with my structure or my Model View in my thinking?
There is no single rule and you need to stay pragmatic, having said that ViewModel and a Model (or Domain Model) are 2 different things. No you don't pollute your entities by placing properties that don't belong to them. The idea is that your UI should be interchangeable and your domain should not in any way depend on it. The dependencies should be inverted. Maybe tomorrow you'd switch (or extend) your UI layer to WPF (for example) ? Where your current ViewModels (with their attributes) wouldn't make much sense.
In your case, yes you should be creating a view model and keep everything relevant to the view in them, after which you map/pass values back to your domain model.
I hope I'm making sense, let me know if you need clarifications.
In your case I'd probably create a flattened RegisterViewModel that would include only the information needed to register a user, for example:
public class RegisterViewModel
{
[Required]
public string DisplayName { get; set; }
[Required]
public string FirstName { get; set; }
// etc ...
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> Ward { get; set; }
[Required(ErrorMessage = "Bạn chưa nhập lại mật khẩu.")]
[StringLength(100, ErrorMessage = "Mật khẩu phải có ít nhất {2} ký tự.", MinimumLength = 6)]
[DataType(DataType.Password)]
[System.Web.Mvc.Compare("User.Password", ErrorMessage = "Mật khẩu không khớp.")]
public string ConfimPass { get; set; }
}

Required and not required fields from one common class

I'm using ASP.NET MVC3 and I have the following class:
public class AddressMetadata
{
public string State { get; set; }
public string City { get; set; }
public string Street { get; set; }
}
Also I have the following edit model:
[Display(Name = "First Address")]
public Address FirstAddress { get; set; }
[Display(Name = "Second Address")]
public Address SecondAddress { get; set; }
And I have to create all fields from FirstAddress as required, but the other ones from SecondAddress not.
How can I do that without creating new class for second address? I know that I can use [Required] directive in AddressMetadata class, but how can I divide those rules between FirstAddress and SecondAddress?
I guess something like this will work, not 100% sure, I've to try it myself. (I'm actually starting with EditorTemplates)
Add [Required] just to FirstAddress in the EditModel.
Add [Required] to all properties of the Adress class.
Write a TemplateEditor for Address class.
The TemplateEditor will have Address as its model and perform validation on that using Address class annotations, while the View will validate according to the EditModel annotations.
Please forgive me for my bad English.
EDIT: was forgetting about this: in the view render the EditorTemplate via
#Html.EditorFor (m => m.FirstAddress)

Strange issue with ASP.NET MVC3 client side validation

I am having an issue with ASP.NET MVC3 client side validation.
My view is based on a viewmodel I've created with the following fields as Required
public class AppointmentFeedbackViewModel_Validation
{
[Required]
public string AttendeeName { get; set; }
[Required(ErrorMessage = "Notes must be filled in")]
public string Notes { get; set; }
[Required(ErrorMessage = "Appointment status must be filled in")]
public int AppointmentStatusId { get; set; }
[Required]
public int StarId { get; set; }
}
Unfortunately, a completely unrelated field SubStatusId appears as required on submitting the form.
This drop down list is passed an empty List from the controller
new List<EF.ViewModels.OpportunityConnectTypeViewModel>();
and marked up as below
<div class="display-label-styled">
Please select another reason for this outcome
</div>
<div class="display-field-styled">
#Html.DropDownListFor(model => model.SubStatusId, new SelectList(ViewBag.SubStatus, "ID", "StatusName"))
#Html.ValidationMessageFor(model => model.SubStatusId)
</div>
If anybody can shed any light on this for me, I'd really appreciate it.
Is SubStatusId an int? Int's are implicitly required. If you want it to not be required, declare it as a nullable int:
public int? SubStatusId;

Model does not apply DataType.Password

Instead of using the object directly, on a simple Razor View I have a form using as it+s model a decorator object.
public class GlobalAccount
{
public GlobalAccount()
{
this.TestService = new TestServiceModel();
}
public TestServiceModel TestService { get; set; }
}
beeing TestServiceModel represented as
public class TestServiceModel
{
[Required]
[Display(Name = "Endpoint (url of your service like http://mydomain/remote/)")]
public string Endpoint { get; set; }
[Required]
[Display(Name = "System username")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "System password")]
public string Password { get; set; }
}
Note the Password property decorated with DataType.Password
and in a Partial Razor view I have a call to that object
#model OnlineServices.Administration.Models.GlobalAccount
...
#Html.TextBoxFor(model => model.TestService.Password, new { size = "30" })
problem is that, in the html I get type="text" instead of text="password"
You can see in this image the entire flow:
What am I missing here?
You should use Html.Password, or even better use Html.EditorFor which will read the DataType.Password and output a password type input for you.
The Html.TextBoxFor is just text based input, not as password based one.
Further to Kieron's answer, in MVC3 it is actually NOT better to use Html.EditorFor for the Password inputs, as for some reason, if the server returns the page (say the username password combo is incorrect) then with EditorFor, the password is transmitted back to the page (and a view source the password is visible)
When using the Html.PasswordFor the password is not transmitted back to the client.

How do I get Timestamp properties to be rendered when I use EditorForModel()?

I have the following domain entity decorated with System.ComponentModel.DataAnnotations:
[HiddenInput(DisplayValue=false)]
public int Id { get; set; }
[Required]
[Display(Name="Last Name")]
public string LastName { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Timestamp]
[HiddenInput(DisplayValue=true)]
[ScaffoldColumn(true)]
public byte[] Version { get; set; }
When I render my model in the view using #Html.EditorForModel() nothing is rendered for the version property. Is there anything that can force EditorForModel() method to render the byte[]?
PS: Using #Html.EditorFor(x => x.Version) works just fine.
You could also create an EditorTemplate named Version and design the output how you see fit. add a UIHint attribute to version in order to use it.
A byte[] is considered to be a complex type by the EditorForModel method and there currently is no way for those to be displayed. You could try adding another property to your model (typed as string for example) that would read from and write to your Version property.
Better write your own template (Object.ascx).
Copy the standard MVC Object.ascx template and change the ShouldShow Method to:
public static bool ShouldShow(ModelMetadata metadata, ViewDataDictionary viewData) {
return metadata.ShowForDisplay
&& metadata.ModelType != typeof(System.Data.EntityState)
&& (!metadata.IsComplexType || metadata.ModelType == typeof(System.Byte[]))
&& !viewData.TemplateInfo.Visited(metadata);
}

Resources