SlideShare a Scribd company logo
ASP.NET MVC
Why MVC
Advantages:
Separation of Concerns
Easily Extensible
Testable [TDD is possible]
Lightweight [No ViewData]
Full Control on View Rendering [HTML]
Disadvantages:
More Learning Curve
More Complex
Rapid Prototype is not supported [Drag n Drop]
How MVC Works
Models
Model Binder
DataAnnotations
View Model vs Entities (Business Layer) vs Data Model (Data Layer)
Models - Model Binder
Form
Default
Custom
Value Provider
Binding Collection/List and Dictionary
Models - Model Binder - FormCollection
It is collection of key/valu pair
Needs to map each value with property of model manually
Needs manual casting as well
Models - Model Binder - DefaultModelBinder
It is default model binder.
It plays an important role in conversion and mapping of model properties
Models - Model Binder - Custom ModelBinder
For complex scenario, application demands to build custom model binder to satisfy specific
requirement.
It is very helpful when UI developer doesn’t know about model.
Models - Model Binder - Value Providers
Model Binding is two step process:
1. Collecting values from requests using Value Providers
2. Populating models with those values using Model Binders
Below are the available value providers. Number indicates priority, and based on priority, Model
Binders looks into Value Providers to find specific value of a model property.
1. Form Fields [Request.Form]
2. JSON Request Body [Request.InputStream - only when request is an Ajax]
3. Routedata [RouteData.Values]
4. Query String Values [Request.QueryString]
5. Posted Files [Request.Files]
Models - Model Binder - Attribute
Models - Model Binder - List/Collection
Models - Model Binder - Dictionary
HomeWork
Custom Value Provider - Cookie
Models - DataAnnotations
Validation DataAnnotations
Other DataAnnotations
Custom Validation Attribute
ModelState
Models - DataAnnotations - Validation
[Required]
[Required(ErrorMessage="")]
[Required(ErrorMessageResourceName="{Key}" ErrorMessageResourceType=typeof(T))]
[StringLength(12, MinimumLength = 6, ErrorMessage = "")]
[Compare("Password", ErrorMessage = "")]
[ValidatePasswordLength]
[Range(18, 65, ErrorMessage = "")]
[RegularExpression(@"d{1,3}", ErrorMessage = "")]
[Remote("{Action}", "{ControllerName}", ErrorMessage = "")]
public ActionResult ValidateUserName(string username)
{
return Json(!username.Equals("duplicate"), JsonRequestBehavior.AllowGet);
}
[Remote("{Route}", HttpMethod="Post", AdditionalFields="Email", ErrorMessage = "")]
[HttpPost]
public ActionResult ValidateUserName(string username, string email /*AdditionalFields*/)
{
// put some validation
return Json(true);
}
Models - DataAnnotations - Other
//Lists fields to exclude or include when binding parameter or form values to model properties
[Bind(Exclude=”{PropertyName}”)]
//Hides the input control
[HiddenInput(DisplayValue=false)]
//To display customized date format
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm}")]
//If value is NULL, "Null Message" text will be displayed.
[DisplayFormat(NullDisplayText = "Null Message")]
//If you don’t want to display a column use ScaffoldColumn attribute.
//This only works when you use @Html.DisplayForModel() helper
[ScaffoldColumn(false)]
/*Specifies the template or user control that Dynamic Data uses to display a data field
If you annotate a property with UIHint attribute and use EditorFor or DisplayFor inside your views,
ASP.NET MVC framework will look for the specified template which you specified through UIHintAttribute.
The directories it looks for is:
For EditorFor: ~/Views/Shared/EditorTemplates, ~/Views/Controller_Name/EditorTemplates
For DisplayFor: ~/Views/Shared/DisplayTemplates, ~/Views/Controller_Name/DisplayTemplates
*/
[UIHint("StarRating")]
public int Rating { get; set; }
/*StarRating.cshtml*/
@model int
<img src="@Url.Content("~/Content/Images/star-" + Model.ToString("00") + ".png")" title="Rated @Model.ToString()/10" />
Models - DataAnnotations - Custom Annotations
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class NotEqualToAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "{0} cannot be the same as {1}.";
public string OtherProperty { get; private set; }
public NotEqualToAttribute(string otherProperty): base(DefaultErrorMessage)
{
if (string.IsNullOrEmpty(otherProperty))
{
throw new ArgumentNullException("otherProperty");
}
OtherProperty = otherProperty;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherProperty);
}
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value != null)
{
var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(OtherProperty);
var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);
if (value.Equals(otherPropertyValue))
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
}
return ValidationResult.Success;
}
}
Models - DataAnnotations - Model State
[AllowAnonymous]
[HttpPost]
public JsonResult SignUp(RegisterModel model)
{
if (ModelState.IsValid)//Checks all data annotations based on their values
{
//TODO:
}
return Json(new
{
success = false,
errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors)
.Select(m => m.ErrorMessage).ToArray()
});
}
Models - DataAnnotations - Model State - Extension
Model State can be easily extended with IValidatableObject interface. Custom validation logic can be written while implementing
interface method “Validate”.
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Mobile != null && !Mobile.StartsWith("91"))
{
yield return new ValidationResult("India country code is required", new[] { "Mobile" });
}
}
The order of operations for the IValidatableObject to get called:
1. Property attributes
2. Class attributes
3. Validate interface
If any of the steps fail it will return immediately and not continue processing.
Model State can be modified before sending final result to view.
ModelState.Remove("Id"); // Removes validation error for this property if exists
ModelState.AddModelError("<Property>", "<Message>");
try
{
...
}
catch
{
ModelState.AddModelError("", "Throttling limit is reached.");
return;
}
Models - DataAnnotations - Model State - Advance
Views
Views - Layouts, Views, Partial Views
Passing Data into Views
Razor - HTML Helpers - Default, Custom; Sections; ViewEngine Customization
Views - Conventional Structure
Views - Layout with ViewStart
Layout is master page
Layout can be configured for each view - using ViewStart.cshtml
Layout can be configured for view folder - creating ViewStart.cshtml in that folder
Layout can be configured in each view individually with setting Layout property
Nested Layout can be configured - Parent/Child or Header/Footer/LeftBar/RightBar
Views - View and Partial View
View is Razor template - HTML snippet. A view can’t have views
Partial View is also Razor template - HTML snippet - Reusable. A view can have partial views.
Rendering Partial Views:
1. Html.Partial - Returns string, can be manipulated later
2. Html.Action - Returns string, can be manipulated later, cacheable
3. Html.RenderPartial - Returns void, content will be written with parent view into stream directly,
gives better performance.
4. Html.RenderAction - Returns void, content will be written with parent view into stream directly,
gives better performance, cacheable.
Views - Passing Data into View
ViewData - Dictionary, needs casting, life: Action to View
ViewBag - dynamic, doesn’t need casting, ViewData wrapper, life: Action to View
Session - dictionary, needs casting, life: across application
TempData - dictionary, needs casting, Session wrapper, life: Action to any action
Model - Passing model in view argument - Strongly Typed View
Razor
Razor - @
Razor code is C#, so all conventions and features are inherited
Razor - @
@{model.property = 20;}
@model.property => 20
@model.property / 10 => 20 / 10
@(model.property / 10) => 2
text@model.property => text@20
text@(model.property) => text2
@my_twitter_handle => error
@@my_twitter_handle => @my_twitter_handle
Razor - Html Helpers
Html.BeginForm
Html.EndForm
Html.TextBox/Html.TextBoxFor
Html.TextArea/Html.TextAreaFor
Html.Password/Html.PasswordFor
Html.Hidden/Html.HiddenFor
Html.CheckBox/Html.CheckBoxFor
Html.RadioButton/Html.RadioButtonFor
Html.DropDownList/Html.DropDownListFor
Html.ListBox/Html.ListBoxFor
Razor - Custom Html Helper
A method that returns IHtmlString (4.0) or MvcHtmlString (before 4.0)
1. Static Method that returns above return type
2. Extension method
3. @helper
Razor - Custom Html Helper
A method that returns IHtmlString (4.0) or MvcHtmlString (before 4.0)
1. Static Method that returns above return type
2. Extension method
3. @helper
Razor - Sections
Views - Default Locations
Views - View Engine Customization
There are two ways:
1. Override existing view engines - Razor or WebForms
2. Create new engine with IViewEngine and IView
public interface IViewEngine
{
ViewEngineResult FindPartialView(ControllerContext controllerContext,
string partialViewName, bool useCache);
ViewEngineResult FindView(ControllerContext controllerContext,
string viewName,string masterName, bool useCache);
void ReleaseView(ControllerContext controllerContext, IView view);
}
public interface IView
{
void Render(ViewContext viewContext, TextWriter writer);
}
Security
There are two kind of securities that will be taken care while building views:
1. XSS
2. CSRF
Security - XSS
Injecting script that steals sensitive informations like cookies etc.
1. Someone hacked view rendering data - always render encoded html or use AntiXSS
1. System allows to enter scripts/html data - always render encoded html or use AntiXSS
Attributes that allows html content posting:
1. ValidateInput - allows html for any property
2. AllowHtml - allows html for specific property
Security - CSRF
Security - CSRF
Routing
Global Routing
Route Constraints
Route Handlers
Routing - Global
Routing - Global
Routing - Custom Route Constraint
Routing - Custom Route Handler
Routing - When is is not applicable
> Existence of Physical File that Matches The URL/Route Pattern
How to handle those requests: routes.RouteExistingFiles = true;
> Restriction of Content like images, css and styles.
[ContentAuthorize]
public FileResult Index()
{
return File(Request.RawUrl, "image/jpeg");
}
> Securing Specific Folders
routes.IgnoreRoute("Content/{*relpath}");
> How to prevent routing from handling requests for the WebResource.axd file
routes.Ignore("{resource}.axd/{*pathInfo}");
Routing - Attribute Routing
New Feature in MVC 5
Homework
Controllers
AllowAnonymous
NoAction
Custom Action Result
Filters
Attributes
Filter Types
Extending Filters
Filters - What
How to modify default processing execution of Request/Response lifecycle?
Example:
public ActionResult Index()
{
if(!IsAuthorized())
{
//Stop processing and return error
}
return View();
}
MSDN says:
“
Sometimes you want to perform logic either before an action method is called or after an action method runs.
To support this, ASP.NET MVC provides filters.
Filters are custom classes that provide both a declarative and programmatic means to add pre-action and post-action
behavior to controller action methods. “
Filters are just Attributes.
Filters - Attributes
Attributes are meta data that contains custom logic that will be executed at given points.
Custom Attributes
public class HelpAttribute : Attribute
{
public HelpAttribute()
{
}
public String Description{get;set;}
}
[Help(Description = "This is user class contains all information about users and their business flow")]
public class User
{
[Help(Description = "This value is used in Authenticate() method.")]
public string UserName {get;set;}
[Help(Description = "This value is used in Authenticate() method.")]
public string Password {get;set;}
[Help(Description = "This method requires UserName and Password field. So please set those fields before calling this
method.")]
public bool Authenticate()
{
return true;
}
}
Filters - Attributes
public class HelpDocument<T>
{
private void Print(Attribute attr)
{
var ha = attr as HelpAttribute;
if (ha != null)
{
Console.WriteLine(ha.Description);
}
}
public void Build(T bo)
{
//Querying Class Attributes
foreach (Attribute attr in type.GetCustomAttributes(true))
{
Print(attr);
}
//Querying Class-Method Attributes
foreach(MethodInfo method in type.GetMethods())
{
Print(attr);
}
//Querying Class-Field (only public) Attributes
foreach(FieldInfo field in type.GetFields())
{
Print(attr);
}
}
}
Filters - Attributes
public class HelpDocument<T>
{
private void Print(Attribute attr)
{
var ha = attr as HelpAttribute;
if (ha != null)
{
Console.WriteLine(ha.Description);
}
}
public void Build(T bo)
{
//Querying Class Attributes
foreach (Attribute attr in type.GetCustomAttributes(true))
{
Print(attr);
}
//Querying Class-Method Attributes
foreach(MethodInfo method in type.GetMethods())
{
Print(attr);
}
//Querying Class-Field (only public) Attributes
foreach(FieldInfo field in type.GetFields())
{
Print(attr);
}
}
}
Filters - Types
Types of Filters [http://snag.gy/DsYnt.jpg]
1. Authentication (IAuthenticationFilter, AuthenticationAttribute) - Runs first, before any other filters or the action method
2. Authorization (IAuthorizationFilter, AuthorizeAttribute) - Runs first, before any other filters or the action method
3. Action (IActionFilter, ActionFilterAttribute) - Runs before and after the action method
4. Result (IResultFilter, ActionFilterAttribute) - Runs before and after the action result is executed
5. Exception (IExceptionFilter, HandleErrorAttribute) - Runs only if another filter, the action method, or the action result
throws an exception
Filters - Extensibility
There are two ways to extend filters
1. Override existing one
2. Create your own
Filters - Ordering
Filters - Extension - Authentication
public class BasicAuthAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
var user = filterContext.HttpContext.User;
if (user == null || !user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
Filters - Extension - Authorization
public class BlackListAuthorizeAttribute : AuthorizeAttribute
{
private string[] disAllowedUsers;
public BlackListAuthorizeAttribute(params string[] disAllowedUsers)
{
this.disAllowedUsers = disAllowedUsers;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isAuthenticated = httpContext.Request.IsAuthenticated;
bool isInBlackList = disAllowedUsers.Contains(httpContext.User.Identity.Name, StringComparer.InvariantCultureIgnoreCase);
return isAuthenticated && !isInBlackList;
}
}
[BlackListAuthorize("homer", "moe")]
public ActionResult Index()
{
return View();
}
Filters - Extension - Action
public class LoggingFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Trace.Write("(Logging Filter)Action Executing: " +
filterContext.ActionDescriptor.ActionName);
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
filterContext.HttpContext.Trace.Write("(Logging Filter)Exception thrown");
base.OnActionExecuted(filterContext);
}
}
Filters - Extension - Result
public class SqlCacheAttribute : FilterAttribute, IResultFilter, IActionFilter
{
private string _SqlContent = "";
private string _Key = "";
private string CacheKey(ControllerContext filterContext)
{
string key="";//TODO: Your Logic
return key;
}
private void CacheResult(ResultExecutingContext filterContext)
{
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
_Key = CreateKey(filterContext);
_SqlContent = GetCacheValue(key);
if (!string.IsNullOrWhiteSpace(_SqlContent))
{
filterContext.Result = new ContentResult();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!string.IsNullOrWhiteSpace(_SqlContent))
{
filterContext.HttpContext.Response.Write(_SqlContent);
return;
}
CacheResult(filterContext);
}
public void OnResultExecuting(ResultExecutingContext filterContext)
{
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
Filters - Extension - Exception
Limitations of HandleError
1. Not support to log the exceptions
2. Doesn't catch HTTP exceptions other than 500
3. Doesn't catch exceptions that are raised outside controllers
4. Returns error view even for exceptions raised in AJAX calls
public class HandleAjaxErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
// return json data
if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = filterContext.Exception.Message
}
};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
}
return;
}
}
Filters - Execution Cancellation
By setting the Result property to a non-null value, further execution will be cancelled.
Example:
OnActionExecuting1,OnActionExecuted1, OnResultExecuting1, OnResultExecuted1
OnActionExecuting2,OnActionExecuted2, OnResultExecuting2, OnResultExecuted2
OnActionExecuting3,OnActionExecuted3, OnResultExecuting3, OnResultExecuted3
OnActionExecuting2, filterContext.Result = new RedirectResult("~/Home/Index"); //non-null value
Cancelled => OnActionExecuted2, OnActionExecuting3, OnActionExecuted3
Filters - Registration
a. Global Filter - http://snag.gy/ZqdDe.jpg
b. Controller Filter - Class
c. Action Filter - Method
Dependency Injection: Introduction
1. Install nuget package - Install-Package Ninject.MVC5
2. Load/Register services
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHomeService>().To<HomeService>();
}
1. Create controller constructor
public class HomeController : Controller
{
IHomeService _Service;
public HomeController(IHomeService service)
{
_Service = service;
}
Bundling and Minification
Ajax
Get
Post
Ajax - Get
$.ajax({
url: '/Ajax/Index'
, type: 'Get'
, contentType: 'application/json; charset=utf-8'
, dataType: 'json'
, success: function (response) {
console.log(response);
alert(response);
}
, error: function (req, status, error) {
//TODO: error handling
}
});
Ajax - Post
$.ajax({
url: '/Ajax/Index'
, type: 'Post'
, contentType: 'application/json; charset=utf-8'
, dataType: 'json'
, data: '{"a2":"test","a1":5}'
, success: function (response) {
console.log(response);
alert(response);
}
, error: function (req, status, error) {
//TODO: error handling
}
});
Questions

More Related Content

Asp.net mvc training

  • 2. Why MVC Advantages: Separation of Concerns Easily Extensible Testable [TDD is possible] Lightweight [No ViewData] Full Control on View Rendering [HTML] Disadvantages: More Learning Curve More Complex Rapid Prototype is not supported [Drag n Drop]
  • 4. Models Model Binder DataAnnotations View Model vs Entities (Business Layer) vs Data Model (Data Layer)
  • 5. Models - Model Binder Form Default Custom Value Provider Binding Collection/List and Dictionary
  • 6. Models - Model Binder - FormCollection It is collection of key/valu pair Needs to map each value with property of model manually Needs manual casting as well
  • 7. Models - Model Binder - DefaultModelBinder It is default model binder. It plays an important role in conversion and mapping of model properties
  • 8. Models - Model Binder - Custom ModelBinder For complex scenario, application demands to build custom model binder to satisfy specific requirement. It is very helpful when UI developer doesn’t know about model.
  • 9. Models - Model Binder - Value Providers Model Binding is two step process: 1. Collecting values from requests using Value Providers 2. Populating models with those values using Model Binders Below are the available value providers. Number indicates priority, and based on priority, Model Binders looks into Value Providers to find specific value of a model property. 1. Form Fields [Request.Form] 2. JSON Request Body [Request.InputStream - only when request is an Ajax] 3. Routedata [RouteData.Values] 4. Query String Values [Request.QueryString] 5. Posted Files [Request.Files]
  • 10. Models - Model Binder - Attribute
  • 11. Models - Model Binder - List/Collection
  • 12. Models - Model Binder - Dictionary
  • 14. Models - DataAnnotations Validation DataAnnotations Other DataAnnotations Custom Validation Attribute ModelState
  • 15. Models - DataAnnotations - Validation [Required] [Required(ErrorMessage="")] [Required(ErrorMessageResourceName="{Key}" ErrorMessageResourceType=typeof(T))] [StringLength(12, MinimumLength = 6, ErrorMessage = "")] [Compare("Password", ErrorMessage = "")] [ValidatePasswordLength] [Range(18, 65, ErrorMessage = "")] [RegularExpression(@"d{1,3}", ErrorMessage = "")] [Remote("{Action}", "{ControllerName}", ErrorMessage = "")] public ActionResult ValidateUserName(string username) { return Json(!username.Equals("duplicate"), JsonRequestBehavior.AllowGet); } [Remote("{Route}", HttpMethod="Post", AdditionalFields="Email", ErrorMessage = "")] [HttpPost] public ActionResult ValidateUserName(string username, string email /*AdditionalFields*/) { // put some validation return Json(true); }
  • 16. Models - DataAnnotations - Other //Lists fields to exclude or include when binding parameter or form values to model properties [Bind(Exclude=”{PropertyName}”)] //Hides the input control [HiddenInput(DisplayValue=false)] //To display customized date format [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy hh:mm}")] //If value is NULL, "Null Message" text will be displayed. [DisplayFormat(NullDisplayText = "Null Message")] //If you don’t want to display a column use ScaffoldColumn attribute. //This only works when you use @Html.DisplayForModel() helper [ScaffoldColumn(false)] /*Specifies the template or user control that Dynamic Data uses to display a data field If you annotate a property with UIHint attribute and use EditorFor or DisplayFor inside your views, ASP.NET MVC framework will look for the specified template which you specified through UIHintAttribute. The directories it looks for is: For EditorFor: ~/Views/Shared/EditorTemplates, ~/Views/Controller_Name/EditorTemplates For DisplayFor: ~/Views/Shared/DisplayTemplates, ~/Views/Controller_Name/DisplayTemplates */ [UIHint("StarRating")] public int Rating { get; set; } /*StarRating.cshtml*/ @model int <img src="@Url.Content("~/Content/Images/star-" + Model.ToString("00") + ".png")" title="Rated @Model.ToString()/10" />
  • 17. Models - DataAnnotations - Custom Annotations [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class NotEqualToAttribute : ValidationAttribute { private const string DefaultErrorMessage = "{0} cannot be the same as {1}."; public string OtherProperty { get; private set; } public NotEqualToAttribute(string otherProperty): base(DefaultErrorMessage) { if (string.IsNullOrEmpty(otherProperty)) { throw new ArgumentNullException("otherProperty"); } OtherProperty = otherProperty; } public override string FormatErrorMessage(string name) { return string.Format(ErrorMessageString, name, OtherProperty); } protected override ValidationResult IsValid(object value,ValidationContext validationContext) { if (value != null) { var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(OtherProperty); var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null); if (value.Equals(otherPropertyValue)) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } }
  • 18. Models - DataAnnotations - Model State [AllowAnonymous] [HttpPost] public JsonResult SignUp(RegisterModel model) { if (ModelState.IsValid)//Checks all data annotations based on their values { //TODO: } return Json(new { success = false, errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors) .Select(m => m.ErrorMessage).ToArray() }); }
  • 19. Models - DataAnnotations - Model State - Extension Model State can be easily extended with IValidatableObject interface. Custom validation logic can be written while implementing interface method “Validate”. public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (Mobile != null && !Mobile.StartsWith("91")) { yield return new ValidationResult("India country code is required", new[] { "Mobile" }); } } The order of operations for the IValidatableObject to get called: 1. Property attributes 2. Class attributes 3. Validate interface If any of the steps fail it will return immediately and not continue processing.
  • 20. Model State can be modified before sending final result to view. ModelState.Remove("Id"); // Removes validation error for this property if exists ModelState.AddModelError("<Property>", "<Message>"); try { ... } catch { ModelState.AddModelError("", "Throttling limit is reached."); return; } Models - DataAnnotations - Model State - Advance
  • 21. Views Views - Layouts, Views, Partial Views Passing Data into Views Razor - HTML Helpers - Default, Custom; Sections; ViewEngine Customization
  • 22. Views - Conventional Structure
  • 23. Views - Layout with ViewStart Layout is master page Layout can be configured for each view - using ViewStart.cshtml Layout can be configured for view folder - creating ViewStart.cshtml in that folder Layout can be configured in each view individually with setting Layout property Nested Layout can be configured - Parent/Child or Header/Footer/LeftBar/RightBar
  • 24. Views - View and Partial View View is Razor template - HTML snippet. A view can’t have views Partial View is also Razor template - HTML snippet - Reusable. A view can have partial views. Rendering Partial Views: 1. Html.Partial - Returns string, can be manipulated later 2. Html.Action - Returns string, can be manipulated later, cacheable 3. Html.RenderPartial - Returns void, content will be written with parent view into stream directly, gives better performance. 4. Html.RenderAction - Returns void, content will be written with parent view into stream directly, gives better performance, cacheable.
  • 25. Views - Passing Data into View ViewData - Dictionary, needs casting, life: Action to View ViewBag - dynamic, doesn’t need casting, ViewData wrapper, life: Action to View Session - dictionary, needs casting, life: across application TempData - dictionary, needs casting, Session wrapper, life: Action to any action Model - Passing model in view argument - Strongly Typed View
  • 26. Razor
  • 27. Razor - @ Razor code is C#, so all conventions and features are inherited
  • 28. Razor - @ @{model.property = 20;} @model.property => 20 @model.property / 10 => 20 / 10 @(model.property / 10) => 2 text@model.property => text@20 text@(model.property) => text2 @my_twitter_handle => error @@my_twitter_handle => @my_twitter_handle
  • 29. Razor - Html Helpers Html.BeginForm Html.EndForm Html.TextBox/Html.TextBoxFor Html.TextArea/Html.TextAreaFor Html.Password/Html.PasswordFor Html.Hidden/Html.HiddenFor Html.CheckBox/Html.CheckBoxFor Html.RadioButton/Html.RadioButtonFor Html.DropDownList/Html.DropDownListFor Html.ListBox/Html.ListBoxFor
  • 30. Razor - Custom Html Helper A method that returns IHtmlString (4.0) or MvcHtmlString (before 4.0) 1. Static Method that returns above return type 2. Extension method 3. @helper
  • 31. Razor - Custom Html Helper A method that returns IHtmlString (4.0) or MvcHtmlString (before 4.0) 1. Static Method that returns above return type 2. Extension method 3. @helper
  • 33. Views - Default Locations
  • 34. Views - View Engine Customization There are two ways: 1. Override existing view engines - Razor or WebForms 2. Create new engine with IViewEngine and IView public interface IViewEngine { ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache); ViewEngineResult FindView(ControllerContext controllerContext, string viewName,string masterName, bool useCache); void ReleaseView(ControllerContext controllerContext, IView view); } public interface IView { void Render(ViewContext viewContext, TextWriter writer); }
  • 35. Security There are two kind of securities that will be taken care while building views: 1. XSS 2. CSRF
  • 36. Security - XSS Injecting script that steals sensitive informations like cookies etc. 1. Someone hacked view rendering data - always render encoded html or use AntiXSS 1. System allows to enter scripts/html data - always render encoded html or use AntiXSS Attributes that allows html content posting: 1. ValidateInput - allows html for any property 2. AllowHtml - allows html for specific property
  • 42. Routing - Custom Route Constraint
  • 43. Routing - Custom Route Handler
  • 44. Routing - When is is not applicable > Existence of Physical File that Matches The URL/Route Pattern How to handle those requests: routes.RouteExistingFiles = true; > Restriction of Content like images, css and styles. [ContentAuthorize] public FileResult Index() { return File(Request.RawUrl, "image/jpeg"); } > Securing Specific Folders routes.IgnoreRoute("Content/{*relpath}"); > How to prevent routing from handling requests for the WebResource.axd file routes.Ignore("{resource}.axd/{*pathInfo}");
  • 45. Routing - Attribute Routing New Feature in MVC 5 Homework
  • 48. Filters - What How to modify default processing execution of Request/Response lifecycle? Example: public ActionResult Index() { if(!IsAuthorized()) { //Stop processing and return error } return View(); } MSDN says: “ Sometimes you want to perform logic either before an action method is called or after an action method runs. To support this, ASP.NET MVC provides filters. Filters are custom classes that provide both a declarative and programmatic means to add pre-action and post-action behavior to controller action methods. “ Filters are just Attributes.
  • 49. Filters - Attributes Attributes are meta data that contains custom logic that will be executed at given points. Custom Attributes public class HelpAttribute : Attribute { public HelpAttribute() { } public String Description{get;set;} } [Help(Description = "This is user class contains all information about users and their business flow")] public class User { [Help(Description = "This value is used in Authenticate() method.")] public string UserName {get;set;} [Help(Description = "This value is used in Authenticate() method.")] public string Password {get;set;} [Help(Description = "This method requires UserName and Password field. So please set those fields before calling this method.")] public bool Authenticate() { return true; } }
  • 50. Filters - Attributes public class HelpDocument<T> { private void Print(Attribute attr) { var ha = attr as HelpAttribute; if (ha != null) { Console.WriteLine(ha.Description); } } public void Build(T bo) { //Querying Class Attributes foreach (Attribute attr in type.GetCustomAttributes(true)) { Print(attr); } //Querying Class-Method Attributes foreach(MethodInfo method in type.GetMethods()) { Print(attr); } //Querying Class-Field (only public) Attributes foreach(FieldInfo field in type.GetFields()) { Print(attr); } } }
  • 51. Filters - Attributes public class HelpDocument<T> { private void Print(Attribute attr) { var ha = attr as HelpAttribute; if (ha != null) { Console.WriteLine(ha.Description); } } public void Build(T bo) { //Querying Class Attributes foreach (Attribute attr in type.GetCustomAttributes(true)) { Print(attr); } //Querying Class-Method Attributes foreach(MethodInfo method in type.GetMethods()) { Print(attr); } //Querying Class-Field (only public) Attributes foreach(FieldInfo field in type.GetFields()) { Print(attr); } } }
  • 52. Filters - Types Types of Filters [http://snag.gy/DsYnt.jpg] 1. Authentication (IAuthenticationFilter, AuthenticationAttribute) - Runs first, before any other filters or the action method 2. Authorization (IAuthorizationFilter, AuthorizeAttribute) - Runs first, before any other filters or the action method 3. Action (IActionFilter, ActionFilterAttribute) - Runs before and after the action method 4. Result (IResultFilter, ActionFilterAttribute) - Runs before and after the action result is executed 5. Exception (IExceptionFilter, HandleErrorAttribute) - Runs only if another filter, the action method, or the action result throws an exception
  • 53. Filters - Extensibility There are two ways to extend filters 1. Override existing one 2. Create your own
  • 55. Filters - Extension - Authentication public class BasicAuthAttribute : ActionFilterAttribute, IAuthenticationFilter { public void OnAuthentication(AuthenticationContext filterContext) { } public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) { var user = filterContext.HttpContext.User; if (user == null || !user.Identity.IsAuthenticated) { filterContext.Result = new HttpUnauthorizedResult(); } } }
  • 56. Filters - Extension - Authorization public class BlackListAuthorizeAttribute : AuthorizeAttribute { private string[] disAllowedUsers; public BlackListAuthorizeAttribute(params string[] disAllowedUsers) { this.disAllowedUsers = disAllowedUsers; } protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuthenticated = httpContext.Request.IsAuthenticated; bool isInBlackList = disAllowedUsers.Contains(httpContext.User.Identity.Name, StringComparer.InvariantCultureIgnoreCase); return isAuthenticated && !isInBlackList; } } [BlackListAuthorize("homer", "moe")] public ActionResult Index() { return View(); }
  • 57. Filters - Extension - Action public class LoggingFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Trace.Write("(Logging Filter)Action Executing: " + filterContext.ActionDescriptor.ActionName); base.OnActionExecuting(filterContext); } public override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.Exception != null) filterContext.HttpContext.Trace.Write("(Logging Filter)Exception thrown"); base.OnActionExecuted(filterContext); } }
  • 58. Filters - Extension - Result public class SqlCacheAttribute : FilterAttribute, IResultFilter, IActionFilter { private string _SqlContent = ""; private string _Key = ""; private string CacheKey(ControllerContext filterContext) { string key="";//TODO: Your Logic return key; } private void CacheResult(ResultExecutingContext filterContext) { } public void OnActionExecuting(ActionExecutingContext filterContext) { _Key = CreateKey(filterContext); _SqlContent = GetCacheValue(key); if (!string.IsNullOrWhiteSpace(_SqlContent)) { filterContext.Result = new ContentResult(); } } public void OnActionExecuted(ActionExecutedContext filterContext) { if (!string.IsNullOrWhiteSpace(_SqlContent)) { filterContext.HttpContext.Response.Write(_SqlContent); return; } CacheResult(filterContext); } public void OnResultExecuting(ResultExecutingContext filterContext) { } public void OnResultExecuted(ResultExecutedContext filterContext) { } }
  • 59. Filters - Extension - Exception Limitations of HandleError 1. Not support to log the exceptions 2. Doesn't catch HTTP exceptions other than 500 3. Doesn't catch exceptions that are raised outside controllers 4. Returns error view even for exceptions raised in AJAX calls public class HandleAjaxErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { // return json data if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest") { filterContext.Result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = new { error = true, message = filterContext.Exception.Message } }; filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.StatusCode = 500; } return; } }
  • 60. Filters - Execution Cancellation By setting the Result property to a non-null value, further execution will be cancelled. Example: OnActionExecuting1,OnActionExecuted1, OnResultExecuting1, OnResultExecuted1 OnActionExecuting2,OnActionExecuted2, OnResultExecuting2, OnResultExecuted2 OnActionExecuting3,OnActionExecuted3, OnResultExecuting3, OnResultExecuted3 OnActionExecuting2, filterContext.Result = new RedirectResult("~/Home/Index"); //non-null value Cancelled => OnActionExecuted2, OnActionExecuting3, OnActionExecuted3
  • 61. Filters - Registration a. Global Filter - http://snag.gy/ZqdDe.jpg b. Controller Filter - Class c. Action Filter - Method
  • 62. Dependency Injection: Introduction 1. Install nuget package - Install-Package Ninject.MVC5 2. Load/Register services private static void RegisterServices(IKernel kernel) { kernel.Bind<IHomeService>().To<HomeService>(); } 1. Create controller constructor public class HomeController : Controller { IHomeService _Service; public HomeController(IHomeService service) { _Service = service; }
  • 65. Ajax - Get $.ajax({ url: '/Ajax/Index' , type: 'Get' , contentType: 'application/json; charset=utf-8' , dataType: 'json' , success: function (response) { console.log(response); alert(response); } , error: function (req, status, error) { //TODO: error handling } });
  • 66. Ajax - Post $.ajax({ url: '/Ajax/Index' , type: 'Post' , contentType: 'application/json; charset=utf-8' , dataType: 'json' , data: '{"a2":"test","a1":5}' , success: function (response) { console.log(response); alert(response); } , error: function (req, status, error) { //TODO: error handling } });