Study Notes for Microsoft Exam: Developing ASP.NET MVC Web Applications (70-486)

Took Microsoft Exam 70-486 which part of MCSD certification. I spend about 2 weeks studying the material and took some notes which are posted here. Notes are not complete in the sense that they don’t cover the full syllabus – half of my notes are scattered in different places which will be incorporated here later (hopefully).

Code First Migrations:

Three step process (use Package Manager Console):

  1. enable-migrations -ContextTypeName MyProject.Models.StudentDBContext
    • Creates Configuration class with Seed method
    • Needs to be executed only once to setup migrations
  2. add-migration MyFirstMig
    • Creates {DateStamp}_MyFirstMig.cs in Migrations folder
    • Execute it after each change to model
  3. update-database
    • Execute it to apply changes to database

Data Annotations:

  • [Required]
  • [Range(5, 10)]
  • [StringLength(5)]
  • [DataType(DataType.Date)]         (enum DataType { CreditCard, Currency, Custom, Date, DateTime, Duration, EmailAddress, Html, ImageUrl, MultilineText, Password, PhoneNumber, PostalCode, Text, Time, Upload, Url, })
  • [DisplayFormat(DataFormatString = “{0:d}”)]

Model Validation:

  • In Controller’s Create or Edit action (server):
[HttpPost]
public ActionResult Create(Movie movie)
{
   if (ModelState.IsValid)
   {
      db.Movies.Add(movie);
      db.SaveChanges();
      return RedirectToAction("Index");
   }

   return View(movie);
}
  • In view (browser):
<div class="editor-field">
   @Html.EditorFor(model => model.Title)     
   @Html.ValidationMessageFor(model => model.Title)
</div>

Cross Site Scripting Attack

  • Add @AntiForgeryToken() in view inside form element
  • Add [ValidateAntiForgeryToken] attribute on form post actions

Asynchronous Programming with async and await:

image001

Bundling and Minification

  • Good Article: Link
  • Most browsers limit the number concurrent requests to the same domain to six
  • To disable
<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>
  • Can be overwritten in code
BundleTable.EnableOptimizations = true;
  • Creating script bundle
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                 "~/Scripts/jquery-{version}.js"));
  • Creating style bundle
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
          "~/Content/themes/base/jquery.ui.core.css",
          "~/Content/themes/base/jquery.ui.resizable.css",
          "~/Content/themes/base/jquery.ui.selectable.css",
          "~/Content/themes/base/jquery.ui.accordion.css" ));
  • Adding reference to bundles in view
@Styles.Render("~/Content/themes/base/css", "~/Content/css")
@Scripts.Render("~/bundles/modernizr")

<script src='@Scripts.Url("~/bundles/modernizr")' async> </script>

 

  • Can use ‘*’ wildcard and IncludeDirectory function
bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll")
    .IncludeDirectory("~/Content/themes/base", "*.css"));
  • .min files are selected for release (jquery-1.7.1.min.js)
  • -vsdoc files are ignored (they are for intellisense)
  • Bundle Transformation
    • Implement IBundleTransform
using System.Web.Optimization;

public class LessTransform : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        response.Content = dotless.Core.Less.Parse(response.Content);
        response.ContentType = "text/css";
    }
}
  • Add transformation
var lessBundle = new Bundle("~/My/Less").IncludeDirectory("~/My", "*.less");
lessBundle.Transforms.Add(new LessTransform());
lessBundle.Transforms.Add(new CssMinify());
bundles.Add(lessBundle);

Using OAuth providers with MVC:

  • Register your site with provider and Receive parameters (such as key or id, and secret)
  • Register your application as Provider’s client: RegisterFacebookClient(            appId: “111111111111111”,            appSecret: “a1a1aa111111111a111a111aaa111111”);

Interaction among View, Layout page (_Layout.cshtml) and other pages

@RenderBody() Called from _Layout.cshtml to render the body of the requested page at the right place within layout.
@RenderSection(“scripts”, required: false) Called from _Layout.cshtml to rendor a section if defined in the requested page.- Section definition is optional if required is false- Section definition on requested page

@section Scripts {

   @Scripts.Render(“~/bundles/jqueryval”)

}

@RenderPage(“MyView.cshtml”, MyModel) Renders the specified page as part of the requested page. Similar to @Html.Partial(“MyView”)

 

WCF vs ASP.Net Web API

image002

Others

  • Don’t use HTTP GET request for delete, edit or create options as they open security holes (link)
  • Fiddler, a web debugging tool which logs all HTTP / HTTPS traffic. (http://www.telerik.com/fiddler/)

Authorization

  • [Authorize(Roles=”Admin,PowerUser“, Users=”Mark“)]
    • Implements IAuthorizationFilter which has one method OnAuthorization
  • AuthorizeAttribute.AuthorizeCore method: When overridden, provides an entry point for custom authorization checks.
  • [AllowAnonymous] This attribute on Action will override the Authroize on Controller and wise versa

 

Browser / Feature Detection and Compatibility

  • Video tab with fall backs
<video>
<source src="video.mp4" type='video/mp4' />
<source src="video.webm" type='video/webm' />
<object type="application/x-silverlight-2">
<param name="source" value="http://url/player.xap">
<param name="initParams" value="m=http://url/video.mp4">
</object>
Download the video <a href="video.mp4">here</a>.
</video>

 

  • Display modes (by default we have regular mode and Mobile mode)
    • Mobile.cshtml will be used instead of Index.cshtml automatically when page is accessed through a mobile
    • Add new DefaultDisplayMode (WP7.cshtml)

 

DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("WP7")
  {
      ContextCondition = ctx => ctx.GetOverriddenUserAgent().Contains("Windows Phone OS")
  });

 

  • Setting viewport to device width <meta name=”viewport” content=”width=device-width” />
  • CSS @media query

 

@media only screen and (max-width: 850px) {
    .site-title {
        color: #c8c8c8;
    }
}

@media (min-width: 768px) and (max-width: 979px) and (orientation:portrait) {…

 

  • Check if user is on mobile device: Browser.IsMobileDevice
  • CSS Vendor Prefixes
    • -ms-, -mso- (Mircosoft); -moz- (Mozilla); -webkit- (Apple, Google); -o-, xv- (Opera)
    • Example: -moz-border-radius: 18px;

 

Razor View Templates

 

  • EditorFor template (used with @Html.EditorFor() helper)
    • Path: ~/Views/ControllerName/EditorTemplates/Article.cshtml

 

@model MyMVCApplication1.Article
@if (Model != null)
{
    @Html.TextBox("", Model.Title)
    @Html.TextBox("", Model.Body)
}
else
{
    @Html.TextBox("", string.Empty)
    @Html.TextBox("", string.Empty)
}

 

  • DisplayTemplate (used with @Html.DisplayFor() helper)
    • Path: ~/Views/ControllerName/DisplayTemplates/<Type Name>.cshtml

 

Action Filters

 

    • Authorization filters – Implements the IAuthorizationFilter attribute.
    • Action filters – Implements the IActionFilter attribute.
    • Result filters – Implements the IResultFilter attribute.
    • Exception filters – Implements the IExceptionFilter attribute.
  • Authorization filters are always executed before action filters
  • Filter’s Order parameter can be used to control the order in which filters of same type are executed
  • Filter’s AllowMultiple parameter can be used to run filter only once
  • ActionFilterAttributeimplements bothIActionFilter andIResultFilter and drives fromActionFilterAttribute
    • It has methods: OnActionExecuting, OnActionExecuted, OnResultExecuting, OnResultExecuted
  • Add filter globally to all actions Add(new RequireHttpsAttribute());
    • filters is GlobalFilters.Filters passed as parameter to FilterConfig
  • Useful Fitlers: HandlerError, OutputCache, Authorize

 

Web Accessibility Initiative-Accessible Rich Internet Applications (WAI-ARIA)

  • aria-labelledby=”name_label” This attribute on input field can an link it to the label which can deliver meaning otherwise delivered visually
  • aria-required defines a mandatory input field

 

Search Engine Optimization

  • txt file – create robot exclusion rules (list pages that should be indexed by search engine)
  • Have meaningful url. Rather than com/1, use mysite.com/<record title>

 

Globalization

  • Accept-Language: en-US,en;q=0.8 (Request Header presented to server)
  • en is Language, US is Locale. Language is at a higher level than locale.
  • <globalization culture=”auto” uiculture=”auto” enableclientbasedculture=”true”/> (enable client based culture in Web.Config)
  • Thread.CurrentThread.CurrentUICulture (find current culture)
  • Use resource files
    • keeps strings in resource files (.resx)
    • create separate files for each language (MyResFile.resx, MyResFile.es-MX.resx)
    • access string using MyResFile.MyLabel1
  • An Alternative to resource files is to use localized views
  • There no way to determine culture in javascript (server has to send it back)
  • Setting culture for jQuery in browser (use anyone of the two)
    • <script>preferCulture(language);</script>
    • $.global.preferCulture(language)
  • Manually set culture on server (may be based on user selection)
    • CurrentThread.CurrentUICulture = new CultureInfo(“es-MX”);
  • Create satellite assemblies (dll) to separate culture specific resouces (only required resources are loaded in memory)

 

Action Attributes (other than filters and attributes covered in else where)

  • RequireHttps
  • ValidateInputTo exclude a field [ValidateInput(true, Exclude = “ArbitraryField”)]
  • AllowHtml
  • ActionName
  • ChildActionOnly (action can’t be accessed directly by client, has to be called from a view using @Html.Action(“MyView”) or RenderAction )

 

Error Handling

  • [HandleError(ExceptionType=typeof(NullReferenceException), View=”MyErrorView”)]
    • Action attribute for handling exception
    • Implements IExceptionFilter that has OnException method
    • By default MVC display ~/Views/Shared/Error
  • Application_Error method in global.asax class (for unhandled exception that makes through the stack)
  • IsCustomErrorEnabled

Action Results

  • All action results derive from ActionResult class
Action Result Type Action Helper method Comments
ViewResult View Renders Html, derive from ViewBaseResult
PartialViewResult PartialView Renders Html, derive from ViewBaseResult
JsonResult Json
JavaScriptResult JavaScript
RedirectResult Redirect
RedirectToRouteResult RedirectToActionRedirectToRoute
FileResult File
ContentResult Content Can be used to return pdf, xml etc.
EmptyResult N/A (return null)

 

  • A custom action result can be created by inheriting from ActionResult class and overriding void ExecuteResult(ControllerContext ctx) method

Model Binders

  • DefaultModelBinder Maps a browser request to a data object
  • LinqBinaryModelBinder Maps a browser request to a LINQ object
  • Creating a custom model binder
  • Implement IModelBinder interface with one method: public object BindModel(ControllerContextcontrollerContext,ModelBindingContextbindingContext)
  • Setting custom binder for a model class
[ModelBinder(typeof(MyModelBinder))]
public class MyModel
{       ...     }
  • Another way of doing it

ModelBinders.Binders.Add(typeof(MyModel),newMyModelBinder())

 

  • Extending DefaultModelBinder class
    • public class MyBinder : DefaultModelBinder
  • Extend BindProperty method (loops through every model property one by one)
    • protected override void BindProperty(ControllerContext contContext, ModelBindingContext bindContext, PropertyDescriptor propDesc)
    • can be used to override default behavior for certain properties e.g. combine date and time from two fields into one property
    • call base.BindProperty for properties you want to bind using default binding
  • Registor the new binder

ModelBinders.Binders.DefaultBinder =newMyBinder();

 

  • Weakly typed model, all parameter with login prefix will map to LoginUser model

public ActionResult Login([Bind(Prefix=”login”)]LoginUser user)

  • Exclude / Include paramters for Bind

public ActionResult Save([Bind(Exclude = “Salary”)]Employee emp)

 

  • Four value providers: FormsValueProvider, QueryStringValueProvider, HttpFileCollectionValueProvider, RouteDataValueProvider
  • Three types of model binding: Strong, Weak and using ValueProvider.

 

Routes

  • Defining routes (IgnoreRoute should come before MapRoute)
public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new
            {
                controller = "Home",
                action = "Index",
                id = UrlParameter.Optional
            },
            constraints: new { id = @"\d+" }
            );
        }

 

  • In case of Areas, providing a link to action

@Html.ActionLink(“Exam Detail”, “Exam”, “Detail”, new { area=”ExamSite”}, null)

 

  • Extending default MvcRouteHandler
    • public class MyCustomRouteHandler : MvcRouteHandler
    • Override protected override IHttpHandler GetHttpHandler(RequestContext reqContext)
    • Registering route handler
routes.MapRoute(
                "Home",
                "{controller}/{action}",
                new { controller = "Home", action = "Index" }
                ).RouteHandler = new MyCustomRouteHandler();
  • Implementing IRouteHandler (has one method GetHttpHandler)
    • Registration is bit different from above

Route customRoute = new Route(“custom/{name}”, new MyRouteHandler(“My Route”));

routes.Add(“route-name”, customRoute);

ControllerFactory

  • For custom controller factory, implement IControllerFactory which has three methods: CreateController, ReleaseController, and GetControllerSessionBehavior.
  • Register controller factory in the Global.asax Application_Start method: ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory());
  • Link: Deep Drive into IControllerFactory

View Engine

  • Both RazorViewEngine and Web Forms engine derive from VirtualPathProviderViewEngine which in turn implements IViewEngine
  • IViewEngine has three methods: FindView, FindPartialView and ReleaseView
  • The two find methods return ViewEngineResult object which contains IView
  • IView has one method public void Render(ViewContext viewContext, System.IO.TextWriter writer)

MVC Life Cycle

  • Request
  • UrlRoutingModule selects the Route object
  • Based on the route, UrlRoutingModule obtains an object that implements IRouteHandler (typically it is MvcRouteHandler)
  • MvcRouteHandler creates an instance of MvcHandler which implements IHttpHandler
  • MvcHandler obtains reference to IControllerFactory (typically DefaultControllerFactory)
  • MvcHandler create Controller instance by help of IControllerFactory
  • MvcHandler calls controller’s Execute method
  • ControllerActionInvoker object associated with Controller determines which action method to call
  • Response
  • Controller action create ViewResult
  • ViewResult calls ViewEngine
  • ViewEngine calls View
  • View renders the Response

HTTP Handlers

  • Implement IHttpHandler which has a method ProcessRequest and a property IsReusable
  • Register handler
      <system.web>
        <httpHandlers>
          <add verb="*" path="SampleHandler.new" type="SampleHandler" />
          <add verb="*" path="*.SampleFileExtension" type="SampleHandler2 " />
        </httpHandlers>
      </system.web>

Http Modules

    <system.web>
      <httpModules>
        <add name="HelloWorldModule" type="HelloWorldModule"/>
      </httpModules>
    </system.web>

Windows Identity Foundation

Async / Await and SynchronicationContext (C# .Net)

Following innocuous looking async / await code will cause deadlock.

private void button1_Click(object sender, EventArgs e)
{
  Task<string> task1 = LongRunningProcess();

  textBox1.Text = task1.Result;
}

public async Task<string> LongRunningProcess()
{
  string txt = await Task.Run(() =>
    {
      System.Threading.Thread.Sleep(5000);
      return "results";
    }
  );

  return txt;
}

To understand why, lets go into what await does in the above case.

1 Execution starts when the button is clicked and button1_Click event is fired on the UI thread.
2 The method, named LongRunningProcess, is invoked.
3 The lamda expression passed to Task.Run() executes in a separate thread (lets call it thread_B)
4 Now await keyword is encountered, rather than completing the rest of the method, control returns back to button1_Click event to continue execution after the call to long running method.
5 Calling task1.Result makes the current thread wait on thread_B to complete and provide the results. So UI thread is now waiting for thread_B to complete.
6 As thread_B completes the task, it has to run the remaining part of long running method. Run time ensures that this code executes on the right context. That is, if the initial part of long running method was executed on the UI thread, then remaining part will also be executed in the same thread context.
7 Therefore, thread_B now attempts to run the remaining part of long running method on UI thread, while UI thread is waiting for thread_B to finish.
8 As UI thread and thread_B are waiting for each other, this creates the deadlock.
How to avoid deadlock?

In this case, deadlock can be avoided by anyone of the following ways:

1- Use await keyword while calling long running method. This makes the button click event asynchronous also.

private async void button1_Click(object sender, EventArgs e)
{
  textBox1.Text = await LongRunningProcess();
}

2- Call ConfigureAwait(false), this will inform the run time that the remaining part of long running method doesn’t need to execute on the UI thread, it can continue running on the thread pool.

public async Task<string> LongRunningProcess()
{
  string txt = await Task.Run(() =>
    {
      System.Threading.Thread.Sleep(5000);
      return "results";
    }
  ).ConfigureAwait(false); //avoids the deadlock

  return txt;
}
Why thread contexts are synchronized?

Consider the UI Controls (Windows Forms or WPF), they are not thread safe. Therefore, any update to the UI controls must be done only from the UI thread. To take care of this, any remaining code after await keyword in an asynchronous method will also execute on the thread context which initiated the method call.

Similarly, in an ASP.Net application, running the code on same thread context is important because the Culture, Principal and other information of the request are stored in the thread.

How thread contexts are synchronized?

To manage all this tricky context synchronization, we have SynchronizationContext class in .Net. There are framework specific implementations (derived classes) for Windows Forms, WPF/Silverlight and ASP.Net which handle the SynchronizationContext in their own ways for the framework to function properly.

The Windows Forms implementation uses Control.Invoke method to accomplish this (more details here). For ASP.NET, execution takes place on a different thread but the context is captured and passed on to the new thread.

There is an excellent article on MSDN regarding the SynchronizationContext which I recommend for details.

 

ASP.Net Web Forms vs ASP.NET MVC

When microsoft released ASP.Net, it was thought that it would relieve the need to master HTML and related technologies for most use cases. It will bring the web development closer to windows forms development model with both having similar controls and tools. In ASP.Net forms, we would be able to drag a data grid, drop it on to a page and bind it to a data source, the same way we used to do for windows apps.

Initially I was excited about the idea. Coming from a windows development background, it made things simpler for me. As I did more work with ASP.Net, something didn’t look right. It was very easy to do things you do most of the time in the most common way. But if you want to do something little bit different, then the complexity of the platform made it ridiculously difficult. ASP.Net forms had some significant improvements over ASP but, in hindsight, I think the power and simplicity of HTML, CSS and JavaScript was underestimated.

With ASP.Net MVC, the focus is back on the key web technologies and it feels so much better.

For a detailed comparison between the two technologies, see:

http://msdn.microsoft.com/en-us/magazine/dd942833.aspx
http://weblogs.asp.net/shijuvarghese/archive/2008/07/09/asp-net-mvc-vs-asp-net-web-form.aspx

For learning ASP.Net MVC, I would recommend the Pluralsight video tutorial at ASP.Net MVC website.