Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon

Creating an Application using ASP.NET MVC, AngularJS and ServiceStack

Save for later
  • 8 min read
  • 23 Jul 2014

article-image

(For more resources related to this topic, see here.)

Routing considerations for ASP.NET MVC and AngularJS

In the previous example, we had to make changes to the ASP.NET MVC routing so it ignores the requests handled by the ServiceStack framework. Since the AngularJS application currently uses hashbang URLs, we don't need to make any other changes to the ASP.NET MVC routing.

Changing an AngularJS application to use the HTML5 History API instead of hashbang URLs requires a lot more work as it will conflict directly with the ASP.NET MVC routing. You need to set up IIS URL rewriting and use the URL Rewrite module for IIS 7 and higher, which is available at www.iis.net/downloads/microsoft/url-rewrite. AngularJS application routes have to be mapped using this module to the ASP.NET MVC view that hosts the client-side application. We also need to ensure that web service request paths are excluded from URL rewriting.

You can explore some changes required for the HTML5 navigation mode in the project found in the Example2 folder from the source code for this article.

The HTML5 History API is not supported in Internet Explorer 8 and 9.

Using ASP.NET bundling and minification features for AngularJS files

So far, we have referenced and included JavaScript and CSS files directly in the _Layout.cshtml file. This makes it difficult to reuse script references between different views, and the assets are not concatenated and minified when deployed to a production environment. Microsoft provides a NuGet package called Microsoft.AspNet.Web.Optimization that contains this essential functionality. When you create a new ASP.NET MVC project, it gets installed and configured with default options.

First, we need to add a new BundleConfig.cs file, which will define collections of scripts and style sheets under a virtual path, such as ~/bundles/app, that does not match a physical file. This file will contain the following code:

bundles.Add(new ScriptBundle("~/bundles/app").Include( "~/scripts/app/app.js", "~/scripts/app/services/*.js", "~/scripts/app/controllers/*.js"));

You can explore these changes in the project found in the Example3 folder from the source code for this article. If you take a look at the BundleConfig.cs file, you will see three script bundles and one style sheet bundle defined. Nothing is stopping you from defining only one script bundle instead, to reduce the resource requests further.

We can now reference the bundles in the _Layout.cshtml file and replace the previous scripts with the following code:

@Scripts.Render("~/bundles/basejs") @Scripts.Render("~/bundles/angular") @Scripts.Render("~/bundles/app")

Each time we add a new file to a location like ~/scripts/app/services/ it will automatically be included in its bundle. If we add the following line of code to the BundleConfig.RegisterBundles method, when we run the application, the scripts or style sheets defined in a bundle will be minified (all of the whitespace, line separators, and comments will be removed) and concatenated in a single file:

BundleTable.EnableOptimizations = true;

If we take a look at the page source, the script section now looks like the following code:

<script src ="/bundles/basejs?v=bWXds_q0E1qezGAjF9o48iD8-
hlMNv7nlAONwLLM0Wo1"></script> <script src ="/bundles/angular?v=k-
PtTeaKyBiBwT4gVnEq9YTPNruD0u7n13IOEzGTvfw1"></script> <script src ="/bundles/app?v=OKa5fFQWjXSQCNcBuWm9FJLcPFS8hGM6uq1SIdZNXWc1">
</script>

Using this process, the previous separate requests for each script or style sheet file will be reduced to a request to one or more bundles that are much reduced in content due to concatenation and minification.

For convenience, there is a new EnableOptimizations value in web.config that will enable or disable the concatenation and minification of the asset bundles.

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime

Securing the AngularJS application

We previously discussed that we need to ensure that all browser requests are secured and validated on the server for specific scenarios. Any browser request can be manipulated and changed even unintentionally, so we cannot rely on client-side validation alone.

When discussing securing an AngularJS application, there are a couple of alternatives available, of which I'll mention the following:

  • You can use client-side authentication and employ a web service call to authenticate the current user. You can create a time-limited authentication token that will be passed with each data request. This approach involves additional code in the AngularJS application to handle authentication.
  • You can rely on server-side authentication and use an ASP.NET MVC view that will handle any unauthenticated request. This view will redirect to the view that hosts the AngularJS application only when the authentication is successful. The AngularJS application will implicitly use an authentication cookie that is set on the server side, and it does not need any additional code to handle authentication.

I prefer server-side authentication as it can be reused with other server-side views and reduces the code required to implement it on both the client side and server side. We can implement server-side authentication in at least two ways, as follows:

  • We can use the ASP.NET Identity system or the older ASP.NET Membership system for scenarios where we need to integrate with an existing application
  • We can use built-in ServiceStack authentication features, which have a wide range of options with support for many authentication providers. This approach has the benefit that we can add a set of web service methods that can be used for authentication outside of the ASP.NET MVC context.

The last approach ensures the best integration between ASP.NET MVC and ServiceStack, and it allows us to introduce a ServiceStack NuGet package that provides new productivity benefits for our sample application.

Using the ServiceStack.Mvc library

ServiceStack has a library that allows deeper integration with ASP.NET MVC through the ServiceStack.Mvc NuGet package. This library provides access to the ServiceStack dependency injection system for ASP.NET MVC applications. It also introduces a new base controller class called ServiceStackController; this can be used by ASP.NET MVC controllers to gain access to the ServiceStack caching, session, and authentication infrastructures. To install this package, you need to run the following command in the NuGet Package Manager Console:

Install-Package ServiceStack.Mvc -Version 3.9.71

The following line needs to be added to the AppHost.Configure method, and it will register a ServiceStack controller factory class for ASP.NET MVC:

ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory
(container));

The ControllerBuilder.Current.SetControllerFactory method is an ASP.NET MVC extension point that allows the replacement of its DefaultControllerFactory class with a custom one. This class is tasked with matching requests with controllers, among other responsibilities. The FunqControllerFactory class provided in the new NuGet package inherits the DefaultControllerFactory class and ensures that all controllers that have dependencies managed by the ServiceStack dependency injection system will be resolved at application runtime.

To exemplify this, the BicycleRepository class is now referenced in the HomeController class, as shown in the following code:

public class HomeController : Controller { public BicycleRepository BicycleRepository { get; set; } // // GET: /Home/ public ActionResult Index() { ViewBag.BicyclesCount = BicycleRepository.GetAll().Count(); return View(); } }

The application menu now displays the current number of bicycles as initialized in the BicycleRepository class. If we add a new bicycle and refresh the browser page, the menu bicycle count is updated. This highlights the fact that the ASP.NET MVC application uses the same BicycleRepository instance as ServiceStack web services.

You can explore this example in the project found in the Example4 folder from the source code for this article.

Using the ServiceStack.Mvc library, we have reached a new milestone by bridging ASP.NET MVC controllers with ServiceStack services. In the next section, we will effectively transition to a single server-side application with unified caching, session, and authentication infrastructures.

The building blocks of the ServiceStack security infrastructure

ServiceStack has built-in, optional authentication and authorization provided by its AuthFeature plugin, which builds on two other important components as follows:

  • Caching: Every service or controller powered by ServiceStack has optional access to an ICacheClient interface instance that provides cache-related methods. The interface needs to be registered as an instance of one of the many caching providers available: an in-memory cache, a relational database cache, a cache based on a key value data store using Redis, a memcached-based cache, a Microsoft Azure cache, and even a cache based on Amazon DynamoDB.
  • Sessions: These are enabled by the SessionFeature ServiceStack plugin and rely on the caching component when the AuthFeature plugin is not enabled. Every service or controller powered by ServiceStack has an ISession property that provides read and write access to the session data. Each ServiceStack request automatically has two cookies set: an ss-id cookie, which is a regular session cookie, and an ss-pid cookie, which is a permanent cookie with an expiry date set far in the future. You can also gain access to a typed session as part of the AuthFeature plugin that will be explored next.