How to Moq private method calls when testing a public method

One scenario that I see once in a while when writing unit tests is when I have a public method that I want to test, but in order to test that public method, I have to set up all the context for the private method calls that happen inside the public method. Here’s an example:

public class MyClass
    {
        public int MyPublicMethod(MyDto dto)
        {
            var condition = CheckCondition(dto);
            if (condition)
            {
                return Foo(dto);
            }
            return Bar(dto);
        }

        private bool CheckCondition(MyDto dto)
        {
            // imagine this method has lots of checks & other logic
            // (things that use other dependencies and take some effort to set up the test scenario)
            return dto.Id > 0;
        }

        private int Foo(MyDto dto)
        {
            return 1;
        }

        private int Bar(MyDto dto)
        {
            return 2;
        }
    }

My goal is to test the method MyPublicMethod. I’d like to make sure it’s calling Foo or Bar correctly. But I don’t want to set up all the data that is needed to be checked inside the CheckCondition method. I could have a lot of branching and other private method calls in there, and I don’t want to prepare a whole scenario for it at this time. I just want to focus on the public method logic.

The thing is, I couldn’t find a way to do exactly that (to mock a private method) using Moq. But there’s a workaround using Moq.Protected that works well.

The first step is to make the private method a protected virtual. So the class would become:

public class MyClass
    {
        public int MyPublicMethod(MyDto dto)
        {
            var condition = CheckCondition(dto);
            if (condition)
            {
                return Foo(dto);
            }
            return Bar(dto);
        }

        protected virtual bool CheckCondition(MyDto dto)
        {
            // imagine this method has lots of checks & other logic
            // (things that use other dependencies and take some effort to set up the test scenario)
            return dto.Id > 0;
        }

        private int Foo(MyDto dto)
        {
            return 1;
        }

        private int Bar(MyDto dto)
        {
            return 2;
        }
    }

Now I can use Moq.Protected and the generic Setup method to mock my private (now protected virtual) CheckCondition method.

[TestFixture]
    public class MyClassTests
    {
        [Test]
        public void MyPublicMethod_WhenConditionIsTrue_CallFoo()
        {
            var mock = new Mock<MyClass>();

            var dto = new MyDto();
            mock.Protected().Setup<bool>("CheckCondition", dto).Returns(true);

            var result = mock.Object.MyPublicMethod(dto);
            Assert.AreEqual(1, result);
        }

        [Test]
        public void MyPublicMethod_WhenConditionIsFalse_CallBar()
        {
            var mock = new Mock<MyClass>();

            var dto = new MyDto();
            mock.Protected().Setup<bool>("CheckCondition", dto).Returns(false);

            var result = mock.Object.MyPublicMethod(dto);
            Assert.AreEqual(2, result);
        }
    }

The two possible downsides:

  • The Setup method takes a string for the method name so refactoring tools probably won’t detect that. (the worst scenario however is getting a test fail, not the end of the world)
  • You have to change your method from private to protected virtual. Some people will feel uncomfortable about this.

I’ve seen that some commercial tools claim to support proper private method mocking, like Telerik JustMock and Typemock Isolator, but I haven’t tried them yet.

Consuming a list in batches using multiple threads (C# TPL)

Recently I had to implement some code to consume an array of integers in batches, and process the batches using multiple threads.

This is what solved my problem:

class Program
    {
        static void Main(string[] args)
        {
            // initialize the collection
            var list = new List<int>();
            for (var i = 1; i <= 1000; i++)
            {
                list.Add(i);
            }

            const int batchSize = 10;
            const int maxDegreeOfParallelism = 5;

            Parallel.ForEach(Partitioner.Create(0, list.Count, batchSize), 
                new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, 
                range =>
            {
                // create the batch
                string s = string.Empty;
                for (var index = range.Item1; index < range.Item2; index++)
                {
                    s += list[index] + " ";
                }

                ProcessBatch(s);                
            });

            Console.WriteLine("Finished.");
            Console.ReadLine();
        }

        public static void ProcessBatch(string s)
        {
            Console.WriteLine("Thread [" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]: " + s);
            System.Threading.Thread.Sleep(1000);
        }
    }

AngularJS custom directives – data binding and template function parameters

Recently I had an experience creating custom directives with AngularJS. You can create a custom directive if you want parts of your UI packed as reusable components. In your directive you can embed HTML, a scope that is isolated from the main/parent scope and controller logic. You can then declare the directive in different parts of your application.

I thought I would register here two basic recipes, for my own record.

Data binding

This first example shows the difference between using “=” (two way) and “@” (read only) in the directive scope, when data binding.

The HTML:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>AngularTest</title>

    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.js"></script>
    <script src="~/Scripts/MyApp.js"></script>

</head>
<body>
    <div data-ng-app="myApp" data-ng-controller="myController">

        <h1>My angular app</h1>       

        <p>Client name from parent scope: {{client.name}}. Client name from parent scope: {{client.postcode}}</p>

        <div data-my-directive="" data-client-name="client.name" data-postcode="{{client.postcode}}" />

    </div>
</body>
</html>

The javascript:

var app = angular.module('myApp', []);

app.controller("myController", function ($scope) {
    $scope.client = { name: 'Leo', postcode: 'SW11 1TN' };    // parent scope
});

app.directive('myDirective', function () {
    return {
        restrict: 'AE',  //E = element, A = attribute, C = class, M = comment         
        replace: 'true',
        scope: { // directive scope
            clientName: '=', // two way data binding
            postcode: '@' // read only data binding
        },
        template:
            '<div><p>Client name from directive: {{clientName}}. Postcode from directive: {{postcode}}</p>' +
            '<p><button data-ng-click="buttonClick()">Click me</button></p></div>',
        controller: myDirectiveController,
        link: function ($scope, element, attrs) { }
    };
});

function myDirectiveController($scope) {
    $scope.buttonClick = function () {
        $scope.clientName = "Sam";
        $scope.postcode = 'SW18 2JR'
    }
}

In this directive we have an isolated scope with two properties, client name and postcode. The client name is linked in a two-way data binding with the parent scope. When the directive updates the client name, the same property of the parent scope is also updated. The other property, postcode, is read from the parent scope, but any modifications to it are kept in the directive scope.

Before the button click:

Before the button click

After the button click (note the postcode on the parent scope hasn’t changed after the button click):

After the button click

Passing parameters to the template function

In your directive you can have a template function to provide the template HTML (instead of using an HTML string or a URL). You can also pass parameters to this template function, to render the template based on them. Here’s an example.

The HTML:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>AngularTest</title>

    <script src="~/Scripts/jquery-1.10.2.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.js"></script>
    <script src="~/Scripts/MyApp.js"></script>

</head>
<body>
    <div data-ng-app="myApp" data-ng-controller="myController">

        <h1>My angular app</h1>

        <div data-my-directive="a1" data-template-type="A"></div>

        <div data-my-directive="b1" data-template-type="B"></div>

    </div>
</body>
</html>

The javascript:

var app = angular.module('myApp', []);

app.controller("myController", function ($scope) {
});

function getTemplate(element, attrs) {

    var templateType = attrs.templateType;

    console.log(templateType);

    if (templateType == "A") {
        var html = '<div><p>My template - version A</p></div>';
        return html;
    }
    else if (templateType == "B") {
        var html = '<div><p>My template - version B</p></div>';
        return html;
    }
    return '<div></div>';
}

app.directive('myDirective', ['$compile', function ($compile) {
    return {
        restrict: 'AE', 
        replace: 'true',
        scope: {
        },
        template: '', // template is assigned in the 'link' function
        link: function ($scope, element, attrs) {
            var templateHtml = getTemplate(element, attrs);
            element.html(templateHtml).show();
            $compile(element.contents())($scope);
        }
    };
}]);

We’re passing the template type as a parameter in the HTML declaration of the directive (data-template-type=”A” or data-template-type=”B”). In the directive we’re creating and assigning the template from the link function, not from the usual template property, and we’re using $compile for that. The parameters declared in the directive are accessed via the attrs argument.

The end result (the template function renders the template based on a parameter given):

Passing parameters to the template function

Working around a few issues with XDocument.Parse

I had a task these days to save the response of a web service call to a log table to investigate what data was being returned, during QA testing. I wanted to save the XML in a nicely formatted way, with indentation, to help reading. I came up with this static method in a helper class:

public static string FormatXml(string xml)
        {
            try
            {
                var doc = XDocument.Parse(xml);
                return doc.ToString();
            }
            catch (Exception)
            {
                return xml;
            }
        }

The method worked for some XML’s but not for others. Sometimes it failed to parse the XML string and was throwing an XmlException with:

Data at the root level is invalid. Line 1, position 1.

It was strange to get that exception because when debugging I couldn’t see any problem with the XML, it all looked fine. I copied and pasted it into a validator and it proved to be well formed. After some research I found the problem was a hidden character (zero width) in the first position of the string, character code 65279 or 0xFEFF. This character is a byte order mark – when something is being serialized to XML, depending on the encoding selected, the character 0xFEFF is inserted at the start of the document to indicate the encoding. I had no control over how the XML was being generated so to make my method work I had to remove that character manually.

Another error I was getting for some XML’s:

‘.’, hexadecimal value 0x00, is an invalid character. Line 1, position 1423.

That was being caused by another unprintable character, the null character \0 (or null terminator).

To fix both problems I just replaced the undesirable characters with an empty string. The final version of my method is this:

public static string FormatXml(string xml)
        {
            try
            {
                // remove the byte order mark if present
                xml = xml.Replace(((char)65279).ToString(CultureInfo.InvariantCulture), string.Empty);

                // remove the null character if present
                xml = xml.Replace("\0", string.Empty);

                var doc = XDocument.Parse(xml);
                return doc.ToString();
            }
            catch (Exception)
            {
                return xml;
            }
        }

How to prevent Visual Studio with Resharper from automatically closing or inserting braces

I’ve been using Visual Studio since version 2002 and one thing that I got used to is to manually close the braces in my code (parentheses and curly braces). I know some tools like Resharper offer the feature of automatically closing the braces for you, but I never really got used to that, I am more productive if I do it manually, so this feature is the first thing I disable when I install Resharper.

I’ve recently installed Visual Studio 2013 with Resharper 8 and was having problems disabling this feature. I disabled it in Resharper but was still getting the braces automatically closed. I was puzzled, I thought Resharper 8 had some bug related to that. I then found the cause: Visual Studio 2013 started offering the same feature (previous versions didn’t have it). So now I have to remove it from both Resharper and Visual Studio 2013 :-)

Here’s how to do:

In Resharper 8, you have to go to Resharper -> Options -> Editor – Editor Behavior -> Braces and Parenthesis and uncheck “Auto-insert pair brackets, parentheses and quotes” and “Auto-insert closing brace”. You also need to go to IntelliSense -> Completion Behavior and uncheck “Automatically insert parentheses after completion”.

In Visual Studio 2013 you need to go to Tools -> Options -> Text Editor -> All Languages (or C#) and uncheck “Automatic brace completion”.

Get the last trade price of a stock in Excel using the Yahoo Finance API

I was looking for a way to access the Yahoo Finance API from Excel, in order to make a personal portfolio spreadsheet smarter. It is very doable, and I’ll give an example below using Excel 2013.

First I should mention this helpful page that explains the possible API parameters, have a look: Gummy Stuff Yahoo Data.

For the proof of concept we can start with a blank Excel spreadsheet. We’ll list the symbols of our stocks in the first column:

Excel with stock symbol list

If you don’t know the symbol for a company you can look at the Yahoo Finance website, start typing the company name in the look up field and the auto-complete box will show the symbols of the company on each stock exchange.

Yahoo Finance symbol look up

Now we need to find the Developer tab in our Excel ribbon.

Excel Developer tab

If the developer tab is not visible we can go to File -> Options -> Customize Ribbon -> and tick the Developer tab.

Excel show the Developer tab

In the Developer tab we click Insert and under ActiveX Controls we’ll select a Command Button to insert. We can place the button anywhere in the spreadsheet. After the button is placed we can click the Properties button in the Developer tab to give the command button a proper name and caption.

Excel show the Developer tab

If we double click the button we’ll go to the VBA code window, with a signature of the click event handler. We can start with the following code:

Private Sub updateButton_Click()
    Dim ws As Worksheet
    Set ws = ActiveSheet
    
    ' This will find the last cell that has content (a stock symbol) in column A
    ' In our example it is A4. We could hardcode the A4 value but this is helpful
    ' in case we add more rows to the column in the future
    Dim last As Integer
    last = ws.Range("A99999").End(xlUp).Row
    If last = 1 Then Exit Sub
    
    Dim symbol As String
    Dim i As Integer
    Dim result As String
    
    For i = 2 To last
        symbol = ws.Range("A" & i).Value
        If Not IsEmpty(symbol) And symbol <> vbNullString Then
            
            Debug.Print "A" & i & " " & symbol
            
        End If
   Next i
End Sub

It will just print the symbols from the first column in the debug window. To execute it we can click View -> Immediate Window and then press F5 (Run). The output will be like this:

VBA Immediate window

The next step is to add a reference to WinHTTP Services. We can go to Tools -> References and tick the box for Microsoft WinHTTP Services, version 5.1.

Excel reference to Microsoft WinHTTP Services

Next we can add a function to retrieve the last trade price from Yahoo.

Function GetStockInfo(symbol As String)

    ' This will return the company name and last trade price
    ' For more information on API parameters please see this page:
    ' http://www.gummy-stuff.org/Yahoo-data.htm

    Dim url As String
    url = "http://finance.yahoo.com/d/quotes.csv?s=" & symbol & "&f=l1n"
    
    Dim httpReq As New WinHttpRequest
    httpReq.Open "GET", url, True
    httpReq.Send
    httpReq.WaitForResponse
    
    Dim response As String
    response = httpReq.ResponseText
    
    GetStockInfo = response
End Function

And this is the integration of the function with the button click handler. The final version of the click handler will be this:

Private Sub updateButton_Click()
    Dim ws As Worksheet
    Set ws = ActiveSheet
     
    ' This will find the last cell that has content (a stock symbol) in column A
    ' In our example it is A4. We could hardcode the A4 value but this is helpful
    ' in case we add more rows to the column in the future
    Dim last As Integer
    last = ws.Range("A99999").End(xlUp).Row
    If last = 1 Then Exit Sub
     
    Dim symbol As String
    Dim i As Integer
    Dim result As String
     
    For i = 2 To last
        symbol = ws.Range("A" & i).Value
        If Not IsEmpty(symbol) And symbol <> vbNullString Then
             
            Debug.Print "A" & i & " " & symbol
            
            ' Empty the current values
            ws.Range("B" & i).Value = "0"
            ws.Range("C" & i).Value = ""
            
            ' Call the API
            result = GetStockInfo(symbol)
            
            ' Split the result string (it's comma-separated)
            Dim parts As Variant
            parts = Split(result, ",")
            
            ' Assign the new values
            ws.Range("B" & i).Value = parts(0)
            ws.Range("C" & i).Value = parts(1)
        End If
   Next i
End Sub

At this point the update button should just work. When clicked it will bring this result:

Excel displaying Yahoo Finance data - final result

Yahoo Finance is a very helpful repository of company information – and better yet, it’s free.

Using Castle Windsor for Dependency Injection with SignalR

Recently I was working with SignalR to create a real time diagnostics page, and I wanted to inject dependencies into my Hub class, using Castle Windsor. I’ll share the solution that worked for me.

Basically you need to create a dependency resolver class. Something like this:

public class SignalRDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver
    {
        private readonly IWindsorContainer _container;

        public SignalRDependencyResolver(IWindsorContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            _container = container;
        }

        public override object GetService(Type serviceType)
        {
            return TryGet(serviceType) ?? base.GetService(serviceType);
        }

        public override IEnumerable<object> GetServices(Type serviceType)
        {
            return TryGetAll(serviceType).Concat(base.GetServices(serviceType));
        }

        [DebuggerStepThrough]
        private object TryGet(Type serviceType)
        {
            try
            {
                return _container.Resolve(serviceType);
            }
            catch (Exception)
            {
                return null;
            }
        }

        private IEnumerable<object> TryGetAll(Type serviceType)
        {
            try
            {
                var array = _container.ResolveAll(serviceType);
                return array.Cast<object>().ToList();
            }
            catch (Exception)
            {
                return null;
            }
        }
    }

Then you can wire your dependency resolver in application initialization (Global.asax.cs).

public class MvcApplication : System.Web.HttpApplication
    {
        private IWindsorContainer _container;

        protected void Application_Start()
        {
            // Castle Windsor
            _container = new WindsorContainer();
            _container.Register(Component.For<IMyDependency>().ImplementedBy<MyDependency>());            

            // SignalR
            _container.Register(Classes.FromThisAssembly().BasedOn(typeof(IHub)).LifestyleTransient());   
            SignalRDependencyResolver signalRDependencyResolver = new SignalRDependencyResolver(_container);
            Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = signalRDependencyResolver;            
            RouteTable.Routes.MapHubs();

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

Note: if you’re using ASP.NET MVC, it’s important that you configure SignalR first in Application_Start, and MVC after it.

With those changes your Hub classes can have their dependencies injected, like this:

public class LogHub : Hub
    {
        private readonly IMyDependency _myDependency = null;

        public LogHub(IMyDependency myDependency)
            : base()
        {
            _myDependency = myDependency;
        }       
    }

Error when creating new IIS site in Powershell: New-Item : Index was outside the bounds of the array

Powershell has a number of cmdlets to manage IIS in Windows. A few days ago I was dealing with a Powershell script in which one of the steps was to create a website in IIS. It had something similar to this:

Set-ExecutionPolicy Unrestricted -Scope Process
Import-Module "WebAdministration"
New-Item IIS:\Sites\MySite -bindings @{protocol='http';bindingInformation=':8080:MySite'} -PhysicalPath C:\MySite

When trying to execute it I was getting the following error:

New-Item : Index was outside the bounds of the array.
At C:\temp\iis-test.ps1:3 char:1
+ New-Item IIS:\Sites\MySite -bindings @{protocol='http';bindingInformation=':8080 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [New-Item], IndexOutOfRangeException
    + FullyQualifiedErrorId : System.IndexOutOfRangeException,Microsoft.PowerShell.Commands.NewItemCommand

This happens to be a known bug, as discussed here. Someone from Microsoft wrote in the thread: “It is a product issue and we will fix it some day in future. The issue we found is that if there is no web sites, the new-website cmdlet does not work, showing the error message.”

The solution is simple, make sure you have at least 1 website created in IIS before running the script. It can be the “Default Web Site” that points to C:\inetpub\wwwroot.

Alternatively you can try a workaround to set a Registry key parameter that will switch the site ID generation from sequential mode to random. Read more about it here.

How to decode the Model column of the MigrationHistory table in EF Migrations

Recently I had to synchronize the entities of a C# application with its corresponding database objects. The application used EF code first with database migrations. There were multiple developers working with the project simultaneously so we ended up with some migrations in the __MigrationHistory table that weren’t making sense. Nobody was recognizing some of them so I wanted to view what was inside their (obscure) Model column to understand what the changes were about.

The Model column in the __MigrationHistory table is a serialized version of your EDMX. If you thought you didn’t have an EDMX because you were using EF code first, now you know you *do* have one, it’s just hidden :-)

The data type of the Model column is varbinary(max) so the first step in order to view its contents is to get a base64 representation of the binary stream.

MigrationHistory table Model column

Select from MigrationHistory

One way to get the Model column as base64 is by using T-SQL:

declare @binaryContent varbinary(max); 

select @binaryContent = Model
	from [dbo].[__MigrationHistory]
where migrationId = '201304071557122_InitialCreate'

select cast('' as xml).value('xs:base64Binary(sql:variable("@binaryContent"))', 
	'varchar(max)') as base64Content

Model column base64

The base64 that you get is your EDMX gzipped so our next step is to decompress it. Here’s a way to do using a console application:

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string modelBase64 = @"H4sIAAAAAAAEAN1ZS2/bOBC+L7D/QdBxgVqx20M3sFukeSyCrZMgSnstaGnsEEuRWpIy7N+2h/1J+xd2qJcp0rKdJ4JegojkfPMeztD//fPv+PMqY8ESpKKCT8Lh4CgMgCcipXwxCQs9f/cx/Pzp11/G52m2Cr43596bc0jJ1SS81zo/jiKV3ENG1CCjiRRKzPUgEVlEUhGNjo5+j4bDCBAiRKwgGN8WXNMMyg/8PBU8gVwXhE1FCkzV67gTl6jBFclA5SSBSThdJid5zmhCNIoyHFQUg7MZgmhY6TA4YZSgXDGweRjkH46/KYi1FHwR50hD2N06B9yfE6ag1uI4/3CoIkcjo0hEOBe6FOFRhghbFVHJczSGXhuxSkUnIUos7RN45k9YdxZw6UaKHKRe38K8prtMwyDq0kUuYUtm0RjW+B/X70dhcFUwRmYMWguhCWMtJPwBHCTRkN4QrUFyQwul6B5Xh4f523BBV2BshcEFXUH6FfhC37ecpmTVrAyPMMK+cYqhiERaFrBFst1czzNC2bOyrb4drldkSRdlJDj8T9JUglKgwuAWWHlC3dO8isyB8fEP68iFFNmtYLX3Nzs/YlHIxJhPbN2+I3IBuivVONqE1M5Aq2F+plgz5tnPZzdGbZavlMPw9ePW4j56+fB1mN8IpQ31gxk/W9qUxe9JGdOkRE/GNAl1SMacKCUSWkpiiWdJ0VXqnKfB7iSujNqogzYsmKbmOkPmaEbPTL2IrZIbxCabHdDfPFDMYpAmnQjDW1NpSSjXfspTntCcsJ0aOVQHlgpj8Bbf3TmDHLjJ9p2KH8K4qQU+85aHU8H2WWYcWRHhl1bTgyAFyFqA6XrTl7h+Nedj0Jao6LlNFHaixAuKLrGVFB5AGxQOhqVHVwo7xaxD25PQNezeBGhFb1X2nLM35C0MS1b3MuoquCXXW2dt2s2o6jebvjTqaUzHU5LnWBatRrVeCeKqSz19Fz+8L8wqjChRW9rDVtqWE96TZAHOLrJGSS+oVPqMaDIjplCfppl37IDQbDjZEeo7q4m35rT5v47+Pa36wO9zbVteoHqZKQNlR+AEjk9WTguEEbml6TgVrMh4fzXqp65aV5u+WjkcoW5DbYh6yccYR47uXuHy7O1Eveu8g1y7K5+f4N6t3eVBHu6lfBknN/eEjdB3d/SjdLtGG6u78yjEUS/i6CGIm/bORtusvnJIeqXYPdJyb0uyU3rHdRnc/3Dg1cXqSBigiZY0NTUxXisN2cAcGMR/s1NGUd/NgSnhdA5K34m/AO9DLNsfndeGR7wEREql7C0+B1Cj+t5h7IGzjf0SwJdEJvdE+hPMUwb9Q1D9geTtT8wv4o7usFyyeIZR+dkcu20Sfpx/9w+6PbiPC5snjY1PmhLbdv9V58LXGAP7u4k3OPj5Tfj+8a93+qsuqkmYzgT6tYrFrcNT32C4ayzcBt4/Vb3G1OgNiTtnREfFTvv4IjOh33Bg9Fi/Z2DgKrrYQJhfNzgknbhpz1zyuWjC15GoOeLUrSlokmJQnUhN5yTRuJ2gruUj3XfCivI+nEF6ya8LnRcaVYZsxjrvpiYNdvEvB9+uzOPrvHyOew4VUEyKKsA1/1JQlrZyX/h3Qh+Eya/6HjS+1OY+XKxbpCvBDwSqzdeWhTvIcoZg6prHZAn9su23Yddi4zNKFpJkqsbY0OMnhl+arT79D98O2NmRGwAA";            

            byte[] bytes = Convert.FromBase64String(modelBase64);
            byte[] uncompressed = Decompress(bytes);

            string edmx = Encoding.UTF8.GetString(uncompressed);
            File.WriteAllText(@"c:\temp\edmx.xml", edmx);
        }

        static byte[] Decompress(byte[] gzip)
        {
            using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
            {
                const int size = 4096;
                byte[] buffer = new byte[size];

                using (MemoryStream memory = new MemoryStream())
                {
                    int count = 0;
                    do
                    {
                        count = stream.Read(buffer, 0, size);
                        if (count > 0)
                        {
                            memory.Write(buffer, 0, count);
                        }
                    }

                    while (count > 0);
                    return memory.ToArray();
                }
            }
        }
    }
}

The resulting EDMX xml looks like this:

EDMX xml

System.IdentityModel – manually parsing the SAML token

I’m working with a set of applications that have single sign-on implemented. They use Microsoft’s System.IdentityModel (.NET 4.5) and Thinktecture’s IdentityServer. In said system the normal flow of execution for the sign-on is:

  • The user tries to access an area of the website that requires authentication;
  • User is redirected to the Security Token Service website (in a different domain). The STS asks for his username and password;
  • User enters his username and password, if they are correct, the STS then creates a security token and posts it back to the original site. The token is intercepted by the FederatedAuthentication module, validated, and the user is signed-in, with his claims and identity available to be used by the application.

I received a requirement to implement this sign-on feature via an Ajax call, so without redirects to the external STS, and without a direct HTTP post from the STS to the application. The application would instead Ajax call to its own domain, and a server proxy would call the STS in the background, receiving the token back, validating it and creating the claims and identity. Basically doing what the FederatedAuthentication does, but in a more manual fashion.

So, to do that, I configured an HTTP Api on the STS, and wrote the necessary client code in the application, using RestSharp.

On the STS side, after the username and password are received and validated, I call ProcessSignInRequest from FederatedPassiveSecurityTokenServiceOperations to create a SignInResponseMessage, from which we get the security token serialized to XML:

SignInResponseMessage signInResponse = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(
                    signInRequestMessage,
                    principal as ClaimsPrincipal,
                    TokenServiceConfiguration.Current.CreateSecurityTokenService());

string xml = signInResponse.Result;

The XML of the security token is encoded and sent to the consumer application. The beast looks like this:

<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
	<trust:RequestSecurityTokenResponse>
		<trust:Lifetime>
			<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-01-19T17:15:47.999Z</wsu:Created>
			<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-01-20T03:15:47.999Z</wsu:Expires>
		</trust:Lifetime>
		<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
			<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
				<wsa:Address>http://mycompany.co.uk/</wsa:Address>
			</wsa:EndpointReference>
		</wsp:AppliesTo>
		<trust:RequestedSecurityToken>
			<Assertion ID="_b8316572-65cc-4f7a-96b9-98b263587f00" IssueInstant="2013-01-19T17:15:47.999Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
				<Issuer>https://my-sts.co.uk/</Issuer>
				<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
					<SignedInfo>
						<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
						<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
						<Reference URI="#_b8316572-65cc-4f7a-96b9-98b263587f00">
							<Transforms>
								<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
								<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
							</Transforms>
							<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
							<DigestValue>kP960TIbMajrVtU5YvE=</DigestValue>
						</Reference>
					</SignedInfo>
					<SignatureValue>pY4KbcpG1vI7+yTEpcdRuVwLbPWRLCmWt8eAyhX</SignatureValue>
					<KeyInfo>
						<X509Data>
							<X509Certificate>MIIFBHOgAwIBAgItwD3ICXpqIw==</X509Certificate>
						</X509Data>
					</KeyInfo>
				</Signature>
				<Subject>
					<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer" />
				</Subject>
				<Conditions NotBefore="2013-01-19T17:15:47.999Z" NotOnOrAfter="2013-01-20T03:15:47.999Z">
					<AudienceRestriction>
						<Audience>http://mycompany.co.uk/</Audience>
					</AudienceRestriction>
				</Conditions>
				<AttributeStatement>
					<Attribute Name="http://schemas.mycompany.com/ws/2012/10/claims/userid">
						<AttributeValue a:type="tn:integer32" xmlns:tn="http://www.w3.org/2001/XMLSchema" xmlns:a="http://www.w3.org/2001/XMLSchema-instance">123</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
						<AttributeValue>testuser</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
						<AttributeValue>testuser@email.com</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.mycompany.com/ws/2012/10/claims/avatarurl">
						<AttributeValue>https://mydomain.blob.core.windows.net/avatars/default/avatar.jpg</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.mycompany.com/ws/2012/10/claims/emailoptin">
						<AttributeValue a:type="tn:boolean" xmlns:tn="http://www.w3.org/2001/XMLSchema" xmlns:a="http://www.w3.org/2001/XMLSchema-instance">True</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/gender">
						<AttributeValue>Male</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth">
						<AttributeValue a:type="tn:date" xmlns:tn="http://www.w3.org/2001/XMLSchema" xmlns:a="http://www.w3.org/2001/XMLSchema-instance">12/21/1973 00:00:00</AttributeValue>
					</Attribute>
					<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode">
						<AttributeValue>SE1 3FL</AttributeValue>
					</Attribute>
				</AttributeStatement>
				<AuthnStatement AuthnInstant="2013-01-19T17:15:47.906Z">
					<AuthnContext>
						<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>
					</AuthnContext>
				</AuthnStatement>
			</Assertion>
		</trust:RequestedSecurityToken>
		<trust:RequestedAttachedReference>
			<SecurityTokenReference d4p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:d4p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
				<KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_b8316572-65cc-4f7a-96b9-98b263587f00</KeyIdentifier>
			</SecurityTokenReference>
		</trust:RequestedAttachedReference>
		<trust:RequestedUnattachedReference>
			<SecurityTokenReference d4p1:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:d4p1="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
				<KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_b8316572-65cc-4f7a-96b9-98b263587f00</KeyIdentifier>
			</SecurityTokenReference>
		</trust:RequestedUnattachedReference>
		<trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
		<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
		<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
	</trust:RequestSecurityTokenResponse>
</trust:RequestSecurityTokenResponseCollection>

In the original application that wants the user authenticated, I receive that XML and convert it into a SecurityToken object. I use the framework’s security token handlers for that. We can access the security token handlers by doing this:

SecurityTokenHandlerCollection handlers = 
FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;

Inside the collection above we have 8 handlers by default, for different types of authentication. They are:

  • [0]: {System.IdentityModel.Tokens.KerberosSecurityTokenHandler}
  • [1]: {System.IdentityModel.Tokens.RsaSecurityTokenHandler}
  • [2]: {System.IdentityModel.Tokens.SamlSecurityTokenHandler}
  • [3]: {System.IdentityModel.Tokens.Saml2SecurityTokenHandler}
  • [4]: {System.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler}
  • [5]: {System.IdentityModel.Tokens.X509SecurityTokenHandler}
  • [6]: {System.IdentityModel.Tokens.EncryptedSecurityTokenHandler}
  • [7]: {System.IdentityModel.Tokens.SessionSecurityTokenHandler}

The SecurityTokenHandlerCollection has a method ReadToken that accepts an XML. This method tries to read the token using all handlers in the collection. In my case the token is Saml2, so the handler responsible to read the token will be the Saml2SecurityTokenHandler.

I struggled initially because the ReadToken method was not working, it was always returning null. That’s because I was passing the original XML to it, starting with the node <trust:RequestSecurityTokenResponseCollection>. However it expects only the token fragment inside the envelope, which is the node <Assertion>.

My method to read the token is:

public SecurityToken ReadSecurityToken(XmlDocument signInResponseXml)
        {
            // for the security token to be read by the handler, the root of the XML must be this line:
            // <Assertion ID="..." IssueInstant="..." Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">

            string samlTokenXml = signInResponseXml
                .DocumentElement  // <trust:RequestSecurityTokenResponseCollection>
                .ChildNodes[0] // <trust:RequestSecurityTokenResponse>
                .ChildNodes[2] // <trust:RequestedSecurityToken>
                .InnerXml; // <Assertion>

            var xmlTextReader = new XmlTextReader(new StringReader(samlTokenXml));

            SecurityTokenHandlerCollection handlers = 
FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;

            // read the token
            SecurityToken securityToken = handlers.ReadToken(xmlTextReader);

            return securityToken;
        }

With the SecurityToken I create the ClaimsPrincipal instance:

var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;

// validate the token and create the identity collection
var claimsIdentityCollection = handlers.ValidateToken(securityToken);

// create ClaimsPrincipal
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentityCollection);            

And to complete the process I just need to assign the ClaimsPrincipal to the current thread and write the federated authentication cookie in the HTTP response:

// assign to the current thread
System.Threading.Thread.CurrentPrincipal = claimsPrincipal;

// write auth cookie to response
var sessionToken = new SessionSecurityToken(claimsPrincipal, TimeSpan.FromHours(12))
{
    IsPersistent = true
};
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);

There are other details in the solution that have been omitted, but in the end it worked very well, and allowed us to have the sign-on feature via Ajax.