{"id":1794,"date":"2013-02-21T16:34:09","date_gmt":"2013-02-21T16:34:09","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/2013\/02\/21\/mvc-single-page-application-template-for-asp-net-and-web-tools-2012-2\/"},"modified":"2013-02-21T16:34:09","modified_gmt":"2013-02-21T16:34:09","slug":"mvc-single-page-application-template-for-asp-net-and-web-tools-2012-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/mvc-single-page-application-template-for-asp-net-and-web-tools-2012-2\/","title":{"rendered":"MVC Single Page Application Template for ASP.NET and Web Tools 2012.2"},"content":{"rendered":"<p>With the final release of ASP.NET and Web Tools 2012.2, we refreshed <a href=\"http:\/\/www.asp.net\/single-page-application\/\">single page application page on asp.net<\/a> .&#160; It talks about <a href=\"http:\/\/www.asp.net\/single-page-application\/overview\/introduction\/knockoutjs-template\">KnockoutJS Template<\/a> and introduced <a href=\"http:\/\/www.asp.net\/single-page-application\/overview\/introduction\/other-libraries\">4 community created SPA templates<\/a> that you can install as MVC templates.<\/p>\n<p>There are four improvements for the MVC SPA template RTM release over the <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2012\/12\/19\/mvc-single-page-template-update-for-asp-net-and-web-tools-2012-2-rc.aspx?CommentPosted=true#commentmessage\">RC release<\/a> that worth a note.<\/p>\n<h2>Antiforgery support for Web API calls<\/h2>\n<p align=\"left\">The ValidateAntiForgeryToken filter only works on MVC calls. Web API doesn&#8217;t have a default Antiforgery filter yet. We implemented attribute \u201cValidateHttpAntiForgeryToken\u201d inside Filters\\ValidateHttpAntiForgeryTokenAttribute.cs to support antiforgery in Web API calls.&#160; You can see section Anti-CSRF in <a href=\"http:\/\/www.asp.net\/single-page-application\/overview\/introduction\/knockoutjs-template\">KnockoutJS Template<\/a> article for more information. <\/p>\n<p>ValidateHttpAntiForgeryToken attribute is used for TodoController class and 3 methods for TodoListController class.<\/p>\n<p>In index.cshtml, we have the following code:<\/p>\n<blockquote>\n<pre class=\"code\"><span style=\"background: yellow;color: black\">@functions{\n<\/span><span style=\"background: white;color: black\">    <\/span><span style=\"background: white;color: blue\">public string <\/span><span style=\"background: white;color: black\">GetAntiForgeryToken()\n    {\n        <\/span><span style=\"background: white;color: blue\">string <\/span><span style=\"background: white;color: black\">cookieToken, formToken;\n        <\/span><span>AntiForgery<\/span><span style=\"background: white;color: black\">.GetTokens(<\/span><span style=\"background: white;color: blue\">null<\/span><span style=\"background: white;color: black\">, <\/span><span style=\"background: white;color: blue\">out <\/span><span style=\"background: white;color: black\">cookieToken, <\/span><span style=\"background: white;color: blue\">out <\/span><span style=\"background: white;color: black\">formToken);\n        <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">cookieToken + <\/span><span>&quot;:&quot; <\/span><span style=\"background: white;color: black\">+ formToken;                \n    }\n<\/span><span style=\"background: yellow;color: black\">}<\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: blue\">&lt;<\/span><span style=\"background: white;color: maroon\">input <\/span><span style=\"background: white;color: red\">id<\/span><span style=\"background: white;color: blue\">=&quot;antiForgeryToken&quot; <\/span><span style=\"background: white;color: red\">type<\/span><span style=\"background: white;color: blue\">=&quot;hidden&quot; <\/span><span style=\"background: white;color: red\">value<\/span><span style=\"background: white;color: blue\">=&quot;<\/span><span style=\"background: yellow;color: black\">@<\/span><span style=\"background: white;color: black\">GetAntiForgeryToken()<\/span><span style=\"background: white;color: blue\">&quot; \/&gt;<\/span><\/pre>\n<\/blockquote>\n<pre class=\"code\">In todo.datacontext.js file, as part of the AJAX call, we have:<\/pre>\n<blockquote>\n<pre class=\"code\"><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">antiForgeryToken = $(<\/span><span>&quot;#antiForgeryToken&quot;<\/span><span style=\"background: white;color: black\">).val();\n<\/span><span style=\"background: white;color: blue\">if <\/span><span style=\"background: white;color: black\">(antiForgeryToken) {\n    options.headers = {\n        <\/span><span>'RequestVerificationToken'<\/span><span style=\"background: white;color: black\">: antiForgeryToken\n    }\n}<\/span><\/pre>\n<\/blockquote>\n<h2>Use camel case for JSON data<\/h2>\n<p>We listened to <a href=\"http:\/\/www.johnpapa.net\/\">John Papa<\/a>\u2019s advice and changed to camel casing for all the JavaScript models.&#160; We added the following line in app_start\/webapiconfig.cs to support the camel case for JSON serialization.<\/p>\n<pre class=\"code\"><span style=\"background: white;color: green\">\/\/ Use camel case for JSON data.\n<\/span><span style=\"background: white;color: black\">config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = <br \/>                  <\/span><span style=\"background: white;color: blue\">new <\/span><span>CamelCasePropertyNamesContractResolver<\/span><span style=\"background: white;color: black\">();<\/span><\/pre>\n<h2>Support JQuery.1.9 JSON parser change<\/h2>\n<p>JQuery 1.9 has a change for JSON Parser that it <a href=\"http:\/\/jquery.com\/upgrade-guide\/1.9\/#jquery-ajax-returning-a-json-result-of-an-empty-string\">no longer accept empty string as valid return<\/a>.&#160; We change the jquery.validate.unobtrusive.js file for all the MVC templates to support JQuery.1.9.&#160; For SPA template, we use \u201ctext\u201d datatype instead of \u201cjson\u201d when we are not expecting a JSON output in todo.datacontext.js file:<\/p>\n<p><pre class=\"code\"><span style=\"background: white;color: black\">    <\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">saveChangedTodoList(todoList) {\n        clearErrorMessage(todoList);\n        <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">ajaxRequest(<\/span><span>&quot;put&quot;<\/span><span style=\"background: white;color: black\">, todoListUrl(todoList.todoListId), todoList<font>, <\/font><\/span><span><font>&quot;text&quot;<\/font><\/span><span style=\"background: white;color: black\">)\n            .fail(<\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">() {\n                todoList.errorMessage(<\/span><span>&quot;Error updating the todo list title. Please make sure it is non-empty.&quot;<\/span><span style=\"background: white;color: black\">);\n            });\n    }\n\n    <\/span><span style=\"background: white;color: green\">\/\/ \u2026\n<\/span><span style=\"background: white;color: black\">    <\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">ajaxRequest(type, url, data<font>, dataType<\/font>) { <\/span><span style=\"background: white;color: green\">\/\/ Ajax helper\n        <\/span><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">options = {\n            <font>dataType: dataType || <\/font><\/span><span><font>&quot;json&quot;<\/font><\/span><span style=\"background: white;color: black\"><font>,\n<\/font>            contentType: <\/span><span>&quot;application\/json&quot;<\/span><span style=\"background: white;color: black\">,\n            cache: <\/span><span style=\"background: white;color: blue\">false<\/span><span style=\"background: white;color: black\">,\n            type: type,\n            data: data ? data.toJson() : <\/span><span style=\"background: white;color: blue\">null\n        <\/span><span style=\"background: white;color: black\">};\n        <br \/><span style=\"background: white;color: green\">        \/\/ \u2026 <\/span><\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: black\"><span style=\"background: white;color: green\"><\/span>        <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">$.ajax(url, options);\n    }<\/span><\/pre>\n<\/p>\n<h2>Support KO ObservableArray IntelliSense by using JavaScript XML Documentation Comments<\/h2>\n<p>The editor uses \u201cscripts\/_references.js\u201d file\u2019s references files to get the Knockout\u2019s IntelliSense in the data-bind attributes.&#160; Sometimes it\u2019s impossible for the JavaScript engine to figure out what the correct object type is for KO\u2019s ObservableArray.&#160; We need to add some XML Documentation Comments to help the JavaScript engine to provide meaningful <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb385682.aspx\">JavaScript IntelliSense<\/a>.&#160; <\/p>\n<h3>todo.model.js<\/h3>\n<pre class=\"code\"><span style=\"background: white;color: black\">    <\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">todoList(data) {\n        <\/span><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">self = <\/span><span style=\"background: white;color: blue\">this<\/span><span style=\"background: white;color: black\">;\n        data = data || {};\n        <\/span><span style=\"background: white;color: green\">\/\/ \u2026<\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: green\"><\/span><span style=\"background: white;color: black\">        self.todos = ko.observableArray(importTodoItems(data.todos));<\/span><\/pre>\n<blockquote>\n<p><span style=\"background: white;color: black\"><\/span><span style=\"background: white;color: green\">&#160;&#160;&#160; \/\/ \u2026<\/span><\/p>\n<\/blockquote>\n<pre class=\"code\"><span style=\"background: white;color: black\">    <\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">importTodoItems(todoItems) {\n        <\/span><span style=\"background: white;color: green\">\/\/\/ &lt;returns value=&quot;[new todoItem()]&quot;&gt;&lt;\/returns&gt;\n        <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">$.map(todoItems || [],\n                <\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">(todoItemData) {\n                    <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">datacontext.createTodoItem(todoItemData);\n                });\n    }<\/span><\/pre>\n<h3>todo.viewmodel.js:<\/h3>\n<blockquote>\n<pre class=\"code\"><span style=\"background: white;color: black\">window.todoApp.todoListViewModel = (<\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">(ko, datacontext) {\n    <\/span><span style=\"background: white;color: green\">\/\/\/ &lt;field name=&quot;todoLists&quot; value=&quot;[new datacontext.todoList()]&quot;&gt;&lt;\/field&gt;\n    <\/span><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">todoLists = ko.observableArray(),<\/span><\/pre>\n<\/blockquote>\n<pre class=\"code\"><span style=\"background: white;color: black\"><\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: black\">So in general, if we have a simple code like below,<\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">TaskListViewModel() {\n<\/span><span style=\"background: white;color: green\">    <\/span><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">self = <\/span><span style=\"background: white;color: blue\">this<\/span><span style=\"background: white;color: black\">;\n    self.tasks = ko.observableArray([]);<\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: black\"><\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: black\">we can convert to the following to support tasks IntelliSense in VS:<\/span><\/pre>\n<pre class=\"code\"><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">TaskListViewModel() {\n    <\/span><span style=\"background: white;color: blue\">var <\/span><span style=\"background: white;color: black\">self = <\/span><span style=\"background: white;color: blue\">this<\/span><span style=\"background: white;color: black\">;\n    self.tasks = ko.observableArray(<\/span><span style=\"background: white;color: blue\">function <\/span><span style=\"background: white;color: black\">() {\n        <\/span><span style=\"background: white;color: green\">\/\/\/ &lt;returns value=&quot;[new Task()]&quot;&gt;&lt;\/returns&gt;\n        <\/span><span style=\"background: white;color: blue\">return <\/span><span style=\"background: white;color: black\">[];\n    }());<\/span><\/pre>\n<h2>Summary<\/h2>\n<p>There are quite a few SPA frameworks around.&#160; You can easily <a href=\"http:\/\/www.asp.net\/vnext\/overview\/fall-2012-update\/custom-mvc-templates\">customize a MVC template<\/a> and create a VSIX file for other people to install.&#160; If you have a great template to share, feel free to contact us to get your template listed in our asp.net SPA page.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the final release of ASP.NET and Web Tools 2012.2, we refreshed single page application page on asp.net .&#160; It talks about KnockoutJS Template and introduced 4 community created SPA templates that you can install as MVC templates. There are four improvements for the MVC SPA template RTM release over the RC release that worth [&hellip;]<\/p>\n","protected":false},"author":410,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197],"tags":[7433,7333,7425],"class_list":["post-1794","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","tag-asp-net-and-web-tools-2012-2","tag-asp-net-mvc","tag-spa"],"acf":[],"blog_post_summary":"<p>With the final release of ASP.NET and Web Tools 2012.2, we refreshed single page application page on asp.net .&#160; It talks about KnockoutJS Template and introduced 4 community created SPA templates that you can install as MVC templates. There are four improvements for the MVC SPA template RTM release over the RC release that worth [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/1794","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/410"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=1794"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/1794\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=1794"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=1794"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=1794"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}