You are here:   Blog
Register   |  Login

 

Oct 29

Written by: Michael Washington
10/29/2013 4:00 PM  RssIcon

image

Visual Studio LightSwitch can be used as the backend data source for your AngularJs applications. This allows you to reuse the service layer you have created for your LightSwitch HTML Client and Silverlight applications, or to simply use LightSwitch as the service layer for your AngularJs applications.

This article would not be possible without the information provided by Dale Morrison (blog.ofanitguy.com). This article also uses the Simple CRUD Grid by Jon Gallant. Please see the links to their sites at the end of this article.

Also see: Using JayData to Consume the Visual Studio LightSwitch OData Business Layer in a AngularJs CRUD Application.

The Application

image

Records can be added, updated, and deleted.

image

The validation from the LightSwitch business layer contained in the LightSwitch service layer is enforced.

 

The LightSwitch Service Layer

image

Using Visual Studio 2013 (or higher), create a New Project.

image

Create a new LightSwitch application.

image

Right-click on the Data Sources folder and select Add Table.

image

Create a table called Person and save it.

The table will be pluralized to People.

image

You could also implement business rules and add additional external data sources and WCF RIA Services.

Add NuGet Components

image

Right-click on the Server project and select Manage NuGet Packages.

image

Install the following packages:

  • Angular
  • FontAwesome
  • jQuery.UI.Combined
  • toastr
  • Twitter.Bootstrap
  • Twitter.Bootstrap.MVC
  • WebActivatorEx

image

Also install ASP.NET MVC version 5 (or higher).

image

Also install ASP.NET Web API version 5 (or higher).

image

Also select Updates, then All and then click the Update All button.

Add Web API Code

 

image

Right-click on the App_Start folder and select Add then select Add then New Item.

Create a file called WebApiConfig.cs and use the following code:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace LightSwitchApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

Also, (in the same App_Start directory) create a file called RouteConfig.cs and use the following code:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace LightSwitchApplication
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // This rule is required to allow the LightSwitch OData service to
            // be accessed when WebAPI is also enabled
            routes.IgnoreRoute("{*allsvc}", new { allsvc = @".*\.svc(/.*)?" });
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

 

Also, (in the same App_Start directory) create a file called FilterConfig.cs and use the following code:

 

using System.Web;
using System.Web.Mvc;
namespace LightSwitchApplication
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }
}

Also, (in the same App_Start directory) create a file called BundleConfig.cs and use the following code:

 

using System.Web;
using System.Web.Optimization;
namespace LightSwitchApplication
{
    public class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
          
        }
    }
}
 

 

image

Right-click on the Server project and select Add then New Item.

image

Add a Global.asax file.

Use the following code for the Global.asax.cs file:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Http;
namespace LightSwitchApplication
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

 

image

Build the Solution at this point.

image

It should build without errors.

 

Create The Home Page

We will create a page called Home (and an associated controller) so that we have a page to load our Angular grid (however, the web communication with the grid will be through Web API and the AngularPersonController that we will create in a later step).

image

Right-click on the Server project and select Add then New Folder.

Name the folder Controllers.

image

Right-click on the Controllers folder and select Add then Class.

Name the file HomeController.cs and use the following code:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace LightSwitchApplication.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ActionResult Index()
        {
            return View();
        }
    }
}

 

image

Create a folder named Views.

Create a folder named Home under the Views folder.

Right-click on the Home folder and select Add then MVC 5 View Page (Razor).

image

Name the view Index.

image

The Index.cshtml page will be created.

Update the page to say “Content will go here”.

image

Add a file called Web.Config under the Views folder.

Use the following code for the file:

 

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, 
                  System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, 
               System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
               requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, 
               System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
               requirePermission="false" />
    </sectionGroup>
  </configSections>
  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, 
          System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>
  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>
    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, 
        System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, 
        System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, 
        System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
             namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*"
           preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

 

 

image

Run the application…

image

Because we don’t have a LightSwitch page configured you will see a message box.

You can create a LightSwitch HTML Client page and provide a link on that page to navigate to the MVC page that we will show in the next step.

image

Change the url to /Home and the Index.cshtml page we created will load.

Create AngularPerson Code

image

Create a folder called Model and add a class.

image

Name the file AngularPerson.cs.

Use the following code:

 

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace LightSwitchApplication.Model
{
    public class AngularPerson
    {
        [Key]
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Birthdate { get; set; }
    }
}

 

Even though the table in LightSwitch is called People (and the entity is called Person), we will use this Data Transfer Object (DTO) to pass back data between Angular and the MVC controller (and the LightSwitch service layer).

The reason we do this is that there are some fields in the LightSwitch entity that cannot be properly serialized so we will only transfer the fields we need.

Create The Controller Code

image

Right-click on the Controllers folder and select Add then Web API Controller Class.

image

Name the controller: AngularPersonController.

Replace all the code with the following code:

 

using LightSwitchApplication.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
namespace LightSwitchApplication.Controllers
{
    public class AngularPersonController : ApiController
    {
        // GET api/AngularPerson
        public IEnumerable<AngularPerson> GetPeople() // Get All People
        {
            using (var serverContext = GetServerContext())
            {
                var PeopleSet = from objPerson in serverContext.DataWorkspace
                                    .ApplicationData.People.GetQuery().Execute()
                                select new AngularPerson
                                {
                                    Id = objPerson.Id,
                                    FirstName = objPerson.FirstName,
                                    LastName = objPerson.LastName,
                                    Birthdate = objPerson.Birthdate.ToShortDateString()
                                };
                return PeopleSet.AsEnumerable();
            }
        }
        // GET api/AngularPerson/5
        public AngularPerson GetPerson(int id) // get one Person
        {
            using (var serverContext = GetServerContext())
            {
                var objAngularPerson = (from objPerson in serverContext.DataWorkspace
                                            .ApplicationData.People.GetQuery().Execute()
                                        where objPerson.Id == id
                                        select new AngularPerson
                                        {
                                            Id = objPerson.Id,
                                            FirstName = objPerson.FirstName,
                                            LastName = objPerson.LastName,
                                            Birthdate = objPerson.Birthdate.ToShortDateString()
                                        }).FirstOrDefault();
                return objAngularPerson;
            }
        }
        // PUT api/AngularPerson/5
        public HttpResponseMessage PutPerson(int id, AngularPerson person) // An Update
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            try
            {
                using (var serverContext = GetServerContext())
                {
                    var objLightSwitchPerson = (from LightSwitchPerson in serverContext.DataWorkspace
                                                    .ApplicationData.People.GetQuery().Execute()
                                                where LightSwitchPerson.Id == person.Id
                                                select LightSwitchPerson).FirstOrDefault();
                    if (objLightSwitchPerson == null)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.NotFound, "not found");
                    }
                    else
                    {
                        objLightSwitchPerson.FirstName = person.FirstName;
                        objLightSwitchPerson.LastName = person.LastName;
                        objLightSwitchPerson.Birthdate = Convert.ToDateTime(person.Birthdate);
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                    }
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (Exception ex)
            {
                // Throw the exception so it will be caught by 'notificationFactory'
                throw new Exception(GetLightSwitchError(ex));
            }
        }
        // POST api/AngularPerson
        public HttpResponseMessage PostPerson(AngularPerson person) // An Insert
        {
            if (ModelState.IsValid)
            {
                using (var serverContext = GetServerContext())
                {
                    try
                    {
                        var objLightSwitchPerson = serverContext.DataWorkspace
                            .ApplicationData.People.AddNew();
                        objLightSwitchPerson.FirstName = person.FirstName;
                        objLightSwitchPerson.LastName = person.LastName;
                        objLightSwitchPerson.Birthdate = Convert.ToDateTime(person.Birthdate);
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                        // Set the Id so it can be returned
                        person.Id = objLightSwitchPerson.Id;
                        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, person);
                        response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = person.Id }));
                        return response;
                    }
                    catch (Exception ex)
                    {
                        // Throw the exception so it will be caught by 'notificationFactory'
                        throw new Exception(GetLightSwitchError(ex));
                    }
                }
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
        // DELETE api/AngularPerson/5
        public HttpResponseMessage DeletePerson(int id) // Delete Person
        {
            AngularPerson objPerson = GetPerson(id);
            if (objPerson == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            using (var serverContext = ServerApplicationContext.CreateContext())
            {
                try
                {
                    var objLightSwitchPerson = (from LightSwitchPerson in serverContext.DataWorkspace
                                                    .ApplicationData.People.GetQuery().Execute()
                                                where LightSwitchPerson.Id == id
                                                select LightSwitchPerson).FirstOrDefault();
                    if (objLightSwitchPerson == null)
                    {
                        return Request.CreateResponse(HttpStatusCode.NotFound);
                    }
                    else
                    {
                        objLightSwitchPerson.Delete();
                        serverContext.DataWorkspace.ApplicationData.SaveChanges();
                        return Request.CreateResponse(HttpStatusCode.OK, objPerson);
                    }
                }
                catch (Exception ex)
                {
                    // Throw the exception so it will be caught by 'notificationFactory'
                    throw new Exception(GetLightSwitchError(ex));
                }
            }
        }
        // Utility
        private static ServerApplicationContext GetServerContext()
        {
            ServerApplicationContext serverContext =
                (LightSwitchApplication.ServerApplicationContext)ServerApplicationContext.Current;
            if (serverContext == null)
            {
                serverContext =
                    (LightSwitchApplication.ServerApplicationContext)ServerApplicationContext.CreateContext();
            }
            return serverContext;
        }
        private string GetLightSwitchError(Exception ex)
        {
            string strError = "";
            Microsoft.LightSwitch.ValidationException ValidationErrors =
                    ex as Microsoft.LightSwitch.ValidationException;
            if (ValidationErrors != null)
            {
                StringBuilder sbErrorMessage = new StringBuilder();
                foreach (var error in ValidationErrors.ValidationResults)
                {
                    sbErrorMessage.Append(string.Format("<p>{0}</p>", error.Message));
                }
                strError = sbErrorMessage.ToString();
            }
            else
            {
                if (ex.InnerException != null)
                {
                    strError = ex.InnerException.InnerException.Message;
                }
                else
                {
                    // This is a simple error -- just show Message
                    strError = ex.Message;
                }
            }
            return strError;
        }
    }
}

 

Add the Angular Grid Control

Download the Jon Gallant Angular Grid Control:

https://github.com/jonbgallant/AngularJS-WebApi-EF/tree/master/AngularJS-WebApi-EF/Scripts/App

image

Insert the folders and files into the Scripts folder.

Note,  you will have to create the folders and import each file into each folder one by one using Add, then Existing Item.

Implement the Angular Grid Control

Replace the contents of Index.cshtml (in the Views/Home folder) with the following:

 

<!doctype html>
<html ng-app="app">
<head>
    <title>AngularJS-WebApi-EF</title>
    @Styles.Render("~/content/bootstrap/base")
    @Styles.Render("~/content/toastr")
    @Styles.Render("~/content/css")
    @Styles.Render("~/content/angular")
</head>
<body>
    <h1>People</h1>
    <div crud-grid table='AngularPerson'
         columns='[
		    {"name":"Id", "class":"col-md-1", "autoincrement": "true"},
		    {"name":"FirstName"},
		    {"name":"LastName"},
		    {"name":"Birthdate"}
	    ]'></div>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/angular")
    @Scripts.Render("~/bundles/toastr")
    @Scripts.Render("~/bundles/bootstrap")
</body>
</html>

 

Also, update the file called BundleConfig.cs (in the App_Code directory) to use the following code:

 

using System.Web;
using System.Web.Optimization;
namespace LightSwitchApplication
{
    public class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));
            bundles.Add(new ScriptBundle("~/bundles/angular").Include(
                        "~/Scripts/angular.js", "~/Scripts/angular-resource.js",
                        "~/Scripts/App/app.js",
                        "~/Scripts/App/Services/*.js",
                        "~/Scripts/App/Directives/*.js", "~/Scripts/App/Directives/Services/*.js"));
            bundles.Add(new ScriptBundle("~/bundles/toastr").Include(
                        "~/Scripts/toastr.js"));
            bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                        "~/Scripts/jquery-ui-{version}.js"));
            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));
            // Use the development version of Modernizr to develop with and learn from. Then, when you're
            // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));
            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
            bundles.Add(new StyleBundle("~/Content/angular").Include("~/Scripts/App/Directives/Content/*.css"));
            bundles.Add(new StyleBundle("~/Content/toastr").Include("~/Content/toastr.css"));
            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                        "~/Content/themes/base/jquery.ui.core.css",
                        "~/Content/themes/base/jquery.ui.resizable.css",
                        "~/Content/themes/base/jquery.ui.selectable.css",
                        "~/Content/themes/base/jquery.ui.accordion.css",
                        "~/Content/themes/base/jquery.ui.autocomplete.css",
                        "~/Content/themes/base/jquery.ui.button.css",
                        "~/Content/themes/base/jquery.ui.dialog.css",
                        "~/Content/themes/base/jquery.ui.slider.css",
                        "~/Content/themes/base/jquery.ui.tabs.css",
                        "~/Content/themes/base/jquery.ui.datepicker.css",
                        "~/Content/themes/base/jquery.ui.progressbar.css",
                        "~/Content/themes/base/jquery.ui.theme.css"));
        }
    }
}

 

 

image

Run the application and navigate to the Home directory.

 

Going Further

The Web API code and the AngularPerson controller can be eliminated if you call the LightSwitch OData methods directly.

See: Using JayData to Consume the Visual Studio LightSwitch OData Business Layer in a AngularJs CRUD Application.

Also, the following article should provide a starting point if you want to use an Angular factory:

http://sravi-kiran.blogspot.com/2013/08/ConsumingWebApiODataUsingResourceServiceOfAngularJS.html

 

Links

 

Simple CRUD Grid (Jon Gallant)

How to build a simple CRUD grid with AngularJS, WebAPI, Entity Framework (EF), Bootstrap, Font Awesome & Toastr

V2 of my AngularJS, WebAPI CRUD Grid - Now using $resource instead of $http and deployed a LIVE DEMO to Azure!

V3 of my AngularJS, WebApi CRUD Grid. It's now a directive and supports multiple grids per page

AngularJS CRUD Grid v4: Sorting, AngularJS 1.2.0 & Bootstrap 3

AngularJS CRUD Grid v5: Now with Dynamic Columns

 

Visual Studio LightSwitch and MVC Dale Morrison (blog.ofanitguy.com)

 

Download Code

The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

(you must have Visual Studio 2013 (or higher) installed to run the code)

Tags: MVC , AngularJs
Categories:

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation