public class TimeCard : IValidatableObject
{
...
[Remote("CheckUserName", "Home", ErrorMessage="Username is invalid")]
public string UserName{get; set;}
...
}
public class HomeController : Controller
{
...
public JsonResult CheckUsername(string username)
{
var result = false;
if(username == "tkhuc")
{
result = true;
}
return Json(result, JsonRequestBehavior.AllowGet);
}
Tuesday, July 10, 2012
ASP.NET MVC Custom Client Validation
Implement IClientValidatable
Implement a jQuery validation method
Implement an unobtrusive adapter
public class GreaterThanDateAttribute : ValidationAttribute, IClientValidatable
{
...
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationType = "greater";
rule.ValidationParameters.Add("other", otherPropertyName);
yield return rule;
}
customvalidation.js
/// <reference path="jquery-1.4.4-vsdoc.js" />
/// <reference path="jquery.validate-vsdoc.js" />
/// <reference path="jquery.validate.unobtrusive.js" />
jQuery.validator.addMethod("greater", function(value, element, param)
{
return Date.parse(value) > Date.parse($(param).val());
});
jQuery.validator.unobtrusive.adapters.add("greater", ["other"], function(options){
options.rules["greater"] = "#" + options.params.other;
options.messages["greater"] = options.message; // ~ rule.ErrorMessage
});
Generated html output
<input class="text-box-single-line" id="EndDate" name="EndDate" type="text" value="1/1/2010 12:00:00 AM"
data-val="true"
data-val-greater="EndDate must be greater than StartDate"
data-val-greater-other="StartDate"
/>
Implement a jQuery validation method
Implement an unobtrusive adapter
public class GreaterThanDateAttribute : ValidationAttribute, IClientValidatable
{
...
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationType = "greater";
rule.ValidationParameters.Add("other", otherPropertyName);
yield return rule;
}
customvalidation.js
/// <reference path="jquery-1.4.4-vsdoc.js" />
/// <reference path="jquery.validate-vsdoc.js" />
/// <reference path="jquery.validate.unobtrusive.js" />
jQuery.validator.addMethod("greater", function(value, element, param)
{
return Date.parse(value) > Date.parse($(param).val());
});
jQuery.validator.unobtrusive.adapters.add("greater", ["other"], function(options){
options.rules["greater"] = "#" + options.params.other;
options.messages["greater"] = options.message; // ~ rule.ErrorMessage
});
Generated html output
<input class="text-box-single-line" id="EndDate" name="EndDate" type="text" value="1/1/2010 12:00:00 AM"
data-val="true"
data-val-greater="EndDate must be greater than StartDate"
data-val-greater-other="StartDate"
/>
ASP.NET MVC Client Validation
<script src="jquery-1.4.4.min.js" type="text/javascript"></script>
<script src="jquery.validate.min.js" type="text/javascript"></script>
<script src="jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
Global Settings
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavascriptEnabled" value="true"/>
</appSettings>
Page-level Settings
@Html.EnableClientValidation(false/true)
@Html.EnableUnobtrusiveJavascript(false/true)
Unobtrusive Javascript Validation
<input id="ConfirmHours" name="ConfirmHours" type="text value="0" class="text-box-single-line"
data-val="true"
data-val-equalto="ConfirmHours and Hours do not match."
data-val-equalto-other="*.Hours"
data-val-number="The field ConfirmHours must be a number."
data-val-range="The field ConfirmHours must be between 1 and 120."
data-val-range-max="120"
data-val-range-min="1"
data-val-required="The ConfirmHours field is required."
/>
<span class="field-validation-valid" data-valmsg-for="ConfirmHours" data-valmsg-replace="true"/>
<script src="jquery.validate.min.js" type="text/javascript"></script>
<script src="jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
Global Settings
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavascriptEnabled" value="true"/>
</appSettings>
Page-level Settings
@Html.EnableClientValidation(false/true)
@Html.EnableUnobtrusiveJavascript(false/true)
Unobtrusive Javascript Validation
<input id="ConfirmHours" name="ConfirmHours" type="text value="0" class="text-box-single-line"
data-val="true"
data-val-equalto="ConfirmHours and Hours do not match."
data-val-equalto-other="*.Hours"
data-val-number="The field ConfirmHours must be a number."
data-val-range="The field ConfirmHours must be between 1 and 120."
data-val-range-max="120"
data-val-range-min="1"
data-val-required="The ConfirmHours field is required."
/>
<span class="field-validation-valid" data-valmsg-for="ConfirmHours" data-valmsg-replace="true"/>
Data Validation using Data Annotations
Data Annotations
[Required()][StringLength(25)]
[Range(1,120)]
public int Hours{get; set;}
[Compare("Hours")]
public int ConfirmHours{get; set;}
<div class="editor-label">
@Html.LabelFor(model=>model.ConfirmHours, "Please confirm the hours worked")
</div>
<div class="editor-field">
@Html.EditorFor(model=>model.ConfirmHours)
@Html.ValidationMessageFor(model=>model)
</div>
Custom Validation Attributes
public class GreaterThanDateAttribute : ValidationAttribute
:base("{0} must be greater than {1}")
{
public string OtherPropertyName{get; set;}
public GreaterThanDateAttribute(string otherPropertyName)
{
OtherPropertyName = otherPropertyName;
}
public override string FormatErrorMessage(string name)
{
return String.Format(ErrorMessageString, name, otherPropertyName);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var otherPropertyInfo = validationContext.ObjectType.GetProperty(otherPropertyName);
var otherDate = (DateTime)otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
var thisDate = (DateTime)value;
if(thisDate <= otherDate) //failed
{
var message = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(message);
}return null; //succeeded
}
}
public DateTime StartDate{get; set;}
[GreaterThanDate("StartDate")]
public DateTime EndDate{get; set;}
Sunday, July 8, 2012
MVC 3 Child Output Caching
Controllers\HomeController.cs
public class HomeController : Controller
{
[OutputCache(Duration = 60)]
public ActionResult Index()
{
var model = DateTime.Now;
return View(model);
}
[ChildActionOnly]
[OutputCache(Duration = 10)]
public PartialViewResult CurrentTime(){
var model = DateTime.Now;
return PartialView(model);
}
}
Views\Home\CurrentTime.cshtml
@model DateTime
<p>This is the child action result, current time is: @Model.ToLongTimeString()</p>
Views\Home\Index.cshtml
@model DateTime
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<div>This is the index view for Home, rendering at time: @Model.ToLongTimeString()</div>
<div>@Html.Action("CurrentTime")</div>
public class HomeController : Controller
{
[OutputCache(Duration = 60)]
public ActionResult Index()
{
var model = DateTime.Now;
return View(model);
}
[ChildActionOnly]
[OutputCache(Duration = 10)]
public PartialViewResult CurrentTime(){
var model = DateTime.Now;
return PartialView(model);
}
}
Views\Home\CurrentTime.cshtml
@model DateTime
<p>This is the child action result, current time is: @Model.ToLongTimeString()</p>
Views\Home\Index.cshtml
@model DateTime
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<div>This is the index view for Home, rendering at time: @Model.ToLongTimeString()</div>
<div>@Html.Action("CurrentTime")</div>
MVC Request Validation
Be careful when sending HTML to server.
[ValidateInput(false)] - turn off all verification
[AllowHtml] - granular verification for view model
[ValidateInput(false)] - turn off all verification
[AllowHtml] - granular verification for view model
MVC 3 Action Results
HttpNotFoundResult
public ActionResult Results()
{
return HttpNotFound();
}
HttpRedirectResult
public ActionResult Results()
{
return RedirectPermanent("http://google.com");
}
HttpStatusCodeResult
public AtionResult Results()
{
return HttpStatusCodeResult(415, "Media type not recognized");
}
public ActionResult Results()
{
return HttpNotFound();
}
HttpRedirectResult
public ActionResult Results()
{
return RedirectPermanent("http://google.com");
}
HttpStatusCodeResult
public AtionResult Results()
{
return HttpStatusCodeResult(415, "Media type not recognized");
}
Global Filters
Controllers\HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
throw new InvalidOperationException();
return View();
}
Views\Shared\Error.cshtml
<h2>Sorry, an error occurred while processing your request.</h2>
Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}
Web.config
<system.web>
<customErrors mode="On"/>
....
Action filters: [Authorize], [HandleError]
Custom Action Filters
public class LogAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext){}
public override void OnActionExecuted(ActionExecutedContext filterContext){}
public override void OnResultExecuting(ResultExecutingContext filterContext){}
public override void OnResultExecuted(ResultExecutedContext filterContext){}
}
public class HomeController : Controller
{
public ActionResult Index()
{
throw new InvalidOperationException();
return View();
}
Views\Shared\Error.cshtml
<h2>Sorry, an error occurred while processing your request.</h2>
Global.asax.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
}
Web.config
<system.web>
<customErrors mode="On"/>
....
Action filters: [Authorize], [HandleError]
Custom Action Filters
public class LogAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext){}
public override void OnActionExecuted(ActionExecutedContext filterContext){}
public override void OnResultExecuting(ResultExecutingContext filterContext){}
public override void OnResultExecuted(ResultExecutedContext filterContext){}
}
Subscribe to:
Posts (Atom)