Asp.net mvc training

Post on 16-Jul-2015

179 views 4 download

Transcript of Asp.net mvc training

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

}

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