MVC Single Page Application Template Update for ASP.NET and Web Tools 2012.2 RC

MVC Single Page Application Template Update for ASP.NET and Web Tools 2012.2 RC

Rate This
  • Comments 6

We added a C# MVC Single Page Application (SPA) template in ASP.NET Fall 2012 Update BUILD Preview. John Papa had written a detailed blog about the preview version. With help of John Papa’s detailed feedback and sample code, we’ve rewritten and reorganized the JavaScript code to make it more structured in RC. We really appreciate the help from John Papa. He just wrote another blog about SPA template in RC version.

The major improvement for the MVC Single Page Template RC release includes the following:

1. Added VB MVC SPA template for .net framework 4.5 and 4.0.

2. Added WebAPI HelpPage support

3. Moved all the application specific JavaScript files to Scripts/app folder

4. Redo the datacontext, model and viewmodel files to make cleaner separation of data access, model and viewmodel layers

5. Created a namespace for the app called "todoApp"

6. Updated the knockout Nuget packages

 

Let’s discuss the important components for MVC SPA template using C#.

Introduction

The MVC SPA template is actually a sample application to demonstrate how to build a SPA application with MVC Web API. The application is able to create, read, update and delete (CRUD) todo-list with todo-items in each list for authenticated users.

At the server side, we use MVC Web API to create the scaffolding of our todo-list and todo-items models.

At the client side, we use Knockout JS framework and binding syntax to demo the Model-View-View Model pattern for SPA. We use JQuery $.ajax to send and receive JSON requests between client data access layer and server’s Web API layer. If you have not used KnockoutJS, you can use the links from the reference section to learn it.

To use the template, just choose “Single Page Application” template when you creates a new ASP.NET MVC 4 Project.

clip_image002 

Layers

Server models

We have 2 basic entity framework models TodoItem and TodoList.

clip_image003

 

TodoList entity contains a list of TodoItems.

clip_image004

 

TodoItem entity has a foreign key TodoListId and a virtual TodoList to represent the relationship with TodoList entity.

clip_image005

The default JSON/XML serialization of these two models, however, will run into circular reference problems. Here are a few solutions to solve them. If the project only uses JSON, it can be solved quite simply by adding a “[JsonObject(IsReference = true)]” attribute to TodoList class.

The default XML serialization could also fail when you have the EF proxy and lazy loading enabled. The issue arises when you try to serialize a proxy of TodoList which really isn’t a TodoList but a dynamically generated type. Thus the following exception is thrown:

Type 'System.Data.Entity.DynamicProxies.TodoList_4ECA216B8773C8B6552AD787C3BA8087E9C365199E3C2F3C1E28B89CD6556441' with data contract name TodoList_4ECA216B8773C8B6552AD787C3BA8087E9C365199E3C2F3C1E28B89CD6556441:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer

In our template, we demonstrated how to use Data Transfer Object (DTO) to solve both problems so that it works for XML and JSON serialization. DTO is a preferred design pattern for solutions with complex data models. You can see the DTO classes from TodoItemDto.cs and TodoListDto.cs files.

Server Web API DBContext

The TodoItemContext.cs file provides the Database Context that Entity framework will use. This file would normally be generated and modified via data model Web API Scaffolding.

clip_image006

Server Web API Controllers

Controllers\TodoController.cs and TodoListController.cs files contain the Web API controller code. When we built the SPA application for template, we generated the files through Web API scaffolding, and then modified them to work with DTOs and authorizations. Controller class attribute “[Authorize]” ensures only authorized user can access these Web API controller calls. Checking against User.Identity.Name inside most functions is to ensure that the database records can only be accessed by their corresponding owners.

The TodoListController.GetTodoLists function has an include statement in its LINQ call. It’s because our default connection string does not have MultipleActiveResultSets=”true” set (MARS). You can modify the SQL connection string locally if you want MARS behavior. For Windows Azure deployment, you need to manually modify its SQL Azure connection string to include MARS if you choose to do so.

Server View and Client View with Knockout JS

In Views\Home\Index.cshtml, we use the knockout data-bind attributes as the view. You can see all the knockout data-bind attributes are colorized and have limited intelliSense available for RC. In order to get the knockout binding handlers and user defined handlers’ intelliSense, we need to reference the knockout and app/todo*.js files in Scripts/_references.js file.

clip_image008

Client JavaScript Data Access Layer

Scripts/app/todo.datacontext.js file defines the todoApp namespace and the data access layer to communicate with the server Web API controllers. One thing to note is the usage of $.ajax with “cache: false” inside its options parameter, because in certain browsers, JSON requests can be cached and we will not be able to get updated Web API results. One thing we might improve in the future for this file is to remove the knockout relationship in this file so that any other SPA framework can work with this file without changing it.

Client JavaScript Models

Scripts/app/todo.model.js file defines the knockout data models. Besides the general knockout observable defines, it also shows how to subscribe a function to an observable so that function will get called whenever the observed property changes.

Client JavaScript ViewModels

Scripts/app/todo.viewmodel.js defines the view model for the page. It defines the page level view model and initiates the knockout bindings for the page.

Knockout Bindings JavaScript File

Scripts/app/todo.bindings.js defines customized knockout binding handlers which demonstrate how to extend knockout JavasSript framework. We also extended the knockout binding handlers to work with JQuery Validation plugin.

AjaxLogin.js file

Scripts/app/ajaxlogin.js shows how we use AJAX to do form based login with JSON. We also have the code to handle the login/register link actions.

Summary

In MVC SPA template, we showed a SPA design pattern with KnockoutJS framework, to work with server end MVC Web API. Our purpose is to provide a simple starting point for people to study knockoutJS SPA framework with MVC Web API, instead of trying to fully cover all SPA aspects, which also includes routing and much more.

Knockout can also be easily replaced with other SPA JavaScript frameworks that you feel comfortable with. Don’t be shy to study the difference of all the SPA frameworks out there.

References

John Papa’s blog about our ASP.NET and Web Tools 2012.2 RC SPA template

John Papa’s blog about our ASP.NET Fall Update 2012 Build Preview SPA template

Knockout JS

The excellent Knockout tutorial

Leave a Comment
  • Please add 4 and 5 and type the answer here:
  • Post
Thanks for sharing your comment! If your comment doesn't appear right away, please be patient as it may take a few minutes to publish or may require moderation.
  • Why does it use "return new createTodoList(list)" instead "return createTodoList(list) in the function at datacontext.js?

    function getSucceeded(data) {

               var mappedTodoLists = $.map(data, function (list) { return new createTodoList(list); });

               todoListsObservable(mappedTodoLists);

           }

    Any benefits?

  • @Richard, I think you are right, we should be able to remove the "new" here to gain better performance as the objected reutnred from createTodoList is already a "new" object.  Thanks for pointing this out!  

  • Hi Xinyang,

    I'd like to know more about the solution to the issue with Lazy Loading.  I know you use a DTO but how does this solve the issue in the sample?  I'm getting this error in my WebAPI and it's incredibly frustrating.

    Jason

  • Hi, Jason,

    I'd like to know more about the solution to the issue with Lazy Loading.  I know you use a DTO but how does this solve the issue in the sample?  I'm getting this error in my WebAPI and it's incredibly frustrating.

    I think some Lazy Loading issues are LINQ problem depending on the database connection setting (e.g. multipleactiveresultsets=true is in the connection string or not).   Some problems are from EF during serializing object to JSON/XML .  Using DTO may not solve the the LINQ lazy loading problems, but will make sure we don't fall to the EF/serialization lazy loading problem.

    In our SPA template, the DTO make it straight forward for our models to support both JSON and XML calls.  Otherwise, we need to add 2 different type of attributes to enable non-circular reference for JSON and XML.  They were very confusing.

    Thanks

    Xinyang Qiu

  • How do you authenticate the web api call like: http://localhost:52934/Api/TodoList ?

    Thank you

  • @Victor,

    I assume you are asking the web application itself.  An authentication token is generated and passed back during login as cookie.  You can see the code from AccountController.cs file.  Then this cookie is used for all future webapi authentication.

    To write other non-browser based client to connect to webapi, it's another story,  For example, you can use a httpClient with cookie container to save the authentication token, If AntiForgeryToken is enabled, you might need to change the server code to find a better way to pass back the antiforgery token.   And if you are using 3rd party oauth provider, then you need to do more customized coding for non-browser based client to achieve the authentications.

    Hope it helps

    Xinyang

Page 1 of 1 (6 items)