MVC Range Attribute not working properly - asp.net-mvc

I have a RangeAttribute that checks if the value of a data field is within a specified range of values here, that gives me a validation error even if I pick a date in between "01/01/2000", "01/01/2015":
[Range(typeof(DateTime), "01/01/2000", "01/01/2015")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
public Nullable<System.DateTime> Date { get; set; }
Here is my edit.cshtml code:
#model StringLength.Models.Employee
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Gender)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Gender)
#Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Date)
#Html.ValidationMessageFor(model => model.Date)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
For instance, if I pick 1.1.2014, I am NOT supposed to see any validation error.
Could anyone please help?
Thanks in advance!

First, DateTime structs weren't properly created from given strings. As your message in red states those strings were converted to 1.1.1910 and 1.1.2060 DateTimes. You should go with CustomValidation attribute.
Second, there might be a problem with converting 01.01.2014 to DateTime at server side. Bear in mind you might be using a specific culture that plays a role in conversions and bindings.

To fix this, we can create a custom DateRangeAttribute. Here are the steps
1. Right click on the project name in solution explorer, and add "Common" folder.
2. Right click on the "Common" folder and add a class file with name = DateRangeAttribute.cs
3. Copy and paste the following code in DateRangeAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class DateRangeAttribute : RangeAttribute
{
public DateRangeAttribute(string minimumValue)
: base(typeof(DateTime), minimumValue, DateTime.Now.ToShortDateString())
{
}
}
}
Finally decorate "HireDate" property with our custom DateRangeAttribute as shown below. Notice that, we are only passing the minimum date value. Maximum date value will be today's date. Please note, DateRangeAttribute is present in MVCDemo.Common namespace.
[DateRange("01/01/2000")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }

Related

Remote Validation working elsewhere

I have a user registration page where I implemented the remote validation concept for the Username. I basically want to keep each Username a unique value. I was able to achieve it, but now in the login page, when I type the username it prompts a message saying the Username is not available. This was meant just for the registration page and not the login page. Could someone please explain what is the mistake I am doing. I have a Model User which has a Username property; to which I am using the remote validation. I have an Action method called UserNameExsists which gets triggered for the remote validation. And the Registration view which utilities the validation. But the validation is being triggered for the login page as well. Is there a way I could set it up just for the Registration View?
Model:
public class User
{
public int ID { get; set; }
[Required]
[Remote("UserNameExists","User",ErrorMessage="Username not available")]
[Display(Name="User Name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[Display(Name="First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name="Last Name")]
public string LastName { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[MinLength(10)]
[MaxLength(10)]
[Display(Name="Mobile No")]
public string PhoneNum { get; set; }
}
Controller: (Name is User)
//Remote Validation
public JsonResult UserNameExists(string username)
{
bool user = db.Users.Any(p => p.UserName == username) ? false : true;
return Json(user,JsonRequestBehavior.AllowGet);
}
View:
Registration page view
#model HindiMovie.Models.User
#{
ViewBag.Title = "Register";
}
<link href="~/Content/Site.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<h2>Register</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNum)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNum)
#Html.ValidationMessageFor(model => model.PhoneNum)
</div>
<p>
<input type="submit" value="Register" />
<input type="reset" value="Clear" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Login page View:
#model HindiMovie.Models.User
#{
ViewBag.Title = "Login";
}
<h2>Login</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Sign in" />
</p>
</fieldset>
}
#Html.ValidationMessage("LogOnError")
<div>
#Html.ActionLink("Create account", "Register","User")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
You are using the same model for the Login and the Registration page, so you get the same validation on both pages.
Create a ViewModel for each view and put your validation attributes there.
That way you can differentiate between the validations for each page.

Cannot convert lambda expression to type 'string' because it is not a delegate type MVC

I know there is a lot of topics like this one, but I cant find the answer.
In code:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>TabelaModel</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Druzyna)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Druzyna)
#Html.ValidationMessageFor(model => model.Druzyna);
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LiczbaMeczy)
</div>
<div class="editor-field">
#Html.TextBox(model => model.LiczbaMeczy)
#Html.ValidationMessageFor(model => model.LiczbaMeczy)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LiczbaGoliStrzelonych)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LiczbaGoliStrzelonych)
#Html.ValidationMessageFor(model => model.LiczbaGoliStrzelonych)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Compiler is throwing an exception in line:
#Html.TextBox(model => model.LiczbaMeczy)
I have put a System.Linq, System.Data.Entity in model, in view, in controller, but still nothing. It's working when i replace #Html.TextBox into #Html.EditorFor, but i really would like to avoid this. My model class:
namespace GridViewTest.Models
{
public class TabelaModel
{
public int ID { get; set; }
public string Druzyna { get; set; }
[Required (ErrorMessage="*")]
public string LiczbaMeczy { get; set; }
[Required(ErrorMessage = "*")]
public int LiczbaGoliStrzelonych { get; set; }
}
}
Could You help me ?
You need to use TextBoxFor (not TextBox):
#Html.TextBoxFor(model => model.LiczbaMeczy)
That will take the lambda expression.

Override Default MVC Editor Templates Not Working

I've been unable to get default editor templates to work in my MVC 4 Razor web application. I've been unable to find any clues. I want to override String, Password, etc. I've tried UIHints in my model (even though you shouldn't have to for default editor templates), ensured I'm using EditorFor in my view and have placed the Editor Templates under ~/Views/Shared/EditorTemplates. I'm stuck. Any help would be appreciated. Thanks!
public class LoginModel
{
[Required(AllowEmptyStrings = false)]
[StringLength(128)]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required(AllowEmptyStrings = false)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
[HiddenInput()]
public Guid UserEmailAddressId { get; set; }
[HiddenInput()]
public bool IsVerified { get; set; }
}
Part of my view where I'm binding to my model...
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>RegisterModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PrimaryEmailAddress)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PrimaryEmailAddress)
#Html.ValidationMessageFor(model => model.PrimaryEmailAddress)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ConfirmPassword)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ConfirmPassword)
#Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CultureId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CultureId, (IEnumerable<SelectListItem>)ViewBag.Cultures, " -- Select -- ", null)
#Html.ValidationMessageFor(model => model.CultureId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TimeZoneId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.TimeZoneId, (IEnumerable<SelectListItem>)ViewBag.TimeZones, " -- Select -- ", null)
#Html.ValidationMessageFor(model => model.TimeZoneId)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
In the Password.cshtml file under ~/Views/Shared/EditorTemplates/Password.cshtml
#Html.Password("", ViewData.TemplateInfo.FormattedModelValue, new { #class = "k-textbox" })
THE EDITOR IS WORKING
Turns out I was looking at the wrong View. The actual View was using #Html.TextBoxFor which is why the Default Editor Template for the password was not rendering. You need to use #Html.EditorFor to invoke the default editor template.

ValidationMessageFor for different object

I'm using mvc4, in my view I have a declaration
#model IEnumerable<UserDisplay>
on the same view I want to have a Form with "create" post for different object type name "Review"
how can I use the EditorFor and ValidationMessageFor ? cause model is of different type.
this is not working
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Review</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Info)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Info)
#Html.ValidationMessageFor(model => model.Info)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FromId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FromId)
#Html.ValidationMessageFor(model => model.FromId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ToId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ToId)
#Html.ValidationMessageFor(model => model.ToId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Create a partial view for that form that uses the #model declaration of the required type then use #Html.Partial("mySubFormView"). Don't mix model types in your views, it makes life too complicated.
You can use a view model containing both objects.
public class MyViewModel
{
public IEnumerable<UserDisplay> { get; set; }
public Review Review { get; set; }
}
Then your model declaration in the view becomes:
#model TheNamespace.For.MyViewModel
Which will allow you to use #Html.EditorFor and #Html.ValidationMessageFor helpers.

ASP.NET MVC Model Binder Fails with Strings that look like version numbers?

This should be straight-forward, but here goes - we're using MVC4 to handle a multi-part Form request to upload a binary along with some meta-data via a strongly-typed view in MVC4.
One of the fields is a version number for the file (i.e. something like 0.0.6, 0.4.5-pre, etc...)
I'm getting the following error from the model binder when it tries to bind this version number field to the model field (string type):
{"The parameter conversion from type 'System.String' to type
'Models.NewFileVersion' failed because no type converter can convert
between these types."}
Specifically the error can be traced to our "VersionNumber" field - any ideas as to why this might be happening?
Edit: Source code below
NewFileVersion.cs
public class NewFileVersion
{
[Display(Name = "Version # (0.67, 0.66-pre, etc...)")]
[Required]
public string Version { get; set; }
[Required]
[StringLength(2000, ErrorMessage = "ChangeLog must be between 30 an 2000 characters", MinimumLength = 30)]
[Display(Name = "Version Notes (will be visible to end-users)")]
[DataType(DataType.MultilineText)]
public string ChangeLog { get; set; }
[Display(Name = "Target Platform")]
[UIHint("Enum")]
public FileType PlatformTarget { get; set; }
}
New.cshtml
#model ViewModels.NewFileVersion
#{
ViewBag.Title = "New";
}
<div class="container" id="main-content">
<div class="row">
<h2>
New</h2>
#using (Html.BeginForm("Create", "Files", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>NewFileVersion</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Version)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Version)
#Html.ValidationMessageFor(model => model.Version)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ChangeLog)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ChangeLog)
#Html.ValidationMessageFor(model => model.ChangeLog)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PlatformTarget)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PlatformTarget)
</div>
<div class="editor-label">
<label for="">
File:</label></div>
<div class="editor-field">
<input type="file" name="fileData" required="required" /></div>
<p>
<input type="submit" value="Upload File" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</div>
</div>
FilesController.cs
[HttpPost]
public ActionResult Create(NewFileVersion version, HttpPostedFileBase fileData)
{
//if our model is valid
if(ModelState.IsValid)
{
//etc....
}
ModelState.AddModelError("", "Invalid file submission");
return View("New", version);
}
Try renaming the version parameter for your Create action, e.g:
public ActionResult Create(NewFileVersion fileVersion, HttpPostedFileBase fileData) { ... }
The model binder may be getting confused between the string version model property and the NewFileVersion version action parameter.
You can see why this happens in the BindModel method, because the model has a property exactly matching the name of the action parameter it tries to bind as a simple type/model rather than a complex one.

Resources