Sunday, 1 September 2013

Wire up a chain of responsibility with Castle Windsor

As part of the greenfield project I'm currently working on I decided that I'd use the chain of responsibility design pattern, but it took me a little while to work out how to set up Castle Windsor to support this.  It's pretty simple, but the stuff I found on the interwebs all seemed to be slightly out of date, so I thought I'd explain it here.

The short version is you can use the 'DependsOn' and 'Dependency.OnComponent<T, U>' methods when registering your components to do this pretty easily.  You can use an installer that looks something like this:
public class ChainOfResponsibilityInstaller : IWindsorInstaller
{
 public void Install(IWindsorContainer container, IConfigurationStore store)
 {
  container.Register(Component.For<IChainItem>()
         .ImplementedBy<ChainItemOne>()
         .DependsOn(Dependency.OnComponent<IChainItem,ChainItemTwo>()),
         Component.For<IChainItem>()
          .ImplementedBy<ChainItemTwo>()
          .DependsOn(Dependency.OnComponent<IChainItem, ChainItemThree>()),
         Component.For<IChainItem>()
           .ImplementedBy<ChainItemThree>());
 }
}

I've put a very basic project up on GitHub - https://github.com/StephenFriend/ChainOfResponsibility-with-Castle - to demonstrate an actual working solution.

Monday, 24 June 2013

Replacing Forms Authentication with the Session Authentication Module

In this post I'm going to run through how to use the SessionAuthenticationModule (SAM) (part of Windows Identity Foundation (WIF) in .Net 4.5) for authentication and authorization in a simple MVC application, replacing Forms Authentication. It won't be production code, but if after reading this you'd like to see a more complete Membership and Identity management library take a look at Brock Allen's Membership Reboot on GitHub https://github.com/brockallen/BrockAllen.MembershipReboot

The solution that goes along with this post is available at https://github.com/StephenFriend/AuthWithWIFAndSAM and it will probably be easier to look at the code as you read this. In the walkthrough below, I've used Visual Studio 2012 and there are different tagged commits, so that it's easy to see the changes that are made as we move from Forms Authentication to using the Session Authentication Module.

First, I'll set up an extremely simple solution using forms auth.  If you've cloned from github, simply type git checkout -f formsAuth

The first step is to create a new MVC4 app (imaginatively called 'DemoSite' in the code), using the 'Internet Application' Project template.  Next we want to amend the Web.config file at the root of the MVC site. 

In the controllers folder create a Home controller using the 'Empty MVC Controller' template from the drop-down in the scaffolding options section of the dialogue.  The code for the Home Controller should look like this:
[Authorize]
public class HomeController : Controller
{
 [AllowAnonymous]
 public ActionResult Index()
 {
  return View();
 }

 public ActionResult MyStuff()
 {
  return View();
 }
}

Note the use of the 'Authorize' attribute on the whole class and the 'AllowAnonymous' attribute on the 'Index()' method.  This should mean that anyone is able to access the Index view, but only users that are authorized can access the MyStuff view.

Next up let's create an Account controller.  The code for this will look like this initially:
public ActionResult Login()
{
   return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginInput model)
{
   if (ModelState.IsValid && LoginDetailsAreValid(model))
   {
    FormsAuthentication.SetAuthCookie(model.Email, false);
    return RedirectToAction("MyStuff", "Home");
   }

   ModelState.AddModelError("", "The user name or password provided is incorrect.");
   return View(model);
}

// In the real world this would be likely be a call to the database to get the user details, with a validation 
// that the user exists and that their password is correct.  See WebMatrix.WebData.SimpleMembershipProvider.ValidateUser()
// for an example (download the ASP.Net web stack here: http://aspnetwebstack.codeplex.com/)
private bool LoginDetailsAreValid(LoginInput loginDetails)
{
 return (string.Compare(loginDetails.Email, "you@example.com",
         StringComparison.InvariantCultureIgnoreCase) == 0 &&
   string.Compare(loginDetails.Password, "password", StringComparison.Ordinal) == 0);
}

In order for this to compile you'll also need to create a LoginInput class (in the Models folder), which is a simple View Model that we'll use to create the login view and user input.  It should look like this:
public class LoginInput
{
 [Required]
 public string Email { get; set; }
 [Required]
 [DataType(DataType.Password)]
 public string Password { get; set; }
}

The end point of this first stage is to create the views that go with the various controller actions. Home/Index looks like this:
@{
    ViewBag.Title = "Index";
}

Welcome to the demo

@Html.ActionLink("Login", "Login", "Account") @Html.ActionLink("My Stuff", "MyStuff", "Home")

Account/Login looks like this:
@model DemoSite.Models.LoginInput

@{
    ViewBag.Title = "Login";
}

Login

@if (User.Identity.IsAuthenticated) { You are already logged in as @User.Identity.Name
} else { using (Html.BeginForm()) { @Html.ValidationSummary()
@ViewBag.Title @Html.EditorForModel()
} }

and Home/MyStuff looks like this:
@{
    ViewBag.Title = "MyStuff";
}

Congratulations, you're authenticated


If you start up the website now, you should be able to log in (as you@example.com, password = 'password') and if you check your cookies, you will see that a cookie called .ASPXAUTH has been created.  If you try to access Home/MyStuff without logging in you will be automatically redirected back to Account/Login

Now, we're going to stop using Forms Authentication, initially not replacing it with anything.  (Use git checkout -f noAuth to see the code in the repo).

To start, go to the web.config file and change the authentication node from:

  

to:

This means that the FormsAuthenticationProvider module will no longer be loaded at application start-up.  Once you've done this, you'll see that if you log on you'll be presented with a 401 error when you are redirected to 'MyStuff'.  If, however, you check your cookies, you'll see that the call to FormsAuthentication.SetAuthCookie in the AccountController has set a cookie, but there is no provider specified so the 401 error is displayed on actions that have an 'Authorize' attribute.

In order to use the SAM module you will need to alter your web.config so that includes the following elements in the <config sections> element:

The first of these is to "configure a service or application to use Windows Identity Foundation" [1], the second names the configuration section for federation configuration, which you'll need to add to the config file:

    
      
    
  

The default configuration requires SSL, so you will need this section if you don't want to sort out setting up SSL for this example.

Under <system.webServer><modules> you will need to add the following so that the SessionAuthenticationModule is added to the ASP.Net pipeline.:


In order to have access to the classes you have just configured, you will also need to add references to System.IdentityModel and System.IdentityModel.Services to your project.

Finally, you need to alter the Account controller to look like this:
public class AccountController : Controller
    {
       public ActionResult Login()
       {
           return View();
       }

       [HttpPost]
       public ActionResult Login(LoginInput model)
       {
           if (ModelState.IsValid && LoginDetailsAreValid(model))
           {
               WriteAuthCookie(model.Email);
               return RedirectToAction("MyStuff", "Home");
           }

           ModelState.AddModelError("", "The user name or password provided is incorrect.");
           return View(model);
       }

        // In the real world this would be most likely be a call to a database to get the user details, with validation 
        // that the user exists and that their password is correct.  See WebMatrix.WebData.SimpleMembershipProvider.ValidateUser()
        // for an example (download the ASP.Net web stack here: http://aspnetwebstack.codeplex.com/)
        private bool LoginDetailsAreValid(LoginInput loginDetails)
        {
            return (string.Compare(loginDetails.Email, "you@example.com",
                                   StringComparison.InvariantCultureIgnoreCase) == 0 &&
                    string.Compare(loginDetails.Password, "password", StringComparison.Ordinal) == 0);
        }

        private void WriteAuthCookie(string userEmail)
        {
            var claims = new List();
            claims.Insert(0, new Claim(ClaimTypes.Name, userEmail)); 
            var claimsId = new ClaimsIdentity(claims, "Password");
            var cp = new ClaimsPrincipal(claimsId);
            var sam = FederatedAuthentication.SessionAuthenticationModule;
            var token = new SessionSecurityToken(cp);

            sam.WriteSessionTokenToCookie(token);
        }
    }

As you can see the new WriteAuthCookie method deals with persisting the authentication details to a cookie.  In it we create a new Name claim (the only claim we use in this example), that is then used to create a ClaimsIdentity, which in turn is used to create a new ClaimsPrinciple that is then persisted to a cookie.
Once you have logged in, if you check your cookies, you should see that you have a new 'FedAuth' cookie, which is what the SAM module uses.  If you then go back to Account/Login you should see that the claim of 'Name' is used for the User.Identity.Name property that is displayed on that page if you're logged in.

[1] http://msdn.microsoft.com/en-us/library/hh568638.aspx - MSDN WIF Configuration Schema

Monday, 10 June 2013

How not to manually manage Garbage Collection

Sometimes code tells you something about the person that wrote it.  I've had the pleasure of working with a codebase that contains the following code*:
while (MainApplicationWork())
{
 GC.Collect();
 GC.WaitForPendingFinalizers();
 GC.Collect();
 GC.WaitForPendingFinalizers();
}

NullMyObjectGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers(); 

Which I think bears some scrutiny - whenever you see a call to GC.Collect your .Net spidey sense should be going bonkers.

Code like this is dotted throughout the suite of applications this snippet comes from, specifically this:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();

which implies that this is standard practice for the dev that wrote it, rather than the response to a problem.  It's conceivable that this person has done a lot of performance tests and could demonstrate that all the calls to GC.Collect are justified.  Or more formally, it's a logical possibility, like the sky being green or everyone from Birmingham having six fingers on their right hands.

Unfortunately because the code is proprietary I can't share the full horror and give the performance metrics to demonstrate how truly awful this is - for instance, the application that contains the top snippet calls GC.Collect() at least four times for every iteration of the while loop.  However what I can do is examine this code, look at why you might do something like this and try to show that the code tells you that the person who wrote it doesn't really understand it.

There are many sources that tell devs to not call GC.Collect() [1, 2], however there are some circumstances when it might be the right thing to do.  According to Microsoft you should "Use the Collect method when there is a significant reduction in the amount of memory being used at a defined point in your application's code."[3]  Rico Mariani also offers this piece of advice for when you might call GC.Collect, "if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die."[4]

At first glance this code doesn't seem to fit that last piece of advice, since it sits in a while loop, however the method that is used for the loop termination criterion (MainApplicationWork()) effectively returns false when there are no more records for the application to process.  Those records do not arrive in a regular fashion, so it is arguable that this is an event that occurs repeatedly, but is irregular (perhaps akin to the canonical example of a user closing a windows form - it might happen multiple times, but it's not a predictable event and so the GC algorithm self-tuning will not work).

When the call to GC.Collect() is made it "Forces an immediate garbage collection of all generations."[5]  Part of this process involves moving pointers from the finalization queue to the freachable queue for all objects with Finalizer methods that have been found to be garbage (i.e. are unreachable).  Interestingly this resurrects the objects you are trying to get rid of because there is now a reachable reference to them (on the freachable queue, which is considered a root) and they will only become unreachable again once their finalizers have been run by the Finalization thread (which runs automatically whenever there are objects in the freachable queue).

Because of this it is recommended[6] to call GC.WaitForPendingFinalizers after GC.Collect as this forces the current thread to wait until all the finalizers in the objects you are trying to clear up have been executed and thus avoids the objects getting promoted to Gen1.  Given that we've just resurrected some objects, it is recommended to call GC.Collect again to finally release the memory of all the objects that have just been finalized. So you should end up with:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

But in this codebase there is a further call to GC.WaitForPendingFinalizers which does, ummmm, precisely nothing since the only compaction/garbage collection that takes place as part of the second call to GC.Collect() is of the objects on the heap that have just been finalized.  Nothing else has changed in the application in the meantime since both GC.Collect() and GC.WaitForPendingFinalizers() block the current thread.

Does it do any harm?  Probably not (although that requires some actual performance metrics to be confident on), but what it does shout is that this snippet is a piece of cargo-cult programming, repeated through a codebase, no doubt with the best of intentions, but almost certainly for no good reason and very likely damaging application performance.


* more or less - the application method names have been changed to protect the innocent
1. http://blogs.msdn.com/b/ricom/archive/2003/12/02/40780.aspx - Rico Mariani "Two things to avoid for better memory usage"
2. http://msdn.microsoft.com/en-us/library/ff647790.aspx - MS Patterns & Practices "Improving Managed Code Performance"
3. http://msdn.microsoft.com/en-us/library/bb384155.aspx - MSDN "Induced Collections"
4. http://blogs.msdn.com/b/ricom/archive/2004/11/29/271829.aspx - Rico Mariani "When to call GC.Collect()"
5. http://msdn.microsoft.com/en-us/library/xe0c2357.aspx - MSDN Library GC.Collect definition
6. http://msdn.microsoft.com/en-us/library/ff647790.aspx - MS Patterns & Practices "Improving Managed Code Performance"

Sunday, 26 May 2013

AngularJS Tutorial and .Net Web API (part 5)

In this blog post I'll look at getting steps 9, 10 & 11 of the AngularJS tutorial running on top of the .Net Web API (http://docs.angularjs.org/tutorial/step_09 http://docs.angularjs.org/tutorial/step_10). None of these tutorials requires changes to the .Net code, so this should be fairly straightforward.

First step 9. Do the usual git checkout thing one, other or both the original AngularJS tutorial code and this version. git checkout -f step9 for the .net version.

Copy app/js/filters.js from the Angular tutorial into the Scripts directory of the .Net project. Update Scripts/app.js to register the dependency on the phonecatFilters module. Update Views/Home/Index.cshtml to include a reference to the new Scripts/filters.js file. Update the Angular template (AngularPartials/phone-detail.html) to use the new filter. Ummm, that's it - behold the cross or the tick under GPS and Infrared on the phone-detail page.

On to step 10 - for the .Net code use git checkout -f step10.
Just follow along with the AngularJS tutorial. Update Scripts/controllers.js and update the template AngularPartials/phone-detail.html to change the main image source and add the 'ng-click' attribute to the smaller images. Finally copy across the latest version of app/css/app.css so that you get the cursor changing to 'pointer' when hovering over the click-able images.

And so finally onto step 11.

This tutorial is about tidying up the Angular code so that some of the implementation details are abstracted away, in effect moving the call to the .Net Web API to a different place. As such it means we don't need to touch the .Net code, however there is a change to the way in which AngularJS makes its requests, which needs a bit of attention.

Working along with the original AngularJS tutorial, amend Views/Home/Index.cshtml to include references to Scripts/services.js and Scripts/angular-resource.js. This latter should exist already (coming down with the nuget package), but you'll need to copy the services file into the Scripts directory. You'll also need to amend the registration of the 'Phone' service in the Scripts/services.js file to reference the Web API controller.
angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
         return $resource('api/phones/:phoneId', {}, {
            query: {method:'GET', isArray:true}
  });
});
Note the slight differences here from the AngularJS tutorial. First the path is to api/phones, secondly when the 'query' is set up I've removed the paramDefaults array because in its original state it causes Angular to make an http request to api/phones/phones when there is no parameter specified, which we don't want because that makes the Web API try to return us a PhoneDetail item with the id 'phones'. In the original tutorial this will cause a call to /phones/phones.json which works perfectly.

Now you just need to register the services in app.js, then amend the Scripts/controllers.js to use the service. This should be exactly the same as the Angular tutorial.

That's it - hopefully the AngularJS tutorial now looks the same live demo http://angular.github.io/angular-phonecat/step-11/app/#/phones

Friday, 24 May 2013

AngularJS Tutorial and .Net Web API (part 4)

In this post I'll get step 8 of the AngularJS tutorial http://docs.angularjs.org/tutorial/step_08 running on top of the .Net Web API.  This tutorial uses more data, so we'll be plumbing in further ApiController actions to connect the Angular code to the data source (JSON text files).  I'll also take a look at some of the under-the-covers stuff about how the ApiController works when resolving requests to actions.

The code for the Web API can be got by using git checkout -f step8.

As per the Angular tutorial, use git to checkout out step 8 of the original tutorial, then copy all the phone model json files from app/phones (i.e. everything apart from phones.json, which you should have edited previously and don't want to overwrite).  Unfortunately all of these files contain a reference to an image file that won't work with our website directory structure, so you'll need to amend the paths in the 'images' section of the JSON files so that the paths point to "Content/img/phones" rather than "img/phones".

Following along with the original tutorial we're going to update the Angular controller (Scripts/AngularControllers/controller.js) so that it makes an http get request for the data the phone-detail view requires.  However it's going to call an action on our Phones controller, rather than make a direct call to a JSON file.  So the function call should look like this:
function PhoneDetailCtrl($scope, $routeParams, $http) {
    $http.get('api/phones/' + $routeParams.phoneId).success(function (data) {
        $scope.phone = data;
    });
}
Once again the path is to 'api/phones' so we'll be calling the Phones controller.  Note that we're also passing the phoneId, which in this case is a string.

Now update the AngularPartials/phone-detail.html file so that it matches the one from the AngularJS tutorial (app/partials/phone-detail.html).

In order for this to work we will need to update the PhonesController class so that it has a method that can respond to this call.
public PhoneDetail GetPhoneBy(string id)
{
 return this.phoneRepo.GetBy(id);
} 
There are a couple of things to note here.  First and most obviously, there's no 'PhoneDetail' class or GetBy(id) method on the repository - we'll add those in shortly.  More subtly, it's also worth thinking about what the ApiController does when it receives a Get request.  The base ApiController class uses a convention whereby it will try to match requests to method names that contain the the request type and the route parameters, (in this case 'Get' and a string).  What this means is that you cannot have two methods names that contain the same request verb (in this case 'get') that have the same signature in your ApiController.  It also implies that it doesn't matter what your methods are called from the application's point of view, those method names are really just for your benefit. 

If you do have two methods with the request type in their name and the same signature, the framework will throw a System.InvalidOperationException which will be caught and transformed into a 500 error response. For further detail download the code from http://aspnetwebstack.codeplex.com/ and take a look at System.Web.Http.Controllers.ActionSelectorCacheItem.SelectAction. Look for:
throw Error.InvalidOperation(SRResources.ApiControllerActionSelector_AmbiguousMatch, ambiguityList);
and
System.Web.Http.Dispatcher.SendAsync
Ultimately this means that Angular will return an empty template and you'll have to track down what the 500 error means.

Having said that, our controller has a single 'Get' method that takes a string as a parameter, so no issues there. It then calls a non-existent method on the repository class.  So, let's update the repository interface and implementation accordingly.
public interface IPhoneRepository
{
 IEnumerable<Phone> GetAll();
 PhoneDetail GetBy(string id);
}

public class FileDrivenPhoneRepository : IPhoneRepository
{
 public IEnumerable<Phone> GetAll()
 {
  string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
  var phonesText = System.IO.File.ReadAllText(dataDirectory +"/phones.json");
  return JsonConvert.DeserializeObject<List<Phone>>(phonesText);
 }

 public PhoneDetail GetBy(string id)
 {
  string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
  var phoneText = System.IO.File.ReadAllText(dataDirectory + "/" + id + ".json");
  return JsonConvert.DeserializeObject<PhoneDetail>(phoneText);
 }
}
Finally I'll create a new PhoneDetail Model (or ViewModel if you prefer).  Add a class 'PhoneDetail' to the Models folder:
public class PhoneDetail
{
 public string additionalFeatures { get; set; }
 public AndroidDetail android { get; set; }
 public string[] availability { get; set; }
 public BatteryDetail battery { get; set; }
 public CameraDetail camera { get; set; }
 public ConnectivityDetail connectivity { get; set; }
 public string description { get; set; }
 public DisplayDetail display { get; set; }
 public HardwareDetail hardware { get; set; }
 public string id { get; set; }
 public string[] images { get; set; }
 public string name { get; set; }
 public SizeAndWeightDetail sizeAndWeight { get; set; }
 public StorageDetail storage { get; set; }

 public class AndroidDetail
 {
  public string os { get; set; }
  public string ui { get; set; }
 }

 public class BatteryDetail
 {
  public string type { get; set; }
  public string talkTime { get; set; }
  public string standbyTime { get; set; }
 }

 public class CameraDetail
 {
  public string[] features { get; set; }
  public string primary { get; set; }
 }

 public class ConnectivityDetail
 {
  public string bluetooth { get; set; }
  public string cell { get; set; }
  public bool gps { get; set; }
  public bool infrared { get; set; }
  public string wifi { get; set; }
 }

 public class DisplayDetail
 {
  public string screenResolution { get; set; }
  public string screenSize { get; set; }
  public bool touchScreen { get; set; }
 }

 public class HardwareDetail
 {
  public bool accelerometer { get; set; }
  public string audioJack { get; set; }
  public string cpu { get; set; }
  public bool fmRadio { get; set; }
  public bool physicalKeyboard { get; set; }
  public string usb { get; set; }
 }

 public class SizeAndWeightDetail
 {
  public string[] dimensions { get; set; }
  public string weight { get; set; }
 }

 public class StorageDetail
 {
  public string flash { get; set; }
  public string ram { get; set; }
 }
}
Once again that I'm going with the convention of Camel case in my C# class to reduce the amount of work I have to do with the copied code for the Angular templates.  Also, I'm struck again by how clever newtonsoft json library is when it comes to transforming a fairly intricate object structure to and from JSON.  I guess that's  why MS use it under the hood.

Finally you'll need to update the CSS in Content/app.css to match what's in app/css/app.css in the Angular tutorial.

Hopefully you now have a working version of step8 of the AngularJS tutorial.

Monday, 20 May 2013

AngularJS Tutorial and .Net Web API (part 3)

This is the third post in a series about using the .Net Web API to run the AngularJS tutorial app on. So far all that's happened is we've created a project that runs step5 of the tutorial.

In this post I'll move onto steps 6 & 7 http://docs.angularjs.org/tutorial/step_06 & http://docs.angularjs.org/tutorial/step_07
Step 6 of the AngularJS tutorial is about updating the template to use images and generate links to individual phones that for the moment don't go anywhere.

Check out step 6 with git checkout -f step6

If you look at app/index.html in the original tutorial directory (or just follow the AngularJS tutorial) you'll see that the content of the 'li' element has changed. Simply copy the new code over the top of the old:
  • {{phone.name}} {{phone.snippet}}
  • In order for this to work, you'll need to update your css, add the images to the project and amend the JSON phones document so that the path to the images is correct.
    So first grab the css from the app/css/app.css and paste it into Content/app.css. Then, create a new 'img' folder in the 'Content' folder of your .Net project. Within that create a 'phones' folder then copy the images from the Angular tutorial directory ('app\img\phones') into this new folder.

    If you try to run the application, no images will be rendered on the page because the paths don't match, so you'll need to update your JSON data file accordingly. Simply substitute img/ for Content/img/ in App_Data/phones.json. If you run the application now, you should see the same page as you do on the AngularJS tutorial live demo http://angular.github.io/angular-phonecat/step-6/app/
    If you click on any of the links, you'll soon realise that they don't work.

    Step7
    Onto step 7, which has much more of the meat of what AngularJS is all about, using Angular's routing capabilities in conjunction with different views and controllers. Again, if you're used to .Net MVC then everything here should be pretty easy to get your head around, but it's definitely the point for me at which I started thinking, "why am I using 2 sets of routing?" I'm not sure I have an answer yet, but I could imagine a hybrid app which has both .Net MVC and Angular MVC in it.

    use git checkout -f step7.

    Again, checkout the correct step of the AngularJS tutorial, then copy app/js/app.js into the 'Scripts' folder at the root of the .Net MVC project. This defines the routes and controllers for Angular's MVC structure.

    Next, update Views/Home/Index.cshtml so that it now has at the top and has a reference to after the reference to angular.js in the head (remember that Views/Home/Index.cshtml is pretty much exactly the same as app/index.html in the AngularJS tutorial). Finally, delete most of the content in the body of Index.cshtml and replace it with

    Now, create a new folder called 'AngularPartials' at the root of your .Net MVC project and add two HTML files to it, 'phone-list.html' and 'phone-detail.html', these should be exactly the same as the Angular app/partials/phone-detail.html and app/partials/phone-list.html files. Now you just need to update the Scripts/app.js file to reflect the paths to those partials, so it should look like this:
    angular.module('phonecat', []).
      config(['$routeProvider', function($routeProvider) {
      $routeProvider.
          when('/phones', {templateUrl: 'AngularPartials/phone-list.html',   controller: PhoneListCtrl}).
          when('/phones/:phoneId', { templateUrl: 'AngularPartials/phone-detail.html', controller: PhoneDetailCtrl }).
          otherwise({redirectTo: '/phones'});
    }]);
    


    Note that the only changes are to the 'templateUrl:' values. Amend 'Scripts/controllers.js' to include the definition for PhoneDetailCtrl
    function PhoneDetailCtrl($scope, $routeParams) {
    $scope.phoneId = $routeParams.phoneId;
    }

    The application should now be working, with links to the 'TBD' view for the phone details.

    Wednesday, 15 May 2013

    AngularJS Tutorial and .Net Web API (part 2)

    This post builds on the previous post about running the AngularJS tutorial application on top of the .Net Web API Framework.  All it's going to do is tidy things up a bit, introducing a repository for the controller to get the data from, rather than it having hard-coded JSON.  Along the way we'll use the DependencyResolver so that our controller isn't creating its own dependencies.

    You should be able to see all the code by using 'git checkout -f step5b'.  Once again, you can either just read the code in its finished state, or work from scratch.

    First let's set up our data source, copy the file 'app/phones/phones.json' from the AngularJS tutorial directory to the App_Data folder in the MVC project directory.

    In the models directory create a new 'Phone.cs' class.  Because of the conventions used by the JSON serialization library, either the 'Models/Phone' class can use Camel case for its properties, or you can change the 'Scripts/AngularControllers/controller.js' file and the 'Views/Home/Index.cshtml' file so that the property names use Pascal case to match your model class.  No-one dies either way.  I've chosen to make the C# class match the AngularJS tutorial, because I only have to make the change in one place, the compiler can warn me of any problems if I use the wrong case somewhere else and I won't keep having to change the other files as I work through the AngularJS tutorial.

    public class Phone
    {
    	public int age { get; set; }
    	public string carrier { get; set; }
    	public string id { get; set; }
    	public string imageUrl { get; set; }
    	public string name { get; set; }
    	public string snippet { get; set; }
    }


    Create a data access folder at the root of the project and in it create an IPhoneRepository.cs file.  This should contain the IPhoneRepository interface that has a single method, GetAll()
    namespace AngularJSTutorial.DataAccess
    {
        public interface IPhoneRepository
        {
            IEnumerable<Phone> GetAll();
        }
    }
    

    In the same folder create a FileDrivenPhoneRepository class that implements IPhoneRepository.  This concrete implementation will read from the JSON file (our data store) in the App_Data.

    using System;
    using System.Collections.Generic;
    using AngularJSTutorial.Models;
    using Newtonsoft.Json;
    
    namespace AngularJSTutorial.DataAccess
    {
        public class FileDrivenPhoneRepository : IPhoneRepository
        {
            public IEnumerable<Phone> GetAll()
            {
                string dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
                var phonesText = System.IO.File.ReadAllText(dataDirectory +"/phones.json");
                return JsonConvert.DeserializeObject<List<Phone>>(phonesText);
            }
        }
    }

    Next amend the PhonesController so that its constructor has an IPhoneRepository as a parameter and the 'GetAll' method uses that repository to get it's list of phones:
     public class PhonesController : ApiController
        {
            private readonly IPhoneRepository phoneRepo;
    
            public PhonesController(IPhoneRepository phoneRepo)
            {
                this.phoneRepo = phoneRepo;
            }
    
            public IEnumerable<Phone> GetAll()
            {
                return this.phoneRepo.GetAll();
            }
        }
     
    Make sure you add the relevant 'using' statements as well, or the project won't compile.

    Now you just need to ensure that the IPhoneRepository dependency is injected.  Create a folder called 'Infrastructure' at the root level of the project and add a class to it called 'SimpleResolver' (or think of a good name).  This class will implement the IDependencyResolver and will do one thing only - it will construct the PhonesController class and manage its dependencies (well, 'dependency' in this case).
    public class SimpleResolver : IDependencyResolver
        {
            public IDependencyScope BeginScope()
            {
                return this;
            }
    
            public object GetService(Type serviceType)
            {
                if (serviceType == typeof (PhonesController))
                {
                    var repo = new FileDrivenPhoneRepository();
                    return new PhonesController(repo);
                }
    
                return null;
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                return new List<object>();
            }
    
            public void Dispose()
            {
                
            }
        }


    Finally we need to make sure that this is what the application uses when creating the PhonesController, so add the following line to the Application_Start() method of the Global.asax.cs file:
    GlobalConfiguration.Configuration.DependencyResolver = new SimpleResolver();


    Also ensure that you have the following 'using' statement at the top of the file:
    using AngularJSTutorial.Infrastructure;


    If you're familiar with creating your own ControllerFactory as part of a .Net MVC website, this probably feels pretty similar.

    While we're now in the slightly odd position of deserializing a JSON file only to let the framework re-serialize it in order for AngularJS to use it, I think this represents a more usual scenario of how the framework can be used - most likely your application will sit on top of a database of some sort and your repository will pull out the required data from that.

    It's worth noting the bit of magic that the framework performs in the PhonesController now, where it automatically serializes the objects to JSON.  This is because the Scripts/controller.js method 'PhoneListCtrl' calls $http.get(), which under the covers sets the Accept header of the request to 'application/json, text/plain, */*'.  When the Web API receives a request it interrogates the Accept header in order to decide what kind of formatter it should use to serialize data for the response and ultimately uses the Newtonsoft.Json library for the serialization to JSON.