Nov 20 2015

New Mvc6 Controls Toolkit

Category: TypeScript | JavaScript | MVC | Asp.netFrancesco @ 04:50

Web development changed dramatically in the last few years and the Mvc Controls Toolkit team run after all changes to offer a state of the art toolkit, but now it is time to redesign the whole toolkit from the scratch! JavaScript world evolved, and web applications reliy always more on client side techniques. New JavaScript frameworks appears and evolve quickly, thus the need of a better separation between server side and client side world. The new Mvc 6 Controls Toolkit answers to these new Web Development boundaries are: TypeScript, a better separation of JavaScript world coordinated with server side C# code through trans-compilation of C# classes and attributes, native support of the most common client side frameworks like Angular.js, and Knockout.js, and open support for other client side framework by means of providers,…and more!

 

Please leave you feedback on the specifications of the new Mvc 6 Controls Toolkit!

 

Francesco

Tags: , , , , , , ,

Oct 31 2015

Building Complex Controls with Asp.Net MVC 6 TagHelpers

Category: Asp.net | MVCFrancesco @ 04:09

Asp.Net Mvc 6 proposes a new option to Html Helpers: Tag Helpers. Tag Helpers are similar to Html Helpers but they use an Html tags – like syntax. Basically, they are custom tags with custom attributes that are translated into standard Html tags during server side Razor processing.

They are somehow similar to Html5 custom elements but they are processed on the server side, so they don’t need JavaScript to work properly and their code is visible to search engine robots. Html 5 elements are not fully supported by all main browsers, but they are somehow simulated on all browsers by several JavaScript frameworks, like, for instance, Knockout.js.

Thus, one might plan to build TagHelper based Mvc controls that create their final Html either on the server side or on the client side with the help of a JavaScript framework that supports custom elements. More specifically, the same Razor View might generate either the final Html or some custom elements based code to be interpreted on the client side by a JavaScript framework, depending on some settings specified either in the View itself, or in the controller, or in some configuration file. Both server and client side generation have their vantages and disadvantages(among them server controls are visible to search engines, but client controls are more flexible), so the possibility to change between them without changing the Razor code appears very interesting.

This post is not a basic tutorial on Tag Helpers, but a tutorial on how to implement advanced template based controls, like grids, menus, or tree-views with TagHelpers. An introduction to TagHelpers is here; please read it if you are new to custom Tag Helpers implementation.

This tutorial assume you have:

  1. A Visual Studio 2015 based development environment. If you have not installed VS 2015, yet, please refer to my previous post on how to build your VS 2015 based development environment.
  2. Asp.Net 5 beta8 installed. Instructions on how to move to beta8 may be found here.

 

Template Based Controls

Complex controls like TreeViews and Grids use templates to specify how each node/row is rendered. Usually, they have also default templates, so the developer needs to specify templates just for the “pieces” that need custom rendering. For instance, in the case of a grid a developer wishing to use the default row template might need to specify templates just for a few columns that need custom rendering. Controls may allow several more custom templates, such as a custom pager template, a custom header template, a footer template and so on.

In this tutorial I’ll show just the basic technique for implementing templates with TagHelpers. For this purpose we define a simple <iterate>…</iterate> TagHelper that instantiates a template on all elements of an IEnumerable. Moreover, all inputs field created in the output Html will have the right names for the Model Binder to read back the IEnumerable when the form containing the <iterate> tag is submitted (see here if you are new to model binding to an IEnumerable).

The Test Project

Open VS 2015 and select: File –> New –> Project…

Project

Now select “ASP.NET Web Application” and call the project “IterateTagHelperTest” (please use exactly the same name, otherwise you will not be able to use my code “as it is”  because of  namespace mismatches).

MVC6

Now choose “Web Application” under “ASP.NET Preview Templates”, and click “OK” without changing anything else.

 

We will test our new TagHelper with a new View handled by the HomeController.

We need a ViewModel, so as a first step go to the “ViewModels” folder and add a child folder named “Home” for all HomeController ViewModels.

Then add a new class called “TagTestViewModel.cs” to this folder.

Finally, delete the code created by the scaffolder and add the following code:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5.  
  6. namespace IterateTagHelperTest.ViewModels.Home
  7. {
  8.     public class Keyword
  9.     {
  10.         public string Value { get; set; }
  11.         public Keyword(string value)
  12.         {
  13.             Value = value;
  14.         }
  15.         public Keyword()
  16.         {
  17.             
  18.         }
  19.  
  20.     }
  21.     public class TagTestViewModel
  22.     {
  23.         public IEnumerable<Keyword> Keywords { get; set; }
  24.     }
  25. }

It is a simple ViewModel containing an IEnumerable to test our iterate TagHelper.

Now move to the HomeController and add the following using:

  1. using IterateTagHelperTest.ViewModels.Home;

 

Then add a Get and a Post action methods to test our TagHelper (without modifying all other action methods):

  1. [HttpGet]
  2. public IActionResult TagTest()
  3. {
  4.     return View(new TagTestViewModel
  5.     {
  6.         Keywords = new List<Keyword> {
  7.         new Keyword("ASP.NET"),
  8.         new Keyword("MVC"),
  9.         new Keyword("Tag Helpers") }
  10.     });
  11. }
  12. [HttpPost]
  13. public IActionResult TagTest(TagTestViewModel model)
  14. {
  15.     return View(model);
  16. }

 

Now go to the Views/Home folder and add a new View for the newly created action methods. Call it “TagTest” to match the action methods name.

Remove the default code and substitute it with:

  1. @model IterateTagHelperTest.ViewModels.Home.TagTestViewModel
  2. @{
  3.     ViewBag.Title = "Tag Test";
  4. }
  5.  
  6. <h2>@ViewBag.Title</h2>

We will insert the remainder of the code after the implementation of our TagHelper. Now we need just a title to run the application and test that everything we have done works properly.

Before testing the application we need a link to reach the newly defined View. Open the Views/Shared/_Layout.cshtml default layout page and locate the Main Menu:

 

  1. <ul class="nav navbar-nav">
  2.     <li><a asp-controller="Home" asp-action="Index">Home</a></li>
  3.     <li><a asp-controller="Home" asp-action="About">About</a></li>
  4.     <li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
  5. </ul>

 

And add a new menu item for the newly created page:

  1. <ul class="nav navbar-nav">
  2.     <li><a asp-controller="Home" asp-action="Index">Home</a></li>
  3.     <li><a asp-controller="Home" asp-action="About">About</a></li>
  4.     <li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
  5.     <li><a asp-controller="Home" asp-action="TagTest">Test</a></li>
  6. </ul>

Now run the application and click on the “Test” top menu item: you should go to our newly created test page with title “Tag Test”.

Now that our test environment is ready we may move to the TagHelper implementation!

Handling Template Current Scope

A template is the whole Razor code enclosed within a template-definition TagHelper. For instance, in the case of a grid we might have a <column-template asp-for=”….”> </column-template > TagHelper that encloses custom column templates, a <header-template > </header-template > that encloses custom header templates, and so on. Since our simple <iteration> TagHelper,  includes a single template we will take the whole <iteration> TagHelper content as template. In the case, of more complex controls the main control TagHelper  usually includes several children template-definition TagHelpers.

According to our previous definition, each template may contain both: tags, Razor instructions and variable definitions. Since the same template is typically  called several time  we need a way to ensure that the scope of all Razor variables is limited to the template itself. Moreover, all asp-for attributes inside the template must not refer to the Razor View ViewModel but to the current model the template is being instantiated on.

Something like:

  1.      <iterate asp-for="Keywords">
  2.          @using (var s = Html.NextScope<Keyword>())
  3.          {
  4.              var m = s.M;
  5.              <div class="form-group">
  6.                  <div class="col-md-10">
  7.                             <input asp-for="@m().Value" class="form-control" />
  8.                  </div>
  9.              </div>
  10.          }
  11.      </iterate>

should do the job. Where Html.NextScope<Keyword>() takes the the current scope passed by the father <iterate> TagHelper put it in a variable, and makes it the active scope. s.M() takes the current model from the current scope. s.M must be a function to avoid that m is included in the input names(Keyword[i].m.Value, instead of the correct Keyword[i].Value).

When the template execution is terminated the scope object is disposed, and its dispose method removes it form the top of the scopes stack, and re-activate the previously active scope, if any(we need a stack, because templates might nest).

The <iteration> TagHelper  takes the list of Keywords thanks to its asp-for=”Keywords” attribute, and call the template on each object of the list:

  1. foreach (var x in model)
  2. {
  3.     TemplateHelper.DeclareScope(ViewContext.ViewData, x, string.Format("{0}[{1}]", fullName, i++));
  4.     sb.Append((await context.GetChildContentAsync(false)).GetContent());
  5.    
  6. }

The TemplateHelper.DeclareScope helper basically put all scope information into an item of the Razor View ViewData dictionary, where the previously discussed Html.NextScope method can take it. The current scope contains the current model, and the HtmlPrefix to be added to all names. In our case Keywords[0]…Keywords[n]. This way all input controls will have names like “Keywords[i].Value”, instead of simply “Value”. This is necessary for model binding to work properly when the form is submitted.

When the scope is activated by Html.NextScope  the HtmlPrefix is temporarily put into the TemplateInfo.HtmlFieldPrefix field of the Razor View ViewData dictionary. This is enough to ensure, it  automatically prefixes all names. When the current scope is deactivated  the previous TemplateInfo.HtmlFieldPrefix value is restored.

In the next two sections i give all implementation details of both the scope stack , and of the <iterate> TagHelper.

Implementing the Scope Stack

We insert the Scope Stack code in a new folder. Go to the Web Project root and add a new folder called HtmlHelpers.

We start with the definition of an interface containing all scope informations. Under the previously created HtmlHelpers folder add a new interface called ITemplateScope.cs. Then substitute the scaffolded code with:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Microsoft.AspNet.Mvc.ViewFeatures;
  6.  
  7. namespace IterateTagHelperTest.HtmlHelpers
  8. {
  9.     public interface ITemplateScope : IDisposable
  10.     {
  11.         string Prefix { get; set; }
  12.         ITemplateScope Father { get; set; }
  13.     }
  14.     public interface ITemplateScope<T> : ITemplateScope
  15.     {
  16.         Func<T> M { get; set; }
  17.     }
  18. }

The interface contains a generic that will be instantiated with the template model type. The model is returned by a function in order to get the right names inside the template (this way all names start from the first property after the function, see previous section). All members that do not depend from the generic are grouped into the not-generic interface ITemplateScope, the final interface inherit from. Moreover, ITemplateScope inherit from IDisposable since it must be used within a using statement. Together with the model the scope contains the current HtmlPrefix(see previous section), and a pointer to the father scope(this way, a template has access also to the father template model in case of nested templates).

Now we are ready to implement the Html.NextScope<T>   and TemplateHelper.DeclareScope methods. The whole implementation is based on an active scopes stack whose stack items are instances of a class that is declared private inside the TemplateHelper static class:

private class templateActivation
{
    public string HtmlPrefix { get; set; }
    public object Model { get; set; }
    public ITemplateScope Scope { get; set; }
}

The class contains the father HtmlPrefix to restore when the scope is deactivated, a not-generic pointer to the scope interface, and the scope model as an object since the model is not accessible through the ITemplateScope interface. The same class is used to pass scope information among method calls.

The DeclareScope method store new scope information in the ViewData dictionary

private const string lastActivation = "_template_stack_";

 

public static void DeclareScope(ViewDataDictionary vd, object model, string newHtmlPrefix)
{
    var a = new templateActivation
    {
        Model = model,
        HtmlPrefix = newHtmlPrefix
    };
    vd[lastActivation] = a;
}

Then NextScope<T> takes it to activate a new scope:

private const string lastActivation = "_template_stack_";
private const string externalActivation = "_template_external_";

 

public static ITemplateScope<T> NextScope<T>(this IHtmlHelper helper)
{
    var activation = helper.ViewContext.ViewData[lastActivation] as templateActivation;
    if (activation != null)
    {
        helper.ViewContext.ViewData[lastActivation] = null;
        var stack = helper.ViewContext.ViewData[templateStack] as Stack<templateActivation>;
        ITemplateScope father = null;
        if (stack != null && stack.Count > 0)
        {
            father = stack.Peek().Scope;
        }
        if (father == null)
        {
            father = helper.ViewContext.ViewData[externalActivation] as ITemplateScope;
        }
        return new TemplateScope<T>(helper.ViewContext.ViewData, activation)
        {
            M = () => (T)(activation.Model),
            Prefix = activation.HtmlPrefix,
            Father = father
        };
    }
    else return null;
}

If a newly created scope is found a new instance of the TemplateScope<T> class that implements the ITemplateScope<T> class is created. The TemplateScope<T> class is declared as private inside the TemplateHelper class. The stack is accessed just to find the father ITemplateScope. If the stack is empty the method try to get the father scope from another ViewData entry, that might be used to keep activation information across partial view calls(not implemented in this example).

The stack push is handled in the TemplateScope<T> constructor:

  1. public TemplateScope(ViewDataDictionary vd, templateActivation a)
  2. {
  3.     this.vd = vd;
  4.     a.Scope = this;
  5.     PushTemplate(a);
  6.  
  7. }

While the stack pop is handled by the TemplateScope<T> Dispose method:

  1. public void Dispose()
  2. {
  3.     PopTemplate();
  4. }

In order to add the whole implementation described above to your project, go to the previously created HtmlHelpers folder and add a class called TemplateHelper.cs. Then replace the scaffolded code by the code below:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Microsoft.AspNet.Mvc.Rendering;
  6. using Microsoft.AspNet.Mvc.ViewFeatures;
  7.  
  8. namespace IterateTagHelperTest.HtmlHelpers
  9. {
  10.  
  11.     public static class TemplateHelper
  12.     {
  13.         private const string templateStack = "_template_stack_";
  14.         private const string lastActivation = "_template_stack_";
  15.         private const string externalActivation = "_template_external_";
  16.         private class templateActivation
  17.         {
  18.             public string HtmlPrefix { get; set; }
  19.             public object Model { get; set; }
  20.             public ITemplateScope Scope { get; set; }
  21.         }
  22.         private class TemplateScope<T> : ITemplateScope<T>
  23.         {
  24.  
  25.  
  26.             public TemplateScope(ViewDataDictionary vd, templateActivation a)
  27.             {
  28.                 this.vd = vd;
  29.                 a.Scope = this;
  30.                 PushTemplate(a);
  31.  
  32.             }
  33.             private ViewDataDictionary vd;
  34.             public string Prefix { get; set; }
  35.             public Func<T> M { get; set; }
  36.             public ITemplateScope Father { get; set; }
  37.             public void Dispose()
  38.             {
  39.                 PopTemplate();
  40.             }
  41.             private void PushTemplate(templateActivation a)
  42.             {
  43.                 var activation = new templateActivation
  44.                 {
  45.                     HtmlPrefix = vd.TemplateInfo.HtmlFieldPrefix,
  46.                     Model = a.Model,
  47.                     Scope = a.Scope
  48.                 };
  49.                 var stack = vd[templateStack] as Stack<templateActivation> ?? new Stack<templateActivation>();
  50.                 stack.Push(activation);
  51.                 vd[templateStack] = stack;
  52.                 vd.TemplateInfo.HtmlFieldPrefix = a.HtmlPrefix;
  53.             }
  54.             private void PopTemplate()
  55.             {
  56.                 var stack = vd[templateStack] as Stack<templateActivation>;
  57.                 if (stack != null && stack.Count > 0)
  58.                 {
  59.                     vd.TemplateInfo.HtmlFieldPrefix = stack.Pop().HtmlPrefix;
  60.                 }
  61.             }
  62.         }
  63.         public static void DeclareScope(ViewDataDictionary vd, object model, string newHtmlPrefix)
  64.         {
  65.             var a = new templateActivation
  66.             {
  67.                 Model = model,
  68.                 HtmlPrefix = newHtmlPrefix
  69.             };
  70.             vd[lastActivation] = a;
  71.         }
  72.         public static ITemplateScope<T> NextScope<T>(this IHtmlHelper helper)
  73.         {
  74.             var activation = helper.ViewContext.ViewData[lastActivation] as templateActivation;
  75.             if (activation != null)
  76.             {
  77.                 helper.ViewContext.ViewData[lastActivation] = null;
  78.                 var stack = helper.ViewContext.ViewData[templateStack] as Stack<templateActivation>;
  79.                 ITemplateScope father = null;
  80.                 if (stack != null && stack.Count > 0)
  81.                 {
  82.                     father = stack.Peek().Scope;
  83.                 }
  84.                 if (father == null)
  85.                 {
  86.                     father = helper.ViewContext.ViewData[externalActivation] as ITemplateScope;
  87.                 }
  88.                 return new TemplateScope<T>(helper.ViewContext.ViewData, activation)
  89.                 {
  90.                     M = () => (T)(activation.Model),
  91.                     Prefix = activation.HtmlPrefix,
  92.                     Father = father
  93.                 };
  94.             }
  95.             else return null;
  96.         }
  97.     }
  98. }

Now we are ready to move to the TagHelper implementation.

Implementing the <iteration> TagHelper

Go to the root of the web Project and add a folder called TagHelpers, then add a new class called IterateTagHelper.cs to this folder. Substitute the scaffolded code with the code below:

  1. using Microsoft.AspNet.Mvc.Rendering;
  2. using Microsoft.AspNet.Razor.Runtime.TagHelpers;
  3. using System.Text;
  4. using Microsoft.AspNet.Mvc.ViewFeatures;
  5. using System.Threading.Tasks;
  6. using System.Collections;
  7. using IterateTagHelperTest.HtmlHelpers;
  8.  
  9.  
  10. namespace IterateTagHelperTest.TagHelpers
  11. {
  12.     [HtmlTargetElement("iterate", Attributes = ForAttributeName)]
  13.     public class IterateTagHelper : TagHelper
  14.     {
  15.         private const string ForAttributeName = "asp-for";
  16.         [HtmlAttributeNotBound]
  17.         [ViewContext]
  18.         public ViewContext ViewContext { get; set; }
  19.         [HtmlAttributeName(ForAttributeName)]
  20.         public ModelExpression For { get; set; }
  21.  
  22.         public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
  23.         {
  24.             var name = For.Name;
  25.             var fullName = ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
  26.             IEnumerable model = For.Model as IEnumerable;
  27.             output.TagName = string.Empty;
  28.             StringBuilder sb = new StringBuilder();
  29.             if (model != null)
  30.             {
  31.                 int i = 0;
  32.                 foreach (var x in model)
  33.                 {
  34.                     TemplateHelper.DeclareScope(ViewContext.ViewData, x, string.Format("{0}[{1}]", fullName, i++));
  35.                     sb.Append((await context.GetChildContentAsync(false)).GetContent());
  36.  
  37.                 }
  38.             }
  39.             output.Content.SetContentEncoded(sb.ToString());
  40.  
  41.         }
  42.  
  43.     }
  44. }

Tag attributes are mapped to properties with the help of the HtmlAttributeName attribute, and are automatically populated when the IterateTagHelper instance is created. The asp-for attribute that in our case selects the collection to iterate on is mapped into the For property whose type is ModelExpression. As a result of the match a ModelExpression instance containing the collection, and its name is created.

The ViewContext property is not mapped to any tag attribute since it is decorated with the HtmlAttributeNotBound attribute. Instead it is populated with the Razor View ViewContext since it is decorated with the ViewContext attribute. We need the View ViewContext to extract the View ViewData dictionary.

The remainder of the code is straightforward:

  1. We get the name of the asp-for bound property.
  2. We add a possible HtmlPrefix to the above name by calling the GetFullHtmlFieldName method. We need it to pass the right HtmlPrefix to the scope of each IEnumerable element. Without the right prefix the collection can’t be bound by the receiving Action Method when the form is submitted.
  3. We extract the collection and cast it to the right type.
  4. Since we don’t want to enclose all template instantiations within a container we set the output.TagName to the empty string.
  5. We create a StringBuilder to build our content.
  6. For each IEnumerable element we create a new scope with the right HtmlPrefix, and the we get the element HTML by calling GetChildContentAsync. We pass a false argument to avoid that the method might return the previously cached string(otherwise we would obtain N copies of HTML of the first collection element).
  7. Finally we set the string created by chaining all children HTML as a tag content by calling the SetContentEncoded method. The Encoded postfix avoids that the string be HTML encoded.

Importing HtmlHelper and TagHelper

Now we need to import our Html Helper and our TagHelper. We may import them either locally in each View using them or globally by adding the import instructions to the Views/_ViewImports.cshtml View. Before the addition the Views/_ViewImports.cshtml file should look like this:

  1. @using IterateTagHelperTest
  2. @using IterateTagHelperTest.Models
  3. @using IterateTagHelperTest.ViewModels.Account
  4. @using IterateTagHelperTest.ViewModels.Manage
  5. @using Microsoft.AspNet.Identity
  6. @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

Add:

@using IterateTagHelperTest.HtmlHelpers
@addTagHelper "*, IterateTagHelperTest"

To get:

@using IterateTagHelperTest
@using IterateTagHelperTest.Models
@using IterateTagHelperTest.ViewModels.Account
@using IterateTagHelperTest.ViewModels.Manage
@using Microsoft.AspNet.Identity
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@using IterateTagHelperTest.HtmlHelpers
@addTagHelper "*, IterateTagHelperTest"

The @addTagHelper "*, IterateTagHelperTest" instruction imports all TagHelpers contained in the Web Site dll(whose name is IterateTagHelperTest).

Testing our TagHelper

No we may finally test our TagHelper. Opens the previously defined Views/Home/TagTest.cshtml View and replace its content with the content below:

@model IterateTagHelperTest.ViewModels.Home.TagTestViewModel
@using IterateTagHelperTest.ViewModels.Home
@{
    ViewBag.Title = "Tag Test";
}

<h2>@ViewBag.Title</h2>
<div>
    <form asp-controller="Home" asp-action="TagTest" method="post" class="form-horizontal" role="form">

        <iterate asp-for="Keywords">
            @using (var s = Html.NextScope<Keyword>())
            {
                var m = s.M;
                <div class="form-group">
                    <div class="col-md-10">
                        <input asp-for="@m().Value" class="form-control" />
                    </div>
                </div>
            }
        </iterate>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <button type="submit" class="btn btn-default">Submit</button>
            </div>
        </div>
    </form>
</div>

Now run the application, and click the “Test” main menu item to go our test page. You should see something like:

TestPage

The TagHelper actually instantiates the template all over the Keywords IEnumerable! The input field names appears correct:

 

Names

Let put a breakpoint in the receiving Action Method of the HomeController to verify that the IEnumerable is bound properly:

 

breakpoint

 

Now let modify a little our Keywords and let submit the form. When the breakpoint is hit let inspect the received model:

 

ModelBinding

 

That’s all for now! The whole project may be downloaded here.

Comments are disabled to avoid spamming, please use my contact form to send feedback:

Stay Tuned!

Francesco

Tags: , , ,

Oct 5 2015

Setup your VS 2015 Based Web Development Environment

Category: JavaScript | Asp.netFrancesco @ 06:17

This time we have a new option to develop and edit our code together with the last version of Visual Studio: Visual Studio Code. A lightweight code editor with both syntax highlighting and intellisense that supports more than 30 languages. It opens .Net development also to Mac and Linux systems, but it is a valid option to VS 2015 also in Windows systems since it opens as fast as notepad and enables you to make quick changes without waiting for VS 2015 initialization. Moreover, it connects easily with Git repositories and Visual Studio on line. Thus, I suggest to add both tools to your development environment. Both VS 2015 Community edition and Visual Studio Code may be freely downloaded here(you may find also further infos and documentation at this link).

The conversion from VS 2013 to VS 2015 is easier than previous migrations, really straightforward, so there are no drawbacks and no reasons for remaining tied to VS 2013.

It is convenient to move to VS 2015 also if you don’t plan to move to Asp.net 5/MVC 6 that are still in beta, since VS 2015 offers interesting enhancements also for old projects. Below I list some of them:

  • Useful suggestions next to errors
  • Performance infos on the line you are debugging. No need to launch performance specific tools to discover performance bottlenecks: you may discover them while you are debugging your application, since VS shows the computer time spent since your last debugging step(previous breakpoint or previous line if you are stepping) next to the line you are debugging. Moreover, on each line you have access to a performance window with several performance infos.
  • Native TypeScript support. In VS 2013, TypeScript compiler and intellisense were accessible through  an extension while in VS 2015 their support is native. However, also if TypeScript compiler is immediately available you have to run manually your compilation, or to write your script to run them automatically. Therefore, I recommend to install also Web Essentials where you may configure TypeScript files for being compiled automatically on project build, or on file save.
  • Require.Js and Angular.Js support (intellisense and error checking).
  • Node.Js support.
  • C# enhancements.

The list above is not exhaustive but collects just the more interesting features for web development. For more infos forrlow the documentation links here.

 

If you use Less(or Scss, JSX, ES6 and CoffeeScript), please notice that VS 2015 Less tools are not included anymore in Web essentials but in a different package.

OOOPSSs I forgot….If you need a repository and a development team support tool you may use a free 5 person Visual Studio On Line account.

 

Thus Summing up:

  1. VS 2015 and Visual Studio Code
  2. Web Essentaials 2015
  3. Node.Js tools for Visual Studio.
  4. Web Compiler extension (Less, Scss, JSX, ES6 and CoffeeScript).
  5. Visual Studio On Line account.

 

That’s all for now!

Enjoy ! In a short time a new series of posts about Asp.Net 5/ Mvc 6

Francesco

Tags: ,

Apr 11 2015

How to Handle Cross-Site Scripting in ASP.NET MVC Application?

Category: Asp.net | MVCCelinSmith @ 22:22
Oops…this is not one of my posts…I invited a friend of mine, to write about Cross Site Scripting attacks. Enjoy!

One common concern that almost all website owners share is maintaining the security of the website. Perhaps, you may adopt commonly practiced and most recommended security techniques to keep your site secure. But, you might not be aware of or overlook the security problems that occurs because of trusting your users too much.

While most of your website, users will perform only the required actions, a malicious user will make every possible effort to obtain access to even most sensitive areas of your site. In this post, we'll discuss about how you can handle Cross Site Scripting (one of the most common security exploit) in ASP.NET Web apps. But before that, let's first discuss in detail about Cross Site Scripting.

Cross Site Scripting – An Overview

Cross Site Scripting (also referred to as XSS) is a kind of vulnerability that occurs when some hacker injects malicious code (ideally script) inside a web page or the database. The insertion of code takes place without the user's knowledge. XSS happens whenever a web application allows to display user's input or input provided by any outside resources without validating the input properly. XSS attacks enables a user to insert malicious JavaScript, HTML and other cross-side scripting languages into a dynamic page – that is not validated.

Here are a few most of the common cross site scripting attacks you should be aware of:

  • Stored XSS (also known as Persistent or Type I): This type of XSS attack occurs when user input remains stored somewhere - in the database, comment field, data forum, etc.
  • Reflected XSS (also known as Non-Persistent or Type II): It takes place when some user input is returned from the server in the form of an error message – including all of the data provided by the user as part of a request made to the server – but without making the data safe for browser rendering.
  • DOM based XSS (or Type-0): Both stored as well as reflected types of XSS attacks come in this category, wherein an attacker makes modifications to the DOM elements and can utilize DOM data.

How to Handle Cross Site Scripting?

There are two different ways following which, you can handle XSS attacks:

1. Check for any XSS vulnerabilities.

One best way to handle cross-site scripting attack requires you to perform a security test on your web applications. In simple words, check out for for any cross-site scripting vulnerabilities. This is where Web Vulnerability Scanner comes in handy. It scans an entire site and perform automatic checks to find out cross-site scripting vulnerabilities. Additionally, it identifies all the URLs/scripts on your site that are vulnerable to XSS attacks, making it easy for you to fix the vulnerability.

One great web vulnerability scanner is “Acunetix Web Vulnerability Scanner” that crawls a site for finding Cross-site Scripting, SQL injection, and other type of vulnerabilities.

2. Prevent XSS attacks from occurring.

Let's consider an example, for avoiding XSS attacks in MVC applications. When any user inserts malicious HTML markup and message into an MVC application, it will display an annoying alert.

image

MVC will reject a user's login request when HTML markup is added in the message box (as shown in the screenshot above). MVC, by default, prevents any requests containing HTML markup, in order to avoid XSS attacks.

image

Now, if you give users the ability to submit HTML markup along with a message, then use any one of the below mentioned approaches:

1st Way (Model Level):

image

2nd Way (Controller Level):

clip_image005

Though, using any of the aforementioned approaches will not execute the request validation part, but you may still encounter a problem: the HTML markup will be encoded.

image

You can fix the problem, using @Html.Raw(item.MessageText).

image

But when allowing a user to write HTML markup with MessageText, you may find some malicious script in the message text, as shown below.

image

image

Now let us talk about how using NuGet packages, you can prevent cross-site scripting attacks from occurring in an MVC application. NuGet is a package manager that comes loaded with tons of packages (or libraries) that make use of a safe approach to HTML encoding. In our case, we'll be using the AntiXSS library.

Open NuGet, and then look for the "AntiXSS" package. Once you've found the package, simply install it.

image

After the installation, you'll be able to see two new libraries in your projects references folder: AntiXssLibrary and HtmlSantizationLibrary.

image

All you need to do is to make a little change in the controller, so as to prevent XSS.

image

That's it! Now, in case any user will try inserting a malicious script with the text message, it will automatically be removed.

image

Conclusion

Hope going through this post will serve as a resourceful guide for developers, looking for ways to handle Cross-site Scripting attacks on their ASP.NET website application.

About the Author:

Celin Smith has been working as a professional asp.net developer with Xicom Technologies Ltd- a leading ASP.Net Development Company offering a range of software solutions like IT Outsourcing Services, Custom Software Development and Web Application Development Services . She has been an avid writer and loves writing interesting and informative stuff on web and mobile applications. You can reach her via her Facebook or @celinsmith1 .

Tags: , ,

Jul 11 2014

Integrate NodeJS tools in Visual Studio/TFS

Category: JavaScript | Asp.netVincenzo @ 03:11

Oops…this is not one of my posts…I invited a friend of mine, Vincenzo, to write about using Node.js tools with Visual Studio. Enjoy!

The presence of NodeJs on TFS online hosted build controller and the recent installation of git client in the platform (suggested by a tweet of mine: https://twitter.com/D3DVincent/status/480968128227074049), and on AppHarbor too (http://support.appharbor.com/discussions/problems/60449-git-binary-in-command-line) opens up new interesting possibilities of integrating Visual Studio and TFS online with the awesome Node JS tools.

In this article I will show you how to set up your Visual Studio and TFS online environment to take advantage of all this.

Note: this is not a NodeJs/tools tutorial. I will assume you have a knowledge about nodejs, npm, bower, tsd, gulp and the packages you're going to install. I will only show you the integration with visual studio.

1) At first, let's make sure to have nodejs installed (www.nodejs.org) with NPM installed and its directories installed into the PATH environment variable.

2) Install a git client (required by bower and tsd) and insert its executables into the PATH environment variable (the current installation package does not set this for you automatically). The most used one on Windows is msysgit (http://msysgit.github.io/), you can find it on WebPlatform too.

clip_image001

clip_image002

clip_image003

Let's make sure that all commands are now available on the command line, by typing its names on the console.

clip_image004

Thanks to this tip, we have now available on Visual Studio console all the tools we need to perform out nodejs tasks.

Prior to see the following steps, I will spend few words on how Npm works.
Unlike nuget, npm has the concept of local and global packages. For this reason, every package installed through this tool can be installed as global (-g flag on the commands). This will make the package available on every directory of your dev machine.

The other option has the same behavior of nuget packages: it will create on your project a new directory called node_modules in which all packages will be stored. You will find a useful .bin directory to all them.

Usually, having packages installed globally is very convenient. In addition, nodejs is smart enough to redirect your commands to the local node_modules directory, if any. This will prevent the usual compatibility issue (more on this, http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation)

Let's now open Visual Studio and work with the new tools installed. We will start with a brand new Asp Net empty web application project.
Unfortunately the package manager console looks like unable to handle interactive commands. So we will have to switch on command line some time.
Go to the package manager console and type this command

npm init

The command will ask us few questions about our new webapplication and write a package.json file for us.

clip_image006

This json file will track all installed package and will be used as a source for restoring packages during a build.

Visual Studio does know nothing about package.json, since we're using an external tool. This file must be included in our source control. I prefer to keep it in the solution too, but this is up to you. Let's go to the solution explorer, show all files and include in solution the package.json file

clip_image007

Now we have npm installed with a repository of over 80 thousand packages. You can browse all of them here: https://www.npmjs.org/.

For a modern web application, I always install these packages from npm repository:

1)Bower (package manager for javascript libraries)

2)Tsd (typescript definitions for javascript libraries)

3)GulpJS (task and automation tools)

npm install bower --save

npm install tsd --save

npm install gulp --save

The --save flag instructs npm to write this installation to packages.json file. If all was done correctly, our file should look like this:

clip_image008

Thanks to these entries, we will be able to perform a package restore on TFS and on our dev machines too.

Since I do not have global packages installed, I have to point the bin directory of node_modules folder.

clip_image010

Let's init tsd too:

clip_image012

And do not forget to include json files into solution.

clip_image013

We're done with interactive commands. We can close command prompt and work comfortably from visual studio and its package manager console.

Next step are just to install packages and tools: I will take jquery and angularjs from bower, their typings from tsd and set up a simple minify task with gulp:

clip_image015

The installed components are, obviously, external to Visual Studio. We have to include them into the project:

clip_image016

In my example, I will include only the highlighted voices. Anyway, the strategy is up to you. If you will select these files, they will be published on Azure or your WebDeployment enabled server. If not, you will have to extend the MsBuild task to include these files.

Now we have a more or less complete development solutions. Install other packages and code your solutions.

Question from .NET developers: why do not use nuget package manager to install DefinitelyTyped Typescript definitions? Well, actually nuget is not able to restore content folder from its packages and developers are not going to cover this use case (you can find more about this issue and why it won’t be fixed here: http://nuget.codeplex.com/workitem/2094. Due to this, we are forced to include into our checkin typings file too. Even if a lot of persons suggests that this is the right thing to do, I do not like this kind of procedure. Switching to the cliend side, I can remove and restore these kind of packages as well and keep under source control only MY app files.

Done that, is time for automation.

At first, let's configure exclusions for TFS source control. We have to add a new .tfignore file in root of our solution and add the following lines:

\NodeJsTools\bower_components
\NodeJsTools\typings

This will exclude these folders from source control, even if they are included into solution file. We do not need to add node_modules since it's completely external.

This means that our hosted source code will miss all nodejs modules and all bower/tsd reference files. In this way, our application will never work (and won't pass the build, since the Typescript target installed into tfs controller will fail: it won't find definitions for angular and jquery).

Here is where MsBuild can help us. We will inject our dependencies task directly on BeforeBuild target.
Tfs controller have got nodejs installed (and npm too) with a git client (needed for bower).

Let's open our project file (.csproj) and let's paste this.

  <Target Name="BeforeBuild">
    <Exec Command="npm install" />
    <Exec Command="node_modules\.bin\tsd reinstall" />
    <Exec Command="node_modules\.bin\bower install --config.interactive=false" />
  </Target>

This target, which will run before build, will install all modules listed into packages.json, then all definitions in tsd.json and all the ones of bower.json. In this way, all references will be fine and the build will pass. Note that I'm using local packages in node_modules since I cannot assume that packages will be installed on tfs hosted build controller.
Let's add these lines too:

  <Target Name="AfterBuild">
    <Exec Command="node_modules\.bin\gulp $(Configuration)" />
  </Target>

These will run my gulp task depending on configuration. In Release, for example, I use to do angular template cache, html and js minification and things like this. In Debug, I usually run jasmine tests. The decision is up to you.

Let's now extend the Clean target to delete also all nodejs stuff. Insert into a PropertyGroup this tag:

     <CleanDependsOn>
        $(CleanDependsOn);
        CleanNodeFiles;
    </CleanDependsOn>

And then let's define this target:

<Target Name="CleanNodeFiles">
      <ItemGroup>
        <TypeScriptGenerated Include="%(TypeScriptCompile.RelativeDir)%(TypeScriptCompile.Filename).js" Condition="!$([System.String]::new('%(TypeScriptCompile.Filename)').EndsWith('.d'))" />
        <TypeScriptGenerated Include="%(TypeScriptCompile.RelativeDir)%(TypeScriptCompile.Filename).js.map" Condition="!$([System.String]::new('%(TypeScriptCompile.Filename)').EndsWith('.d'))" />
    </ItemGroup>

    <Delete Files="@(TypeScriptGenerated)" />
    <RemoveDir Directories=".\build\;.\bower_components\;.\typings\"/>
    <Exec Command=".\tools\DelFolder .\node_modules" />
  </Target>

These lines will delete all typescript generated files and all bower/tsd files.
You may see that node_modules directories and subdirectories are deleted using a DelFolder script and not through the remove dir. This is because node_modules are very deep directory and RemoveDir target cannot delete paths longer that 256 characters. For this reason, I use to include a script in my source control (not in the project, however) with these lines:

@echo off
if \{%1\}==\{\} @echo Syntax: DelFolder FolderPath&goto :EOF
if not exist %1 @echo Syntax: DelFolder FolderPath - %1 NOT found.&goto :EOF
setlocal
set folder=%1
set MT="%TEMP%\DelFolder_%RANDOM%"
MD %MT%
RoboCopy %MT% %folder% /MIR
RD /S /Q %MT%
RD /S /Q %folder%
endlocal

As final task, we may want to add custom files (generated by gulp js tasks for example). We can do it with other few lines of msbuild code:

<Target Name="DefineCustomFiles">
    <ItemGroup>
      <CustomFilesToInclude Include=".\build\**\*.*">
        <Dir>./</Dir>
      </CustomFilesToInclude>
    </ItemGroup>
  </Target>

  <Target Name="CustomCollectFiles">
    <ItemGroup>
      <FilesForPackagingFromProject Include="@(CustomFilesToInclude)">
        <DestinationRelativePath>%(CustomFilesToInclude.Dir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
      </FilesForPackagingFromProject>
    </ItemGroup>
  </Target>

These lines instruct the deployment to include all build folder and place it into the root.
A typical use case is this one:
Usually you have got your html files into solutions and using gulp, you minify your views. Of course you will not save these changes into your project root, or your source files will be modified and not usable (since they are minified).
For this reason, you may want usually to place all modified files into another folder, (in my case, build). Of course, Visual Studio does know nothing about these files since they are completely external to your webapplication. Thanks to this task, we will include these files into WebDeployment and place it into root folder, replacing the "development" files.
This task can be useful to include into deployment the bower_components folder (selecting the appropriate scripts) and removing from your .csproj all the folder reference. This choice is up to you. However, I usually prefer to keep scripts reference into solutions to always have a clear overview of what my webapplication needs to run up.

Ok, let's casting out nines: clean your project and verify that all nodeJs folders are gone. It may take a bit since the robocopy script is slower than a simple directory delete. Then build your project and all the stuff should be in its place.

You can find all the source code for this demo cloning this repository: https://github.com/XVincentX/NodeVStudio
Good. We're done. Have fun.

 

P.S: The project is evolving: have a look here -> https://github.com/XVincentX/NodeJsMsBuild
P.S2: I was mentioned in Morning Brew and Asp.Net site too!

image image

Tags: , ,

Jun 21 2014

New Versions of Mvc Controls Toolkit and Data Moving Controls Suite

Category: Asp.net | Javascript | MVC | WebApiFrancesco @ 21:43

New 3.0.0 release of the Mvc Controls Toolkit. See the list of changes.

New 1.2 release of the Data Moving Controls Suite. See the list of changes.

 

Enjoy!

Francesco

Tags: , , ,

Feb 18 2014

Data Moving Mvc Control Suite Available for Purchase!

Category: WebApi | MVC | JavaScript | Asp.netFrancesco @ 06:54

Finally, the Data Moving Controls Suite is available for purchase! Not only, several powerful asp.net mvc controls easy to configure with a fluent interface and easy to style with your favourite framework (supported: jQuey UI, JQuery Mobile and Twitter Bootstrap), but also, a complete Single Page Application Framework. A sophisticated validation framework that extends the standard server/client asp.net mvc validation framework, the possibility to store control settings to reuse them in several pages, futuristic user interfaces based on Interaction Primitives, and more...

Hurry Up 25% off till 2014-4-31! 

Try to win your license by solving the Triangles Enumeration Problem.

Tags: , , ,

Mar 20 2013

Single Page Applications 3: TreeIterator

Category: Asp.net | MVCFrancesco @ 23:08

Data Moving Plugin Controls

Data Moving Plugin Styling

Data Moving Plugin Forms: Detail Views, Data Filtering UI, and Undo/Redo Stack

Single Page Applications 1: Manipulating the Client Side ViewModel

Single Page Applications 2: Validation Error Handling

Single Page Applications 3: TreeIterator

Client templates instantiation is one of the techniques used to implement SPA applications: The initial page contains just a minimum Html, and the remainder of the Html is created dynamically by instantiating client templates on data items. Typically, template instantiations are triggered by actions executed by javascript code. The Data Moving Plug-in offers a simple way to create dynamically all Html of a SPA, in a declarative data-driven fashion. The TreeIterator helper scans a hierarchical data structure and decides  which template to use for each data element it meets during this processing. The developer is required to provide just a list of templates, and a function that selects a template given a data item. After that, the provided templates are used as building blocks to produce the whole UI of the page (or of a part of the page) as soon as a new client ViewModel(or a new part of it, such as a Workspace) is sent to the client side.

Since the Mvc Controls Toolkit, and consequently the Data Moving Plug-in that is built on top of it, are able to compile any Razor template into a client side template, we can put everything in the templates provided to the TreeIterator: paged grids and/or complex controls such as Dual selects , or whole Data Moving Forms.

We will see how the TreeIterator works with a simple example: automatically building a multipage JQuery mobile menu based on nested lists, from the information contained in a hierarchy of objects. We will use the Mvc Controls Toolkit SimpleMenuItem class to define each menu item:

  1. public class SimpleMenuItem
  2. {
  3.     public SimpleMenuItem();
  4.  
  5.     public List<SimpleMenuItem> Children { get; set; }
  6.     public string Link { get; set; }
  7.     public string Target { get; set; }
  8.     public string Text { get; set; }
  9.     public string UniqueName { get; set; }
  10. }

 

As first step we declare all needed templates:

  1. var menuTemplates = h.DeclareClientTemplates("mobile_menu")
  2.                 .Add<SimpleMenuItem>(
  3.                 @<ul data-role="listview" id="menuRoot">
  4.                         @item.RecurIterationOn(m => m.Children)
  5.                               </ul>
  6.                 )
  7.                 .Add<SimpleMenuItem>(
  8.                 @<li >
  9.                         @item._D(m => m.Text)           
  10.                 </li>
  11.                 )
  12.                 .Add<SimpleMenuItem>(
  13.                 @<li >
  14.                     @item.LinkFor(m => m.Text, m => m.Link)            
  15.                 </li>
  16.                 )
  17.                 .Add<SimpleMenuItem>(
  18.                 @<li >
  19.                     @item.LinkFor(m => m.Text, m => m.Link, target: m => m.Target)          
  20.                 </li>
  21.                 )
  22.                 .Add<SimpleMenuItem>(
  23.                 @<li >
  24.                     @{var mitem = item.ViewData.Model;}
  25.                     @item._D(m => m.Text)
  26.                     <ul data-role="listview">
  27.                         @item.RecurIterationOn(m => m.Children)
  28.                                     </ul>
  29.                 </li>
  30.                 );

This task is easily accomplished with the fluent interface of the DeclareClientTemplates helper. The unique argument of this helper is the templates base name. All templates are named by adding an integer suffix to this base name: the firts template is named “mobile_menu0”, the second one “mobile_menu1”, and so on.

Our first template defines the startup template, that is, the initial template that starts the rendering. The startup template is not necessarily the first one, but the startup template is declared in the call to the TreeIterator helper.

Then we have the template to use for displaying pure text, then the template of a menu item that links to a target page, then then the template of a menu item that links to a target page to be opened in a new browser window, and finally the template to be used for a menu item that has sub-menu items.

As you can see both the startup template and the last template call RecurIteration on the children of the current SimpleMenuItem. This is the way the TreeIterator visits recursively, the whole data structure. In general, each, template may contains several calls to RecurIteration if the object has several children arrays.

Once we have defined all templates we need just to render them:

  1. @menuTemplates.Render("menuTemplateChoice")

The single argument of the Render method is the name of the javascript function that selects the template to use for each data item:

  1. function menuTemplateChoice(item) {
  2.     if ((!item.Children()) || item.Children().length == 0) {
  3.         if (item.Link()) {
  4.             return item.Target() ? 'mobile_menu3' : 'mobile_menu2';
  5.         }
  6.         else return 'mobile_menu1'
  7.     }
  8.     else return 'mobile_menu4';
  9. }

The above code is self-explanatory.

Finally, we may call the TreeIterator helper that "will do the job”:

  1. @h.ClientTreeIteratorFor(m => m, "mobile_menu0", "listviewAfterRender")

The first argument is the root of the objects hierarchy, the second argument is the name of the startup template, and finally the third argument is a javascript function to be called after the whole objects hierarchy has been rendered. In our case the listviewAfterRender javascript function enhances the <ul> <li> nested list created by the ClientTreeIteratorFor transforming them into a JQuery mobile nested listview:

  1. function listviewAfterRender() {
  2.         $('#menuRoot').hide();
  3.         setTimeout(function () { $('#menuRoot').listview(); $('#menuRoot').show(); });
  4.     }

The nice part, is that as soon as we substitute the root of the objects hierarchy with a different data item the UI of the menu is changed immediately to reflect the new settings.

In this example all templates were pre-rendered in the host Html page, however, in more complex multi-page applications templates may be organized in modules and loaded dynamically together with AMD javascript modules.

The video below shows the menu working:

 

That’ all for now!

Stay tuned and give a look also to all other Data Moving Plug-in introductory tutorials and videos

                      Francesco

Tags: , , , , , ,

Mar 19 2013

Single Page Applications 2: Validation Error Handling

Category: MVC | Asp.netFrancesco @ 22:30

Data Moving Plugin Controls

Data Moving Plugin Styling

Data Moving Plugin Forms: Detail Views, Data Filtering UI, and Undo/Redo Stack

Single Page Applications 1: Manipulating the Client Side ViewModel

Single Page Applications 2: Validation Error Handling

Single Page Applications 3: TreeIterator

This is the second half of the tutorial Single Page Applications 1: Manipulating the Client Side ViewModel that describes the enhancements added to the standard asp.net Mvc validation error engine by the Data Moving Plug-in. We advice to assist the video associated to this introductory tutorial before reading it:

In the Data Moving Plug-in validation rules, and error handling are coded with the usual tools of Asp.net Mvc, such as Data Annotations (or Fluent validation), by adding errors to the ModelState, etc. Also client side validation is based on the jquery validation plug-in. However, all this tools have been enhanced in several ways. First of all, server errors are returned also as a result of JSon updates, and dispatched to the right places in the UI (thanks to the updatesManagers that handle the updates). Moreover, also elements that are detached from the Dom, and rendered again by instantiating  client templates “remember” their error state thanks to parallel data structures that takes care of this “job”.

Probably, the more interesting enhancement is “error bubbling”. What is “error bubbling”? Suppose you need to report an error to the property AllProgrammers[1].EMail, that is to the Email of the second programmer of the programmers list. Well, since the grid has no visible Email column, the error cant be shown! In order to overcome this problem the error is bubbled up to the whole entity level:  AllProgrammers[1]. Now since we added an error column to the programmers grid the user can see the second programmer has an error:

  1. .AddErrorColumn(m => m, "*", width: 20)

Since we put m => m the error column is triggered by whole entity level errors. This way also errors in fields that are not shown in a grid row can be signalled to the user. Error bubbling is useful also in TreeViews/TreeGrids because an error happening in a child entity is signalled also in its father entity, so the user may open the right branch of the tree to find the children entity in error.

Error bubbling is automatically applied to both the errors returned by the server and to client side validation errors.

What if the user want to know exactly which among the fields that are not shown in the grid is in error in order to correct the error? Simple! He just shows the entity in error in a detail view, and thanks to the errors synchronization behavior with detail views provided by the data moving plug-in he will see the error in the detail view!

Another interesting feature is Error Filtering. All Data Moving plug-in controls that have been enhanced with a retrievalManager, have error filtering capabilities. This means, they respond to a “show just entity in error” filtering command that can be issued with a button in a toolbar. This way the user can review all errors by browsing the list of all entities in error.

Everything works properly because the Data Moving engine “remembers” the error state of a field also if the entity the field in error belongs to is removed from the Dom, for instance, because of paging.

In order to minimize the round-trips to the server the Data Moving Plug-in offers the possibility to add entity level validation rules, and whole Core Workspace validation rules directly on the client side.

Below the addition of an entity level validation rule to the programmers updatesManager:

 

  1. TeamBuilding.programmersUpdater.options({ itemErrors: function (x) {
  2.         if (x.CanBeTeamLeader() && (!x.Experience() || x.Experience() < 7))
  3.             return ["A 7 years experience is required to be a Team Leader"];
  4.         else return null;
  5.     }
  6.     });

Validation errors are specified through a function that receives an entity as argument and returns an array of errors. Error dispatching in the adequate place of the UI is done automatically by the Data Moving plug-in engine.

Below the definition of a Core Workspace level validation rule in the whole Workspace updatesManager:

  1. TeamBuilding.ClientModel, "ProposedTeam", TeamBuilding.DestinationModel, "ProposedTeam",
  2. { updatersIndices: [TeamBuilding.programmersUpdater, TeamBuilding.artistsUpdater],
  3.     {
  4.     ......
  5.     ......
  6.     Errors: function (model) {
  7.         if (model.LeaderProgrammer() && model.LeaderArtist()) return null;
  8.         else return ["The team is incomplete"];
  9.     }
  10. });

We can also specify an error callback that is invoked with a data structure containing information on the errors as argument whenever there are errors in the Workspace :

  1. onObjectErrors: function (errorObjects) {
  2.                  alert("Click the error button to show errors that are not visible on the screen");
  3.              }

That’ all for now!

Stay tuned and give a look also to all other Data Moving Plug-in introductory tutorials and videos

                      Francesco

Tags: , , , , , , ,

Mar 18 2013

Single Page Applications 1: Manipulating the Client Side ViewModel

Category: Asp.net | MVC | WebApiFrancesco @ 21:46

Data Moving Plugin Controls

Data Moving Plugin Styling

Data Moving Plugin Forms: Detail Views, Data Filtering UI, and Undo/Redo Stack

Single Page Applications 1: Manipulating the Client Side ViewModel

Single Page Applications 2: Validation Error Handling

Single Page Applications 3: TreeIterator

This is the first of 3 introductory tutorials about the features for handling Single Page Applications offered by The Data Moving Plugin. The Data Moving Plugin is in its RC stage and will be released to the market in about one month.

Firs of all just a little bit theory….then we will move to a practical example. If you want, you may give a look to the video that shows the example working before reading about the theory:

See this Video in High Resolution on the Data Moving Plug-in Site

 

Typically an SPA application allows the user to perform several tasks without leaving its physical Html page. This is result may be achieved by defining several “virtual pages” inside the same physical page. During the whole lifetime of the application just an active virtual page is visible, all other pages are either hidden or completely out of the Dom because they are created dynamically by instantiating client templates. The active page interacts with just a part of the Client Side ViewModel, and only that part is kept in synchrony with the server. 

One can use also different techniques to enable the user to perform several tasks without leaving the l Html physical page; in any case the client ViewModel may be partitioned into subparts that are the smallest “units” that may be sinchronized with the server independently of the remainder of the client side ViewModel. We call such elementary units Workspaces because they are the “data units”  manipulated by the user while he is performing one of the several tasks allowed by the SPA.

A workspace, in turn, is composed of two conceptually different sub-parts: a kind of short living data structure that is used just to carry out the current task and a set of long living data structures that are typically connected with a Database on the server side. Typically, on the client side, we don’t have all long living entities  of a “given type” but just a small window of the whole Entity Set. We call Entity Set Window, the set of all long-living entities of the same type stored in the Client Side ViewModel, and we call Core Workspace the part of the Workspace that remains after removing all Entity Set Windows.

Summing up, the Client side ViewModel is composed of partially overlapping Workspaces, that are in turn composed of a Core WorkSpace and several Entity Set Windows.

In general we can’t assume that all data of the Workspace are someway visible in the user interface. In fact the task being performed currently by the user may be composed of several steps (just think to the steps of a wizard), and substantially just the data “used” in the current step are visible to the user. Accordingly, each Workspace may be further split into partially overlapping UI Units, where each UI Unit is a part of the workspace that is “visible” in the user interface at a given time.

The concept of UI Unit is very important in error handling because, while all UI Units belonging to a Workspace must be submitted simultaneously to the server, only the errors that refer to the current UI Unit can be shown to the user.

The Data Moving Plug-in, offers tools to handle properly Entity Set Windows, Core Workspaces, and for handling properly UI Units during validation error processing:

  1. Retrieval Managers takes care of browsing Entity Sets in the Entity Set Windows, while updatesManagers take care of keeping the Entity Set Windows synchronized with the server by processing updates performed by the users to the Entity Set Windows, and by dispatching the principal key of newly created entities returned by the server.
  2. Whole WorkSpace updatesMangers take care of keeping a whole Workspace synchronized with the server, by automatically issuing commands to the updatesManagers of all Entity Set Windows contained in the Workspace and by taking care “personally” of the Core Workspace.
    The communication protocol between a whole Workspace updatesManager and the server includes the possibility for the server to issue “remote commands” that modify the Core Workspace on the client side. In fact, often, it is not possible for the server, to send a whole “updated” Core Workspace to the client that substitutes completely the old one, because the Core Workspace might have “links” with UI elements and with other Client Side ViewModel data, and a similar substitution would break them.
  3. The Data Moving Plug-in provides a powerful dom element-to-dom element data binding engine that enables the user to trigger “interactions” between dom elements,  and provides also a  Reference Knockout binding that maps UI elements to sub-parts of the Workspace, in such a way that the user “move” such parts of the Workspace by simply moving the UI elements that represent them in an intuitive way. The dom element-to-dom element data binding engine has been already described in a previous tutorial and in a previous video, so in this tutorial we will focus mainly on the Reference binding.
  4. Error Bubbling, Entities in Error Filtering, and other enhancements of the standard Asp.net Mvc validation engine help in associating errors to data that are not immediately visible on the screen. Error handling will be described in the second tutorial about SPA applications:  Single Page Applications 2: Validation Error Handling.

Let understand better how all this works with a simple example(the same shown in the video above).

Suppose we have a list of artists and a list of programmers, that are completely stored in the client side view model, and let suppose we would like to build a team to face a web project made of both artists and programmers. The team will have both a leader programmer and a leader artist, and not all people are entitled to cover the role of leader. Below a screen shot with an indication of the UI elements that represent data of the Core Workspace and data of the Entity Set Windows:

TeamBuilding

In the programmers tab there is another Entity Set Window containing Programmers Entities. Since we said all programmers and all artists are contained in the client ViewModel the Entity Set Windows  contain the whole Entity Sets. Moreover, since both the list of all programmers and the list of all artists are paged, not all all programmers and not artists belong to the current UI Unit; this means we will have difficulties in showing possible errors related to artists and programmers that are not in the current page.

As we can see in the video new people may be added to the Team being built by simply dragging them in the “Members” area. if a new Leader is selected, the old leader is automatically moved back in the original list. People that can cover the role of leader have a yellow border, and the two Leader areas accept only people entitled to cover the Leader role. Moreover, the artists area of the team accepts just artists while the programmers area of the team accepts just programmers.

The whole team building UI logics with the constraints listed above has been obtained without writing a single line of procedural code, but by just declaring reference bindings, Drag Sources, and Drop Targets.

For instance, below the definition of the leader programmer area:

  1.   <div id="leader_programmer"class='leader-container programmers ui-widget-content' data-bind="@bindings.Reference(m => m.ProposedTeam.LeaderProgrammer).Get()">
  2.     @ch._withEmpty(m => m.ProposedTeam.LeaderProgrammer, ExternalContainerType.div, existingTemplate: "ProgrammerTemplate0")
  3. </div>
  4. @Html.DropTarget("#leader_programmer", new List<string> { "LeaderProgrammer" }, rolesDropOptions)

The reference binding maps the div named “leader-programmer” with the property of the Core Workspace ProposedTeam.LeaderProgrammer, while the DropTarget declaration makes it accepts Drag Sources tagged as “LeaderProgrammer”. As a consequence of this two declarations when a UI element representing a programmer entitled to cover the role of leader (ie that has the “LeaderProgrammer” tag) is dragged over this are it is “accepted”, and the data item tied to the dragged UI element with another reference binding, is moved into the knockout observable of the ProposedTeam.LeaderProgrammer property. This in turn triggers the instantiation of the programmerTemplate0 client template because of the _withEmpty instruction that is an enhancement of the knockout with binding.

The ProgrammerTemplate0 templates is the client template automatically built by the grid on the left of the page that lists all programmers. As a consequence the chosen leader programmer is rendered in the “Leader Programmer” area with the same appearance he had in the grid. Each member area works in a similar way:

  1. <div class="members-container programmers ui-widget-content" id ="all_programmers" data-bind="@bindings.Reference(m => m.ProposedTeam.Programmers).Get()">
  2.     @ch._foreachEmpty(m => m.ProposedTeam.Programmers, ExternalContainerType.div, existingTemplate: "ProgrammerTemplate0")
  3. </div>
  4. @Html.DropTarget("#all_programmers", new List<string> { "Programmer" }, rolesDropOptions)

However in this case the ProposedTeam.Programmers property used in the reference binding is an observable array, so the dragged element is pushed into this array. Instead of the _withempty, we have a _foreachEmpty that is an enhancement of knockout foreach binding.

 

To makes everything works properly all programmers must be declared as Drag Sources tagged with “Programmer”. Moreover, all programmers entitled to cover the role of leader must have also the “LeaderProgrammer” tag:

  1. @Html.DragSourceItems(".programmers", ".simple-list-item", new List<string> { "Programmer" }, new DataDragOptions { DestroyOriginal = true, AppendTo = "body" })

The above declaration basically says: “define all elements marked with the class “simple-list-item”  that are descendants of the dom element with class “programmers” as Drag Sources with tag “Programmer”. Now since the whole grid containing all programmers is under a div with class “programmers” and since all rows of this grid have the class “simple-list-item” all programmers are all defined as Drag sources.

The request is extended also to future elements that will be added as descendants of the element with class “programmers“, thus if we insert new elements in the grid they will be automatically declared as Drag Sources.

The “simple-list-item” class is added to each row of the grid as a part of its row definition instructions with:

  1. .ItemRootHtmlAttributes(new Dictionary<string, object> { { "class", "simple-list-item" } })

About the “LeaderProgrammer” tag, it must be added to all data items with the property CanBeTeamLeader set to true. Since this property may change during processing we must add it with a knockout binding attached to the CanBeTeamLeader property:

  1. .KoBindingsGenerator(bb => bb.CSS("LeaderProgrammer", l => l.CanBeTeamLeader)
  2.     .Reference(m => m)
  3.     .Get().ToString())

The KoBindingsGenerator is a method of the fluent interface of the grid row definition. It accepts a function of the type

  1. Func<IBindingsBuilder<U>, string> knockoutBindings

and applies the knockout bindings defined in the body of the function to all rows of the grid, by adding them to the client row template being built by the grid. We use the IBindingsBuilder interface received as argument to build a standard Knockout Css binding that adds the css class “LeaderProgrammer” whenever the property CanBeTeamLeader is true, and a Reference binding that bind each row to its associated data item. The Reference binding enables the “Dragged” programmer to “release” its referred data to the data item referred by the “Drop Traget”.

Since in the options of the DragSourceItems declaration we set DestroyOriginal to true a dropped programmer is removed from the programmers list.

When we put a new Leader Programmer in the Leader Programmer area, the old Leader programmer returns back to the programmers list because we defined the Programmers list as mirroring pool for the programmers entities (this is done in javascript):

  1. ko.mirroring.pool = function (obj) {
  2.     var dis = obj["MainCompetence"];
  3.     dis = ko.utils.unwrapObservable(dis);
  4.     if (dis === "Artist") return TeamBuilding.ClientModel.AllArtsist.Content;
  5.     else if (dis === "Programmer") return TeamBuilding.ClientModel.AllProgrammers.Content;
  6.     else return null;
  7. };

All mirroring pools are defined by assigning a javascript function to the ko.mirroring.pool configuration variable. This function is passed all items that were removed from their places because of a Reference binding based interaction and that were put in no other place, so they “disappeared” from the client side ViewModel. This function is their last chance to find an “home”. This function analyze all properties of each item and possibly find a new “home” for it.

Moving either an artist or a programmer in the detail area assigns a reference to its associated data item to the knockout observable CurrentDetail in the client ViewModel without detaching the data item from its previous place, because in this case the DestroyOriginal option of the drop target is not set to true. This triggers the instantiation of a template that shows the data item in detail mode:

  1. @ch._with0(m => m.CurrentDetail,
  2.     @<text>
  3.         <p>
  4.         <span class='ui-widget-header'>@item.LabelFor(m => m.Name)</span>
  5.         :
  6.         @item.TypedEditDisplayFor(m => m.Name, simpleClick: true)
  7.         @item.ValidationMessageFor(m => m.Name, "*")
  8.         </p>
  9.         <p>
  10.         <span class='ui-widget-header'>@item.LabelFor(m => m.Surname)</span>
  11.         :
  12.         @item.TypedEditDisplayFor(m => m.Surname, simpleClick: true)
  13.         @item.ValidationMessageFor(m => m.Surname, "*")
  14.         </p>
  15.         <p>
  16.         <span class='ui-widget-header'>@item.LabelFor(m => m.EMail)</span>
  17.         :
  18.         @item.TypedEditDisplayFor(m => m.EMail, simpleClick: true)
  19.         @item.ValidationMessageFor(m => m.EMail, "*")
  20.         </p>
  21.         <p>
  22.         <span class='ui-widget-header'>@item.LabelFor(m => m.Address)</span>
  23.         :
  24.         @item.TypedEditDisplayFor(m => m.Address, simpleClick: true)
  25.         @item.ValidationMessageFor(m => m.Address, "*")
  26.         </p>
  27.         <p>
  28.         <span class='ui-widget-header'>@item.LabelFor(m => m.CanBeTeamLeader)</span>
  29.         :
  30.         @item.CheckBoxFor(m => m.CanBeTeamLeader)
  31.         </p>
  32.     </text>
  33. , ExternalContainerType.koComment, afterRender: "mvcct.ko.detailErrors", forceHtmlRefresh: true, isDetail: true)

The _with0 instruction is a different enhancement of the knockout with binding, that accepts an in-line razor helper as client template. Among its arguments there is one named isDetail that we set to true, to inform the Data Moving Plug-in engine that the template is the detail view of a data item. This declaration triggers a synchronization behavior between the original UI of the data item and its detail view.

 

Having finished describing how the user can manipulate the Workspace we can move to see how server-client interaction takes place. The two Entity Set Windows of the Workspace are implemented with two grids. For a detailed description about how to “code” grids you may refer to Data Moving Plugin Controls. Here we point out just that since all data items are already on the client side we must use a local retrievalManager to execute the paging, sorting and filtering queries:

  1. .StartLocalRetrievalManager(m => m.AllProgrammers.Content, true, "TeamBuilding.programmersRM").EndRetrievalManager()

The first argument is the source of all items to be queried(a property of the client side ViewModel), the second argument set to true requires the execution of an initial query as soon as the page is loaded (in order to show some initial data in the grid), and the third argument is where to put the newly created retrievalManager.

The updatesManager of the two grids are both root updatesManager since our items are not children of any one-to-many relation, as in all other examples we have seen in Data Moving Plugin Controls. However, in this case they don’t communicate directly with the server, because we will define a whole WorkSpace updatesManager that will take care of collecting data from the two grids updatesManagers, handling the updates of the Core WorkSpace, communicating with the server, and dispatching the responses of the server to the two grids updatesManagers.

The definition of the programmers updatesManager is:

 

  1. .CreateUpdatesManager<TeamBuildingDestinationViewModel>("TeamBuilding.programmersUpdater", true)
  2.     .BasicInfos(m => m.Id, m => m.ProgrammersChanges, "TeamBuilding.DestinationModel")
  3.     .IsRoot(Url.Action("UpdateTeam"))
  4. .EndUpdatesManager()

It appears more complex of the updates managers we have seen in Data Moving Plugin Controls. The first call to CreateUpdatesManager contains the whole path where to store the updatesManager on the client side instead of the name of the property of the ViewModel where to store it, that’s why the second optional parameter is set to true. Moreover, the method call contains a generic type instantiation, the viewmodel we will use to submit all changes to the server:

  1. public class TeamBuildingDestinationViewModel
  2. {
  3.     public Team ProposedTeam { get; set; }
  4.     public OpenUpdater<Employed, Guid?> ProgrammersChanges { get; set; }
  5.     public OpenUpdater<Employed, Guid?> ArtistsChanges { get; set; }
  6. }

The first property will be filled with the whole Core Workspace, while the other two properties will be filled with the programmers and artists change sets. That’s why the call to BasicInfos has two more parameters after the specification of the principal key: the first parameter is the property of the destination ViewModel where to store the programmers change set, and the third parameter is the property of the whole client ViewModel where to put the destination viewmodel before sending it to the server. The IsRoot method contains a fake url since the destination ViewModel will be posted to the server by the whole Workspace updatesManager.

The whole Workspace updatesManager must be defined in javascript since it is not tied to any specific Data Moving Plugin control:

  1. $('#outerContainer').attr('data-update'),
  2.  TeamBuilding.ClientModel, "ProposedTeam", TeamBuilding.DestinationModel, "ProposedTeam",
  3.  { updatersIndices: [TeamBuilding.programmersUpdater, TeamBuilding.artistsUpdater],
  4.      classifyEntity: function (x) {
  5.          if (x['Id'] && x['MainCompetence'])
  6.              return x.MainCompetence() == "Programmer" ? 0 : 1;
  7.          else
  8.              return null;
  9.      },
  10.      ........

The first argument is the url where to submit the destination ViewModel that is extracted from an Html5 attribute of a dom element. The second argument is the whole client ViewModel and the third argument is the path where to find the Core Workspace within the whole client ViewModel. The fourth argument is the destination ViewModel, and the fifth argument is the path to the place where to store the Core Workspace within the destination ViewModel. Then we have an option argument with several properies. Here we analyze just three of them, since all others are connected to error handling that will be discussed in Single Page Applications 2: Validation Error Handling.

UpdatersIndices is an array containing all updatersManager of the Entity Set Windows of the Workspace; in our case the updatesManagers of the two grids.

classifyEntities is a function that given an entity must return the index in the previous array of its Entity Set Windows updatesManager. This function enables the whole Workspace updatesManager to process adequately all entities it find inside the Core WorkSpace.

That’s enough for everything to work properly! When the user clicks submit the update method of TeamBuilding.updater is invoked, the destination ViewModel is filled, and submitted to the server. When the server send the response the parts of the response destined to the Entity Set Windows updatesManagers will be automatically dispatched to them, and processed automatically. As a consequence, modifications to the the Core Workspace returned as remote commands by the server are applied, keys created for newly inserted entities are dispatched each to its entity, and errors associated to various data elements are dispatched next to the adequate UI elements:

  1. $('#submit').click(function () {
  2.         var form = $(this).closest('form');
  3.         TeamBuilding.ClientModel.CurrentDetail(null);
  4.         if (form.validate().form()) {
  5.             TeamBuilding.updater.update(form);
  6.         }
  7.     });

Let give a look to the action method:

  1. public HttpResponseMessage Post(TeamBuildingDestinationViewModel model)
  2.         {
  3.             if (ModelState.IsValid)
  4.             {
  5.                 try
  6.                 {
  7.                     var builder = ApiResponseBuilder.NewResponseBuilder(model, ModelState, true, "Error in client request");
  8.                     builder.Process(m => m.ArtistsChanges, model.ProposedTeam, m => m.Id);
  9.                     builder.Process(m => m.ProgrammersChanges, model.ProposedTeam, m => m.Id);
  10.                     //business processing here
  11.  
  12.                     var response = builder.GetResponse();
  13.                     return response.Wrap(Request);
  14.                 }
  15.                 catch (Exception ex)
  16.                 {
  17.                     ModelState.AddModelError("", ex.Message);
  18.                     return
  19.                         Request.CreateResponse(System.Net.HttpStatusCode.InternalServerError, new ApiServerErrors(ModelState));
  20.                 }
  21.             }
  22.             return Request.CreateResponse(System.Net.HttpStatusCode.InternalServerError, new ApiServerErrors(ModelState));
  23.         }

This code is very similar to the code we have seen in the action methods that processes the grids updates in Data Moving Plugin Controls: we create an ApiResponseBuilder and then we call the Process method on each of the Entity Set change sets we received in the destination ViewModel. Since our principal key are Guids we dont need to specify a custom key generation function, so the indication of which property is the principal key suffices. However, now the Process methods has 3 arguments, instead of two. We used a different overload! An overload that accepts a Core WorkSpace as second argument. Why we need this further argument? Simple, because we have to process also the changes of the entities that are contained in the Core WorkSpace. In fact, a programmer or artist that we added to the Team might have been modified, or it might be a newly inserted item. The addition of the new argument enables the Process method to include also the entities contained in the Core WorkSpace  in the change sets in their appropriate places if this is necessary.

 

Now suppose we want to modify the client side Core WorkSpace by changing all programmers names with the suffix “Changed” and by adding two more programmers to the team. We need to add adequate remote commands in the response. How to built them? Quite easy! It is enough to create a changes builder object and then to mimic these operations on it:

  1. var changer = builder.NewChangesBuilder(model.ProposedTeam);
  2.  
  3. changer.Down(m => m.Programmers)
  4.     .UpdateModelIenumerable(m => m, m => m.Name, (m, i) => m.Name + "Changed");
  5. changer.UpdateModelField(m => m.LeaderProgrammer, m => m.Name, model.ProposedTeam.LeaderProgrammer.Name + "Changed");
  6. changer.Down(m => m.Programmers)
  7.     .AddToArray(m => m[0],
  8.         new Employed()
  9.         {
  10.             Id = Guid.NewGuid(),
  11.             MainCompetence = "Programmer",
  12.             Name = "John1",
  13.             Surname = "Smith1",
  14.             Address = "New York, USA",
  15.             EMail = "John@dummy.us",
  16.             CanBeTeamLeader = true
  17.         }, 0, true).AddToArray(m => m[0],
  18.             new Employed()
  19.             {
  20.                 Id = Guid.NewGuid(),
  21.                 MainCompetence = "Programmer",
  22.                 Name = "John2",
  23.                 Surname = "Smith2",
  24.                 Address = "New York, USA",
  25.                 EMail = "John@dummy.us"
  26.             }, 0, true);

The first instruction modifies the names of the programmers that are simple members of the team(actually it just creates the remote command to do this). We go down the Programmers properties of the Core Workspace and then call the UpdateModelIEnumerable that applies a modifications to all elements of an IEnumerable. The first argument specify the IEnumerable to be modified; since we already moved into the IEnumerable it is just m => m. The second argument specifies the property of each element that must me modified and the third argument specifies how to modify it.

The second instruction modifies the LeaderProgrammer name.  It is self-explanatory.

Finally, the third instruction adds two more programmers. We move down the Programmers property, and then we call AddToArray twice. The first argument of each call specifies the place in the javascript array where to place the newly added element: in our case we place it at index 0….but wait …wait wait, since the last argument of the call is set to true the enumeration starts from the bottom, so we are just queuing the new elements at the bottom of the array.

Now in order to include all “remote commands” in the response we must substitute:

  1. var response = builder.GetResponse();

with:

  1. var response = builder.GetResponse(changer.Get());

However, we have a problem, the two programmers that we added to the team might be already contained in the programmers list so we might have an entity duplication in the client side View Model. Luckily, the Data Moving Plug-in offers tools to enforce  uniqueness.we may trigger the processing that enforce uniqueness of entities in onUpdateComplete callback of the whole WorkSpace updatesManager (defined in its options):

  1. onUpdateComplete: function (e, result, status) {
  2.     if (!e.success) return;
  3.     var hash = {};
  4.     mvcct.updatesManager.utils.entitiesInWorkSpace(TeamBuilding.ClientModel.ProposedTeam, hash);
  5.     TeamBuilding.programmersUpdater.filterObservable(hash);
  6.     TeamBuilding.artistsUpdater.filterObservable(hash);
  7. },

The mvcct.updatesManager.utils.entitiesInWorkSpace method extracts all entities contained in the core workspace, and index them into an hash table. After that, each Entity Set updatesManager ensures they are not contained in the Entity Set Window it takes care of. The task is carried out efficiently because of the indexing performed by mvcct.updatesManager.utils.entitiesInWorkSpace .

That’ all for now!

Stay tuned and give a look also to all other Data Moving Plug-in introductory tutorials and videos

                      Francesco

Tags: , , , , , ,