{"id":20255,"date":"2018-03-23T16:47:00","date_gmt":"2018-03-23T16:47:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/premier_developer\/?p=20255"},"modified":"2019-03-01T09:33:23","modified_gmt":"2019-03-01T16:33:23","slug":"running-net-applications-client-side-in-the-browser","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/premier-developer\/running-net-applications-client-side-in-the-browser\/","title":{"rendered":"Running .NET applications client-side in the browser"},"content":{"rendered":"<p>In this post, App Dev Managers <a href=\"https:\/\/www.linkedin.com\/in\/robertdschumann\/\">Robert Schumann<\/a> and <a href=\"https:\/\/www.linkedin.com\/in\/ben-hlaban-6b276028\/\">Ben Hlaban<\/a>, introduce us to Blazor \u2013 an experimental web UI framework based on C#, Razor, and HTML that runs in the browser via WebAssembly.<\/p>\n<hr \/>\n<p>This journey started from a <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/blazor-experimental-project\/\">blog<\/a> by <a href=\"https:\/\/www.linkedin.com\/in\/daniel-roth-0102185\">Daniel Roth<\/a>. Other than the YouTube of <a href=\"https:\/\/www.youtube.com\/watch?v=MiLAE6HMr10&amp;feature=youtu.be&amp;t=31m45s\">Steve Sanderson\u2019s prototype demo at NDC Oslo<\/a>, this wasn\u2019t much information to draw from.<\/p>\n<p>A few days later I mention Blazor to my colleague <a href=\"https:\/\/www.linkedin.com\/in\/ben-hlaban-6b276028\">Ben<\/a>, and he starts asking a bunch of rapid-fire questions. Whoa! Time-out. With coffee top-offs, we start a Skype call, launch Visual Studio, git clone repo, and intrigue quickly ensued.<\/p>\n<p>This blog is about getting started with Blazor. We\u2019ll provide setup guidance, develop a cursory ToDo List application using the MVC pattern, and even do some unit testing. A second blog is intended to delve into E2E testing the application using Selenium and demonstrate how to position the project for CI\/CD.<\/p>\n<p><b><u>Pre-requisites*<\/u><\/b><\/p>\n<ul>\n<li>.NET Core SDK (&gt;2.1.4)\n<ul>\n<li>At command prompt type \u201cdotnet &#8211;version\u201d\n<ul>\n<li>Download: <a href=\"https:\/\/www.microsoft.com\/net\/learn\/get-started\/windows\">https:\/\/www.microsoft.com\/net\/learn\/get-started\/windows<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Node.js (&gt;8.3)\n<ul>\n<li>At command prompt type \u201cnode -v\u201d\n<ul>\n<li>Download: <a href=\"https:\/\/nodejs.org\/en\/\">https:\/\/nodejs.org\/en\/<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Visual Studio (&gt;2017)\n<ul>\n<li>Download: <a href=\"https:\/\/www.visualstudio.com\/thank-you-downloading-visual-studio\/?sku=Community&amp;rel=15\">https:\/\/www.visualstudio.com\/thank-you-downloading-visual-studio\/?sku=Community&amp;rel=15<\/a><\/li>\n<\/ul>\n<\/li>\n<li>\u00b7 Blazor.VSExtension.VSIX\n<ul>\n<li>Download: <a href=\"https:\/\/github.com\/SteveSanderson\/Blazor\/releases\/download\/v0.3.1\/Blazor.VSExtension.vsix\">https:\/\/github.com\/SteveSanderson\/Blazor\/releases\/download\/v0.3.1\/Blazor.VSExtension.vsix<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>* If you had to install any of the above please do cursory system reboot<\/p>\n<p><b><u>Setup<\/u><\/b><\/p>\n<ul>\n<li>Launch Visual Studio Installer\n<ul>\n<li>Make sure Visual Studio is up-to-date<\/li>\n<li>Make sure \u201cASP.NET and web development\u201d is enabled<\/li>\n<li>Make sure \u201c.NET Core cross-platform development\u201d is enabled<\/li>\n<\/ul>\n<\/li>\n<li>Install Blazor project template\n<ul>\n<li>Double-click previously downloaded file Blazor.VSExtension.VSIX\nor<\/li>\n<li>At command via VSIXInstaller.exe Blazor.VSExtension.VSIX<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><b><u>Here we go\u2026<\/u><\/b><\/p>\n<ul>\n<li>In Visual Studio 2017, select <b>File | New Project | Visual Studio | Web | Blazor application<\/b><\/li>\n<li><b>Name<\/b> this new project \u201cHelloBlazor\u201d. Click <b>OK <\/b>button.<\/li>\n<li>Press <b>CTRL + F5 <\/b>to make sure the default baseline project works. IIS Express should spin-up. The project eventually loads and is a typical Visual Studio templated SPA with Home, Counter, and Fetch Data features OTB.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image66.png\"><img decoding=\"async\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb60.png\" alt=\"image\" width=\"1028\" height=\"160\" border=\"0\" \/><\/a><\/p>\n<ul>\n<li>Right-click HelloBlazor project | Add | Class | Name = \u201cTodo.cs\u201d | OK<\/li>\n<\/ul>\n<pre>namespace HelloBlazor\r\n{\r\n\r\npublic class Todo\r\n\r\n{\r\n\r\npublic string Description { get; set; }\r\n\r\npublic bool IsComplete { get; set; }\r\n\r\n}\r\n\r\n}<\/pre>\n<ul>\n<li>Right-click HelloBlazor project | Add | Class | Name = \u201cTodoComponent .cs\u201d | OK<\/li>\n<\/ul>\n<pre>using Blazor.Components;\r\nusing System.Collections.Generic;\r\n\r\nnamespace HelloBlazor\r\n\r\n{\r\n\r\npublic class TodoComponent : RazorComponent\r\n\r\n{\r\n\r\npublic IList&lt;Todo&gt; Todos = new List&lt;Todo&gt;();\r\n\r\npublic Todo NewTodo = new Todo();\r\n\r\npublic void AddTodo()\r\n\r\n{\r\n\r\nif (!string.IsNullOrWhiteSpace(NewTodo.Description))\r\n\r\n{\r\n\r\nTodos.Add(new Todo { Description = NewTodo.Description, IsComplete = NewTodo.IsComplete });\r\n\r\nNewTodo = new Todo();\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n<\/pre>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image67.png\"><img decoding=\"async\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb61.png\" alt=\"image\" width=\"1028\" height=\"152\" border=\"0\" \/><\/a><\/p>\n<ul>\n<li>Right-click HelloBlazor project | Add | New Item | Web | ASP.NET | Razor View | Name = \u201cTodoList.cshtml\u201d | OK<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true \">@using HelloBlazor\r\n@inherits TodoComponent\r\n&lt;h1&gt;Todo List (@Todos.Count(todo =&gt; !todo.IsComplete))&lt;\/h1&gt;\r\n&lt;ul style=\"list-style: none\"&gt;\r\n   @foreach (var todo in Todos)\r\n   {\r\n      &lt;li&gt;\r\n      &lt;input @bind(todo.Description) \/&gt;\r\n      &lt;input type=\"checkbox\" @bind(todo.IsComplete) \/&gt;\r\n      &lt;\/li&gt;\r\n   }\r\n   &lt;li&gt;\r\n   &lt;input @bind(NewTodo.Description) \/&gt;\r\n   &lt;input type=\"checkbox\" @bind(NewTodo.IsComplete) \/&gt;\r\n   &lt;button @onclick(AddTodo)&gt;Add&lt;\/button&gt;\r\n   &lt;\/li&gt;\r\n&lt;\/ul&gt;\r\n<\/pre>\n<ul>\n<li>Finally, let\u2019s add a menu link to the new page <b><u><\/u><\/b>\n<ul>\n<li>Double-click or open the file Shared\/NavMenu.cshtml<\/li>\n<li>Add a new list item to the existing unordered list;\n<pre class=\"lang:default decode:true\">&lt;ul class='nav navbar-nav'&gt;\r\n   . . .\r\n   &lt;li&gt;\r\n      &lt;a href='~\/TodoList'&gt;\r\n      &lt;span class='glyphicon glyphicon-th-list'&gt;&lt;\/span&gt; Todo List\r\n      &lt;\/a&gt;\r\n   &lt;\/li&gt;\r\n&lt;\/ul&gt;\r\n<\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Press <b>CTRL + F5 <\/b>to make sure the modified project works. The new page should be available on the left navbar from the \u201cTodo List\u201d link.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image68.png\"><img decoding=\"async\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb62.png\" alt=\"image\" width=\"1028\" height=\"225\" border=\"0\" \/><\/a><\/p>\n<p><b><u>Unit Testing<\/u><\/b><\/p>\n<ul>\n<li>Right-click HelloBlazor solution | Add | New Project | Installed | Visual C# | Web | .NET Core | MSTest Test Project (.NET Core) | Name = HelloBlazor.Test | OK<\/li>\n<li>Right-click Dependencies | Add Reference | Projects | Solution | HelloBlazor | OK<\/li>\n<li>Right-click UnitTest1.cs file | Rename | Name = TodoComponentTests.cs | Yes<\/li>\n<li>Within the TodoComponentTests class rename TestMethod1 to AddToDo<\/li>\n<\/ul>\n<pre>using Microsoft.VisualStudio.TestTools.UnitTesting;\r\nnamespace HelloBlazor.Tests\r\n\r\n{\r\n\r\n[TestClass]\r\n\r\npublic class TodoComponentTests\r\n\r\n{\r\n\r\n[TestMethod]\r\n\r\npublic void AddTodo()\r\n\r\n{\r\n\r\n\/\/arrange\r\n\r\nvar todoComponent = new TodoComponent();\r\n\r\nvar description = \"this is a test\";\r\n\r\nvar isComplete = false;\r\n\r\n\/\/act\r\n\r\ntodoComponent.NewTodo.Description = description;\r\n\r\ntodoComponent.NewTodo.IsComplete = isComplete;\r\n\r\ntodoComponent.AddTodo();\r\n\r\n\/\/assert\r\n\r\nAssert.IsTrue(todoComponent.Todos.Count == 1);\r\n\r\nAssert.IsTrue(todoComponent.Todos[0].Description == description);\r\n\r\nAssert.IsTrue(todoComponent.Todos[0].IsComplete == isComplete);\r\n\r\n}\r\n\r\n}\r\n\r\n}<\/pre>\n<ul>\n<li>Press <b>CTRL+R,A<\/b> to run all tests.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image69.png\"><img decoding=\"async\" title=\"image\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/31\/2019\/04\/image_thumb63.png\" alt=\"image\" width=\"1028\" height=\"145\" border=\"0\" \/><\/a><\/p>\n<p><u>References<\/u><\/p>\n<ul>\n<li>Steve Sanderson\u2019s Blog\n<a href=\"http:\/\/blog.stevensanderson.com\/\">http:\/\/blog.stevensanderson.com\/<\/a><\/li>\n<li>Microsoft ASP.NET\n<a href=\"https:\/\/www.asp.net\/\">https:\/\/www.asp.net\/<\/a><\/li>\n<li>Blazor on Git\n<a href=\"https:\/\/github.com\/aspnet\/blazor\">https:\/\/github.com\/aspnet\/blazor<\/a><\/li>\n<li>Introduction to Razor Pages in ASP.NET Core\n<a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/mvc\/razor-pages\/?tabs=visual-studio\">https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/mvc\/razor-pages\/?tabs=visual-studio<\/a><\/li>\n<\/ul>\n<hr \/>\n<p><a href=\"https:\/\/blogs.msdn.com\/b\/premier_developer\/archive\/2014\/09\/15\/welcome.aspx\"><strong>Premier Support for Developers<\/strong><\/a> provides strategic technology guidance, critical support coverage, and a range of essential services to help teams optimize development lifecycles and improve software quality.\u00a0 Contact your Application Development Manager (ADM) or <a href=\"https:\/\/blogs.msdn.microsoft.com\/premier_developer\/contact-us\/\">email us<\/a> to learn more about what we can do for you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, App Dev Managers Robert Schumann and Ben Hlaban, introduce us to Blazor \u2013 an experimental web UI framework based on C#, Razor, and HTML that runs in the browser via WebAssembly. This journey started from a blog by Daniel Roth. Other than the YouTube of Steve Sanderson\u2019s prototype demo at NDC Oslo, [&hellip;]<\/p>\n","protected":false},"author":582,"featured_media":37840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[80],"tags":[106,3,107],"class_list":["post-20255","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","tag-net","tag-team","tag-webbrowser"],"acf":[],"blog_post_summary":"<p>In this post, App Dev Managers Robert Schumann and Ben Hlaban, introduce us to Blazor \u2013 an experimental web UI framework based on C#, Razor, and HTML that runs in the browser via WebAssembly. This journey started from a blog by Daniel Roth. Other than the YouTube of Steve Sanderson\u2019s prototype demo at NDC Oslo, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/20255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/users\/582"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/comments?post=20255"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/posts\/20255\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media\/37840"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/media?parent=20255"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/categories?post=20255"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/premier-developer\/wp-json\/wp\/v2\/tags?post=20255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}