Sunday, 30 March 2014

Basics: Benefits of Writing Unit Tests

Quite often people ask the reasons of writing unit tests for their code. There are several benefits of writing unit tests that add value to the code as well as the developers writing the tests. I am listing a set of points here that came to my mind while thinking about the benefits of Unit testing.

Benefits to code:
  • The code will have very few bugs as most of them are identified and resolved while running tests
  • Silly mistakes are inevitable while writing code. Identifying them while running the application is difficult at times. Unit tests catch them instantly
  • Code doesn’t need documentation. Names of the behaviours or methods defined in unit tests shout the purpose of their part
  • Testable code is easily extensible too. Adding new features to the code becomes easy
  • If Unit tests are written right from beginning of development, the underlying code automatically follows a set of quality measures that are otherwise very difficult to achieve
  • After applying some modifications, the code can be shipped within very less amount of time, as most of the regression testing is also done by the unit tests


Benefits to Programmers:
  • Unit testing teaches good programing practices to developers
  • Unit tests force programmers to use some of the features of the language and framework that would otherwise remain just as theories in programmers’ minds
  • As we write more code, our thinking about code starts maturing. With unit tests, we are bound to write a lot of additional code than the usual production code. So, it improves the programmer’s ability to think logically
  • Programmers gain the experience of writing clean, loosely coupled code and learn the ways to avoid anti-patterns
  • It becomes very easy for any new member to understand and start working on the code


These are just my opinions. The list is definitely not limited to the above set of points. Feel free to put a comment on anything that I didn’t mention in the above list.

Happy coding!

Sunday, 9 March 2014

A Closer Look at the Identity Client Implementation in SPA Template

Sometime back, we took a look at the identity system in ASP.NET and its support for both local and remote accounts. In this post, we will take a closer look at the way it is used in the Single Page Application template that comes with Visual Studio 2013.

The SPA application is a JavaScript client that uses an authenticated Web API. The Web API exposes a number of API methods to manage users. The JavaScript code uses jQuery for AJAX and Knockout for data binding has a number of methods that accomplish the task of managing the user. Let’s take a look at how the local users are authenticated.

Identity Client Implementation for Local Users:
If you check the Web API’s authentication configuration class, it exposes an endpoint at /Token for serving authorization token. Login credentials of the user have to be posted to this URL to get the user logged in. In response, the endpoint sends some data of which access token is a component. The access token has to be saved and used for subsequent requests to indicate the session of the logged in user.

Following code in the app.datamodel.js file sends a post request to the ‘/Token’ endpoint to login the user:


self.login = function (data) {
    return $.ajax(loginUrl, {
        type: "POST",
        data: data
    });
};

Following is the snippet from login.viewmodel.js that calls the above method:
dataModel.login({
    grant_type: "password",
    username: self.userName(),
    password: self.password()
}).done(function (data) {
    self.loggingIn(false);

    if (data.userName && data.access_token) {
        app.navigateToLoggedIn(data.userName, data.access_token, self.rememberMe());
    } else {
        self.errors.push("An unknown error occurred.");
    }
});


There are a couple of things to be noticed in the above code:

  • The property grant_type has to be set in the data passed to the login method
  • The navigateToLoggedIn method stores the access token in browser’s local storage to make it available for later use

To sign up for a new user, we just need to post the user’s data to the endpoint at ”/api/Account/Register”. Once the user is successfully registered, it sends a login request to the token endpoint discussed above to login the user immediately. Code for this can be found in the register method of register.viewmodel.js file. Following is the snippet that deals with registering and logging in:


dataModel.register({
    userName: self.userName(),
    password: self.password(),
    confirmPassword: self.confirmPassword()
}).done(function (data) {
    dataModel.login({
        grant_type: "password",
        username: self.userName(),
        password: self.password()
    })
    ......


Identity Client Implementation for External Login Users:
Identity implementation for external accounts is a bit tricky; because it involves moving the scope to a public web site and a number of API calls. When the application loads, it gets the list of external login providers by sending an HTTP GET request to “/api/Account/ExternalLogins”. Following method in app.datamodel.js does this:


self.getExternalLogins = function (returnUrl, generateState) {
    return $.ajax(externalLoginsUrl(returnUrl, generateState), {
        cache: false,
        headers: getSecurityHeaders()
    });
};

The parameter returnUrl used in the above method is where the user would be redirected after logging in from the external site.

Based on the providers obtained from the server, the provider specific login buttons are shown on the page. When a user chooses to use an external login provider, the system redirects him to the login page of the chosen provider. Before redirecting, the script saves the state and the URL redirected in session storage and local storage (both are used to make it work on most of the browsers). This information will be used once the user comes back to the site after logging in. Following snippet in login.viewmodel.js does this:


self.login = function () {
    sessionStorage["state"] = data.state;
    sessionStorage["loginUrl"] = data.url;
    // IE doesn't reliably persist sessionStorage when navigating to another URL. Move sessionStorage temporarily
    // to localStorage to work around this problem.
    app.archiveSessionStorageToLocalStorage();
    window.location = data.url;
};


Once the user is successfully authenticated by the external provider, the external provider redirects the user to the return URL with an authorization token in the query string. This token is unique for every user and the provider. This token is used to check if the user has already been registered to the site. If not, he would be asked to do so. Take a look at the following snippet from the initialize method in app.viewmodel.js:
......       
 } else if (typeof (fragment.access_token) !== "undefined") {
    cleanUpLocation();
    dataModel.getUserInfo(fragment.access_token)
    .done(function (data) {
    if (typeof (data.userName) !== "undefined" && typeof (data.hasRegistered) !== "undefined"
            && typeof (data.loginProvider) !== "undefined") {
        if (data.hasRegistered) {
            self.navigateToLoggedIn(data.userName, fragment.access_token, false);
        }
        else if (typeof (sessionStorage["loginUrl"]) !== "undefined") {
            loginUrl = sessionStorage["loginUrl"];
            sessionStorage.removeItem("loginUrl");
            self.navigateToRegisterExternal(data.userName, data.loginProvider, fragment.access_token,                              loginUrl, fragment.state);
        }
        else {
            self.navigateToLogin();
        }
    } else {
        self.navigateToLogin();
    }
})
......


It does the following:

  • Clears the access token from the URL
  • Queries the endpoint ‘/api/UserInfo’ with the access token for information about the user
  • If the user is found in the database, it navigates to the authorized content
  • Otherwise, navigates to the external user registration screen, where it asks for a local name

The external register page accepts a name of user’s choice and posts it to ‘/api/RegisterExternal’. After saving the user data, the system redirects the user to login page with value of state set in the session and local storages and also sends the authorization token with the URL. The login page uses this authorization token to identify the user.


dataModel.registerExternal(self.externalAccessToken, {
        userName: self.userName()
    }).done(function (data) {
        sessionStorage["state"] = self.state;
        // IE doesn't reliably persist sessionStorage when navigating to another URL. Move sessionStorage
        // temporarily to localStorage to work around this problem.
        app.archiveSessionStorageToLocalStorage();
        window.location = self.loginUrl;
    })


For logout, an HTTP POST request is sent to ‘/api/Logout’. It revokes the claims identity that was associated with the user. The client code removes entry of the access token stored in the local storage.

Happy coding!