Asp.net mvc training

67
ASP.NET MVC

Transcript of Asp.net mvc training

Page 1: Asp.net mvc training

ASP.NET MVC

Page 2: Asp.net mvc training

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]

Page 3: Asp.net mvc training

How MVC Works

Page 4: Asp.net mvc training

Models

Model Binder

DataAnnotations

View Model vs Entities (Business Layer) vs Data Model (Data Layer)

Page 5: Asp.net mvc training

Models - Model Binder

Form

Default

Custom

Value Provider

Binding Collection/List and Dictionary

Page 6: Asp.net mvc training

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

Page 7: Asp.net mvc training

Models - Model Binder - DefaultModelBinder

It is default model binder.

It plays an important role in conversion and mapping of model properties

Page 8: Asp.net mvc training

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.

Page 9: Asp.net mvc training

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]

Page 10: Asp.net mvc training

Models - Model Binder - Attribute

Page 11: Asp.net mvc training

Models - Model Binder - List/Collection

Page 12: Asp.net mvc training

Models - Model Binder - Dictionary

Page 13: Asp.net mvc training

HomeWork

Custom Value Provider - Cookie

Page 14: Asp.net mvc training

Models - DataAnnotations

Validation DataAnnotations

Other DataAnnotations

Custom Validation Attribute

ModelState

Page 15: Asp.net mvc training

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);

}

Page 16: Asp.net mvc training

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" />

Page 17: Asp.net mvc training

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;

}

}

Page 18: Asp.net mvc training

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()

});

}

Page 19: Asp.net mvc training

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.

Page 20: Asp.net mvc training

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

Page 21: Asp.net mvc training

Views

Views - Layouts, Views, Partial Views

Passing Data into Views

Razor - HTML Helpers - Default, Custom; Sections; ViewEngine Customization

Page 22: Asp.net mvc training

Views - Conventional Structure

Page 23: Asp.net mvc training

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

Page 24: Asp.net mvc training

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.

Page 25: Asp.net mvc training

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

Page 26: Asp.net mvc training

Razor

Page 27: Asp.net mvc training

Razor - @

Razor code is C#, so all conventions and features are inherited

Page 28: Asp.net mvc training

Razor - @

@{model.property = 20;}

@model.property => 20

@model.property / 10 => 20 / 10

@(model.property / 10) => 2

[email protected] => text@20

text@(model.property) => text2

@my_twitter_handle => error

@@my_twitter_handle => @my_twitter_handle

Page 29: Asp.net mvc training

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

Page 30: Asp.net mvc training

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

Page 31: Asp.net mvc training

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

Page 32: Asp.net mvc training

Razor - Sections

Page 33: Asp.net mvc training

Views - Default Locations

Page 34: Asp.net mvc training

Views - View Engine Customization

There are two ways:

1. Override existing view engines - Razor or WebForms

2. Create new engine with IViewEngine and IViewpublic 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);

}

Page 35: Asp.net mvc training

Security

There are two kind of securities that will be taken care while building views:

1. XSS

2. CSRF

Page 36: Asp.net mvc training

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

Page 37: Asp.net mvc training

Security - CSRF

Page 38: Asp.net mvc training

Security - CSRF

Page 39: Asp.net mvc training

Routing

Global Routing

Route Constraints

Route Handlers

Page 40: Asp.net mvc training

Routing - Global

Page 41: Asp.net mvc training

Routing - Global

Page 42: Asp.net mvc training

Routing - Custom Route Constraint

Page 43: Asp.net mvc training

Routing - Custom Route Handler

Page 44: Asp.net mvc training

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}");

Page 45: Asp.net mvc training

Routing - Attribute Routing

New Feature in MVC 5

Homework

Page 46: Asp.net mvc training

Controllers

AllowAnonymous

NoAction

Custom Action Result

Page 47: Asp.net mvc training

Filters

Attributes

Filter Types

Extending Filters

Page 48: Asp.net mvc training

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.

Page 49: Asp.net mvc training

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;

}

}

Page 50: Asp.net mvc training

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);

}

}

}

Page 51: Asp.net mvc training

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);

}

}

}

Page 52: Asp.net mvc training

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

Page 53: Asp.net mvc training

Filters - Extensibility

There are two ways to extend filters

1. Override existing one

2. Create your own

Page 54: Asp.net mvc training

Filters - Ordering

Page 55: Asp.net mvc training

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();

}

}

}

Page 56: Asp.net mvc training

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();

}

Page 57: Asp.net mvc training

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);

}

}

Page 58: Asp.net mvc training

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)

{

}

}

Page 59: Asp.net mvc training

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;

}

}

Page 60: Asp.net mvc training

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

Page 61: Asp.net mvc training

Filters - Registration

a. Global Filter - http://snag.gy/ZqdDe.jpg

b. Controller Filter - Class

c. Action Filter - Method

Page 62: Asp.net mvc training

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;

}

Page 63: Asp.net mvc training

Bundling and Minification

Page 64: Asp.net mvc training

Ajax

Get

Post

Page 65: Asp.net mvc training

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

}

});

Page 66: Asp.net mvc training

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

}

});

Page 67: Asp.net mvc training

Questions