Formatters And Content Negotiation In ASP.NET Web API 2


Introduction

As the title suggests, this article will focus on the practical aspects of the formatters and the content negotiation in ASP.NET Web API. This article will explain what content negotiation is and why it is necessary, and how to achieve and get it working in ASP.NET Web API. The article will focus more on the implementation part of the content negotiation in Web API. The first part of the article will focus on the formatters, where it is described, how to support XML or JSON formats in Web API and how to format the result of the API. We’ll take a sample Web API project, that caters simple CRUD operations on the database, using the Entity Framework. We’ll not go into the details of underlying project architecture and the standard way of architecture of the same, but will focus on the content negotiation part in Web API projects. For creating a standard enterprise level Application with Web API, you can follow this series. You can find all the downloads related to this article at the end of the post.

Continue reading “Formatters And Content Negotiation In ASP.NET Web API 2”

CRUD operations using RESTful ASP.Net WebAPI and MongoDB


MongoDB-Logo-5c3a7405a85675366beb3a5ec4c032348c390b3f142f5e6dddf1d78e2df5cb5c

macbook-624707_640

Introduction

In my previous article, we did CRUD operations using MongoDB shell commands. As promised, here I am with this article sharing how to create RESTful Web API for CRUD operations in MongoDB using .NET drivers.

As you already know, MongoDB is the future of modern web applications and it is very important for .NET developers to get their hands on MongoDB drivers, so this article is my little effort in this direction. I hope you would like it and appreciate my work.

In this article, we are to going to create Web APIs for manipulating and performing CRUD operations on student resource of our project. Continue reading “CRUD operations using RESTful ASP.Net WebAPI and MongoDB”

RESTful Day #9: OData in ASP.NET Web APIs


Download Source Code

Introduction

This is the last article of the RESTful series in which I’ll explain how you can leverage OData capabilities in Asp.net WebAPI. I’ll explain what OData is and we’ll create OData enabled RESTful services. I’ll try to keep the article very concise with less theory and more practical implementations.

Continue reading “RESTful Day #9: OData in ASP.NET Web APIs”

RESTful Day #8: Unit Testing and Integration Testing in WebAPI using NUnit and Moq framework (Part2)


Download Source Code

Introduction

In my last article I explained how to write unit tests for business service layer. In this article we’ll learn on how to write unit tests for WebAPI controllers i.e. REST’s actual endpoints. I’ll use NUnit and Moq framework to write test cases for controller methods. I have already explained about installing NUnit and configuring unit tests. My last article also covered explaining about NUnit attributes used in writing unit tests. Please go through my last article of the series before following this article.

Continue reading “RESTful Day #8: Unit Testing and Integration Testing in WebAPI using NUnit and Moq framework (Part2)”

RESTful Day #7: Unit Testing and Integration Testing in WebAPI using NUnit and Moq framework (Part 1)


Source Code at GitHub

Introduction

We have been learning a lot in WebAPI. We covered almost all the techniques required to build a robust and a full stack REST service using ASP.NET WebAPI, from creating a service to making it a secure and ready-to-use boilerplate with enterprise level applications. In this article, we’ll learn on how to focus on test driven development and write unit tests for our service endpoints and business logic. I’ll use NUnit and Moq framework to write test cases for business logic layer and controller methods. I’ll cover less theory and focus more on practical implementations on how to use these frameworks to write unit tests. I have segregated the article into two parts. The first part focusses on testing business logic and class libraries created as BusinessServices in our code base. The second part will focus on testing a Web API. The purpose of segregation is simple; the scope of this article is very large and may turn up into a very large post which would be not easy to read in one go.

Roadmap

The following is the roadmap I have setup to learn WebAPI step by step:

I’ll purposely use Visual Studio 2010 and .NET Framework 4.0 because there are few implementations that are very hard to find in .NET Framework 4.0, but I’ll make it easy by showing how to do it.

Unit Tests

“Unit tests allow you to make big changes to code quickly. You know it works now because you’ve run the tests, when you make the changes you need to make, you need to get the tests working again. This saves hours.” I got this from a post at stack overflow, and I completely agree to this statement.
A good unit test helps a developer to understand his code and (most importantly) the business logic. Unit tests help to understand all the aspects of business logic, right from the desired input and output to the conditions where the code can fail. A code having well written unit tests have less chances to fail provided the unit tests cover all the test cases required to execute.

NUnit

There are various frameworks available for Unit tests. NUnit is the one that I prefer. NUnit gels well with .NET and provides flexibility to write unit tests without hassle. It has meaningful and self-explanatory properties and class names that help developers write the tests in an easy way. NUnit provides an easy to use interactive GUI where you can run the tests and get the details. It shows the number of tests passed or failed in a beautiful fashion and also gives the stack trace in if any test fails, thereby enabling you to perform the first level of debugging at the GUI itself. I suggest downloading and installing NUnit on your machine for running the tests. We’ll use NUnit GUI after we write all the tests. I normally use inbuilt GUI of NUnit provided by ReSharper integrated in my Visual Studio. However, I have suggested you use NUnit GUI to run the tests since ReSharper is a paid library and only few developers may have it integrated. Since we are using Visual Studio 2010, we need to use the older version of NUnit i.e. 2.6.4. You can download and run the .msi and install on your machine following this URL.
Once you finish installation, you’ll see NUnit installed in your installed items on your machine as shown in below image:

Moq Framework

Moq is a simple and straightforward library to mock the objects in C#. We can mock data, repositories, classes, and instances with the help of mock library. So when we write unit tests, we do not execute them on the actual class instances, but instead perform in-memory unit testing by making a proxy of class objects. Like NUnit, Moq library classes are also easy to use and understand. Almost all of its methods, classes and interface names are self-explanatory.
The following is the list taken from Wikipedia on why to use mock objects
  • The object supplies non-deterministic results (e.g., the current time or the current temperature);
  • Has states that are not easy to create or reproduce (e.g., a network error);
  • Is slow (e.g., a complete database, which would have to be initialized before the test);
  • Does not yet exist or may change behavior;
  • Would have to include information and methods exclusively for testing purposes (and not for its actual task).
So whatever test we write, we actually execute that on test data and proxy objects i.e. not the instances of real classes. We’ll use Moq to mock data and repositories so that we do not hit the database again and again for executing unit tests. You can read more about Moq in this article.

Setup Solution

I’ll use this article to explain how to write unit tests for business logic i.e. covering our business logic layer and for WebAPI controllers. The scope of Unit tests should not be only limited to business logic or endpoints, but should be spread over all publically exposed logics like filters and handlers as well. Well written unit tests should cover almost all the code. One can track the code coverage through some of the tools available online. We’ll not test filters and common classes, but will focus on controllers and business logic layer and get an idea of how to proceed with unit tests. I’ll use the same source code that we used until Day# 6 of the series and will proceed with the latest code base that we got out of last article of the series. The code base is available for download with this post. When you take the code base from my last article and open it in Visual Studio, you’ll see the project structure something like as shown in below image:
IUnitOfWork is the new interface that I have added to facilitate interface driven development. It helps in mocking objects and improved structure and readability. Just open Visual Studio and add a new interface named IUnitOfWork under UnitOfWork folder in DataModel project and define the properties used in UnitOfWork class as shown below:
Now, go to the UnitOfWork class and inherit that class using this interface, so UnitOfWork class becomes something like this
#region Using Namespaces...

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Data.Entity.Validation;
using DataModel.GenericRepository;

#endregion

namespace DataModel.UnitOfWork
{
    /// <summary>
    /// Unit of Work class responsible for DB transactions
    /// </summary>
    public class UnitOfWork : IDisposable, IUnitOfWork
    {
        #region Private member variables...

        private readonly WebApiDbEntities _context = null;
        private GenericRepository _userRepository;
        private GenericRepository _productRepository;
        private GenericRepository _tokenRepository;
        #endregion

        public UnitOfWork()
        {
            _context = new WebApiDbEntities();
        }

        #region Public Repository Creation properties...

        /// <summary>
        /// Get/Set Property for product repository.
        /// </summary>
        public GenericRepository ProductRepository
        {
            get
            {
                if (this._productRepository == null)
                    this._productRepository = new GenericRepository(_context);
                return _productRepository;
            }
        }

        /// <summary>
        /// Get/Set Property for user repository.
        /// </summary>
        public GenericRepository UserRepository
        {
            get
            {
                if (this._userRepository == null)
                    this._userRepository = new GenericRepository(_context);
                return _userRepository;
            }
        }

        /// <summary>
        /// Get/Set Property for token repository.
        /// </summary>
        public GenericRepository TokenRepository
        {
            get
            {
                if (this._tokenRepository == null)
                    this._tokenRepository = new GenericRepository(_context);
                return _tokenRepository;
            }
        }
        #endregion

        #region Public member methods...
        /// <summary>
        /// Save method.
        /// </summary>
        public void Save()
        {
            try
            {
                _context.SaveChanges();
            }
            catch (DbEntityValidationException e)
            {

                var outputLines = new List();
                foreach (var eve in e.EntityValidationErrors)
                {
                    outputLines.Add(string.Format("{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State));
                    foreach (var ve in eve.ValidationErrors)
                    {
                        outputLines.Add(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));
                    }
                }
                System.IO.File.AppendAllLines(@"C:\errors.txt", outputLines);

                throw e;
            }

        }

        #endregion

        #region Implementing IDiosposable...

        #region private dispose variable declaration...
        private bool disposed = false; 
        #endregion

        /// <summary>
        /// Protected Virtual Dispose method
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    Debug.WriteLine("UnitOfWork is being disposed");
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        /// <summary>
        /// Dispose method
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        } 
        #endregion
    }
}
So, now all the interface members defined in IUnitOfWork are implemented in UnitOfWork class:
public interface IUnitOfWork
    {
        #region Properties
        GenericRepository ProductRepository { get; }
        GenericRepository UserRepository { get; }
        GenericRepository TokenRepository { get; } 
        #endregion
        
        #region Public methods
        /// <summary>
        /// Save method.
        /// </summary>
        void Save(); 
        #endregion
    }
Doing this will not change the functionality of our existing code, but we also need to update the business services with this Interface. We’ll pass this IUnitOfWork interface instance inside services constructors instead of directly using UnitOfWork class.
private readonly IUnitOfWork _unitOfWork;

public ProductServices(IUnitOfWork unitOfWork)
{
    _unitOfWork = unitOfWork;
}
So our User service, Token service and product service constructors becomes as shown below,

Product Service

User Service

Token Service

Testing Business Services

We’ll start writing unit tests for BusinessServices project.

Step 1: Test Project

Add a simple class library in the existing Visual Studio and name it BusinessServices.Tests. Open Tools->Library Packet Manager->Packet manager Console to open the package manager console window. We need to install come packages before we proceed.

Step 2: Install NUnit package

In package manager console, select BusinessServices.Tests as default project and write command “Install-Package NUnit –Version 2.6.4“. If you do not mention the version, the PMC (Package manage Console) will try to download the latest version of NUnit nugget package but we specifically need 2.6.4, so we need to mention the version. Same applies to when you try to install any such package from PMC
After successfully installed, you can see the DLL reference in project references i.e. nunit.framework,

Step 3: Install Moq framework

Install the framework on the same project in the similar way as explained in Step 2. Write command “Install-Package Moq” .Here we use latest version of Moq
Therefore adding the DLL

Step 4: Install Entity Framework

Install-Package EntityFramework –Version 5.0.0

Step 5: Install AutoMapper

Install-Package AutoMapper –Version 3.3.1
Our package.config i.e. automatically added in the project looks like,
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AutoMapper" version="3.3.1" targetFramework="net40" />
  <package id="EntityFramework" version="5.0.0" targetFramework="net40" />
  <package id="Moq" version="4.2.1510.2205" targetFramework="net40" />
  <package id="NUnit" version="2.6.4" targetFramework="net40" />
</packages>

Step 6: References

Add references of DataModel, BusinessServices, BusinessEntities project to this project.

TestHelper

We will require few helper files that would be needed in BusinessServices.Tests project and in our WebAPI.Tests project that we’ll create later. To place all the helper files, I have created one more class library project named TestHelper. Just right click the solution and add new project named TestHelper and add a class namedDataInitializer.cs into it. This class contains three simple methods to fetch i.e. User’s, Product’s and Token’s dummy data. You can use the following code as the class implementation:
using System;
using System.Collections.Generic;
using DataModel;

namespace TestsHelper
{
/// <summary>
/// Data initializer for unit tests
/// </summary>
public class DataInitializer
{
/// <summary>
/// Dummy products
/// </summary>
/// <returns></returns>
public static List GetAllProducts()
{
var products = new List
{
new Product() {ProductName = "Laptop"},
new Product() {ProductName = "Mobile"},
new Product() {ProductName = "HardDrive"},
new Product() {ProductName = "IPhone"},
new Product() {ProductName = "IPad"}
};
return products;
}

/// <summary>
/// Dummy tokens
/// </summary>
/// <returns></returns>
public static List GetAllTokens()
{
var tokens = new List
{
new Token()
{
AuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77761",
ExpiresOn = DateTime.Now.AddHours(2),
IssuedOn = DateTime.Now,
UserId = 1
},
new Token()
{
AuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77762",
ExpiresOn = DateTime.Now.AddHours(1),
IssuedOn = DateTime.Now,
UserId = 2
}
};

return tokens;
}

/// <summary>
/// Dummy users
/// </summary>
/// <returns></returns>
public static List GetAllUsers()
{
var users = new List
{
new User()
{
UserName = "akhil",
Password = "akhil",
Name = "Akhil Mittal",
},
new User()
{
UserName = "arsh",
Password = "arsh",
Name = "Arsh Mittal",
},
new User()
{
UserName = "divit",
Password = "divit",
Name = "Divit Agarwal",
}
};

return users;
}

}
}
In the above class GetAllUsers() fetches dummy data for users, GetAllProducts() fetches dummy data for Products and GetAllTokens() method fetches dummy data for Tokens. So now, our solution has two new projects as shown below:
Add DataModel project reference to TestHelper project and TestHelper project reference to BusinessServices.Tests project.

ProductService Tests

We’ll start with setting up the project and setting up the pre-requisites for tests and gradually move on to actual tests.

Tests Setup

We’ll proceed with creating ProductServices tests. Add a new class named ProductServicesTests.cs in BusinessServices.Tests project.
Declare variables
Define the private variables that we’ll use in the class to write tests,
#region Variables
private IProductServices _productService;
private IUnitOfWork _unitOfWork;
private List _products;
private GenericRepository _productRepository;
private WebApiDbEntities _dbEntities;
#endregion
Variable declarations are self-explanatory where _productService will hold mock for ProductServices,_unitOfWork for UnitOfWork class, _products will hold dummy products from DataInitializer class of TestHelper project, _productRepository and _dbEntities holds mock for Product Repository and WebAPIDbEntities from DataModel project respectively.
Write Test Fixture Setup
Test fixture setup is written as a onetime setup for all the tests. It is like a constructor in terms of classes. When we start executing setup, this is the first method to be executed. In this method we’ll populate the dummy products data and decorate this method with the [TestFixtureSetUp] attribute at the top that tells compiler that the particular method is a TestFixtureSetup. [TestFixtureSetUp] attribute is the part of NUnit framework, so include it in the class as a namespace i.e. using NUnit.Framework;. Following is the code forTestFixtureSetup.
#region Test fixture setup

 /// <summary>
 /// Initial setup for tests
 /// </summary>
 [TestFixtureSetUp]
 public void Setup()
 {
     _products = SetUpProducts();
 }

 #endregion

private static List SetUpProducts()
 {
     var prodId = new int();
     var products = DataInitializer.GetAllProducts();
     foreach (Product prod in products)
         prod.ProductId = ++prodId;
     return products;

 }
SetUpproducts() method fetches products from DataInitializer class and not from database. It also and assigns a unique id to each product by iterating them. The result data is assigned to _products list to be used in setting up mock repository and in every individual test for comparison of actual vs resultant output.
Write Test Fixture Tear Down
Unlike TestFixtureSetup, tear down is used to de-allocate or dispose the objects. It also executes only one time when all the tests execution ends. In our case we’ll use this method to nullify _products instance. The attribute used for Test fixture tear down is [TestFixtureTearDown].
Following is the code for teardown.
#region TestFixture TearDown.

 /// <summary>
 /// TestFixture teardown
 /// </summary>
 [TestFixtureTearDown]
 public void DisposeAllObjects()
 {
     _products = null;
 }

 #endregion
Note that we have till now not written any unit test.
Write Test Setup
TestFixtureSetUp is a onetime run process whereas [SetUp] marked method is executed after each test. Each test should be independent and should be tested with a fresh set of input. Setup helps us to re-initialize data for each test. Therefore, all the required initialization for tests are written in this particular method marked with the [SetUp] attribute. I have written a few methods and initialized the private variables in this method. These lines of code execute after each test ends, so that individual tests do not depend on any other written tests and do not get hampered with other tests pass or fail status. The code for Setup:
#region Setup
/// <summary>
/// Re-initializes test.
/// </summary>
[SetUp]
public void ReInitializeTest()
{
    _dbEntities = new Mock().Object;
    _productRepository = SetUpProductRepository();
    var unitOfWork = new Mock();
    unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);
    _unitOfWork = unitOfWork.Object;
    _productService = new ProductServices(_unitOfWork);
}

#endregion
We make use of Mock framework in this method to mock the private variable instances. Like for _dbEntitieswe write _dbEntities = new Mock().Object;. This means that we are mockingWebDbEntities class and getting its proxy object. Mock class is the class from Moq framework, so include the respective namespace using Moq; in the class
Write Test Tear down
Like test, Setup runs after every test. Similarly, Test [TearDown] is invoked after every test execution is complete. You can use tear down to dispose and nullify the objects that are initialized while setup. The method for tear down should be decorated with the [TearDown] attribute. The following is the test tear down implementation.
/// <summary>
/// Tears down each test data
/// </summary>
[TearDown]
public void DisposeTest()
{
    _productService = null;
    _unitOfWork = null;
    _productRepository = null;
    if (_dbEntities != null)
        _dbEntities.Dispose();
}
Mocking Repository
I talked about mocking repository for the entities. I have created a method SetUpProductRepository() to mock Product Repository and assign it to _productrepository in ReInitializeTest() method.
private GenericRepository SetUpProductRepository()
{

// Initialise repository
var mockRepo = new Mock<GenericRepository>(MockBehavior.Default, _dbEntities);

// Setup mocking behavior
mockRepo.Setup(p => p.GetAll()).Returns(_products);

mockRepo.Setup(p => p.GetByID(It.IsAny()))
.Returns(new Func(
id => _products.Find(p => p.ProductId.Equals(id))));

mockRepo.Setup(p => p.Insert((It.IsAny())))
.Callback(new Action(newProduct =>
{
dynamic maxProductID = _products.Last().ProductId;
dynamic nextProductID = maxProductID + 1;
newProduct.ProductId = nextProductID;
_products.Add(newProduct);
}));

mockRepo.Setup(p => p.Update(It.IsAny()))
.Callback(new Action(prod =>
{
var oldProduct = _products.Find(a => a.ProductId == prod.ProductId);
oldProduct = prod;
}));

mockRepo.Setup(p => p.Delete(It.IsAny()))
.Callback(new Action(prod =>
{
var productToRemove =
_products.Find(a => a.ProductId == prod.ProductId);

if (productToRemove != null)
_products.Remove(productToRemove);
}));

// Return mock implementation object
return mockRepo.Object;
}
Here we mock all the required methods of Product Repository to get the desired data from _products object and not from actual database.
The single line of code
var mockRepo = new Mock<GenericRepository>(MockBehavior.Default, _dbEntities);
mocks the Generic Repository for Product and mockRepo.Setup() mocks the repository methods by passing relevant delegates to the method.
Initialize UnitOfWork and Service
I have written following lines of code in ReInitializeTest() method i.e. our setup method,
var unitOfWork = new Mock();
unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);
_unitOfWork = unitOfWork.Object;
_productService = new ProductServices(_unitOfWork);
Here you can see that I am trying to mock the UnitOfWork instance and forcing it to perform all its transactions and operations on _productRepository that we have mocked earlier. This means that all the transactions will be limited to the mocked repository and the actual database or the actual repository will not be touched. Same goes for service as well; we are initializing product Services with this mocked _unitOfWork. So when we use_productService in actual tests, it actually works on mocked UnitOfWork and test data only.
All set now and we are ready to write unit tests for ProductService. We’ll write test to perform all the CRUD operations that are part of ProductService.

1. GetAllProductsTest ()

Our ProductService in BusinessServices project contains a method named GetAllProducts (), following is the implementation,
public IEnumerable GetAllProducts()
{
var products = _unitOfWork.ProductRepository.GetAll().ToList();
if (products.Any())
{
Mapper.CreateMap();
var productsModel = Mapper.Map<List, List>(products);
return productsModel;
}
return null;
}
We see here, that this method fetches all the available products from the database, maps the database entity to our custom BusinessEntities.ProductEntity and returns the list of custom BusinessEntities.ProductEntity. It returns null if no products are found.
To start writing a test method, you need to decorate that test method with [Test] attribute of NUnit framework. This attribute specifies that particular method is a Unit Test method.
The following is the unit test method I have written for the above mentioned business service method:
[Test]
public void GetAllProductsTest()
{
var products = _productService.GetAllProducts();
var productList =
products.Select(
productEntity =>
new Product {ProductId = productEntity.ProductId, ProductName = productEntity.ProductName}).ToList();
var comparer = new ProductComparer();
CollectionAssert.AreEqual(
productList.OrderBy(product => product, comparer),
_products.OrderBy(product => product, comparer), comparer);
}
We used instance of _productService and called the GetAllProducts() method, that will ultimately execute on mocked UnitOfWork and Repository to fetch test data from _products list. The products returned from the method are of type BusinessEntities.ProductEntity and we need to compare the returned products with our existing _products list, such as the list of DataModel.Product (a mocked database entity) so we need to convert the returned BusinessEntities.ProductEntity list to DataModel.Product list. We do this with the following line of code:
var productList =
products.Select(
productEntity =>
new Product {ProductId = productEntity.ProductId, ProductName = productEntity.ProductName}).ToList();
Now we got two lists to compare, one _products list i.e. the actual products and another productList i.e. the products returned from the service. I have written a helper class and compare method to convert the two Product list in TestHelper project. This method checks the list items and compares them for equality of values. You can add a class named ProductComparer to TestHelper project with the following implementations:
public class ProductComparer : IComparer, IComparer
{
public int Compare(object expected, object actual)
{
var lhs = expected as Product;
var rhs = actual as Product;
if (lhs == null || rhs == null) throw new InvalidOperationException();
return Compare(lhs, rhs);
}

public int Compare(Product expected, Product actual)
{
int temp;
return (temp = expected.ProductId.CompareTo(actual.ProductId)) != 0 ? temp : expected.ProductName.CompareTo(actual.ProductName);
}
}</product>
To assert the result we use CollectionAssert.AreEqual of NUnit where we pass both the lists and comparer.
CollectionAssert.AreEqual(
productList.OrderBy(product => product, comparer),
_products.OrderBy(product => product, comparer), comparer);
Since I have the NUnit plugin in my Visual Studio provided by ReSharper, let me debug the test method to see the actual result of Assert. We’ll run all the tests with NUnit UI at the end of the article.
productList:
_products:
We got both the lists and we need to check the comparison of the lists, so I just pressed F5 and got the result on TestUI as:
This shows our test is passed, i.e. the expected and returned result is same.

2. GetAllProductsTestForNull ()

You can also write the test for null check for the same method where you nullify the _products list before you invoke the service method. We actually need to write tests that cover all the exit points of the invoked method.
The following test covers another exit point of the method that returns null in case of no products found.
/// <summary>
/// Service should return null
/// </summary>
[Test]
public void GetAllProductsTestForNull()
{
    _products.Clear();
    var products = _productService.GetAllProducts();
    Assert.Null(products);
    SetUpProducts();
}
In the above mentioned test, we first clear the _products list and invoke the service method. Now assert the result for null because our expected result and actual result should be null. I called the SetUpProducts()method again to populate the _products list, but you can do this in the test setup method as well i.e.ReInitializeTest().
Now let’s move to other tests.

3. GetProductByRightIdTest ()

Here we test the GetProductById() method of ProductService. The ideal behavior is that if I invoke the method with a valid id, the method should return the valid product. Now let’s suppose I know the product id for my product named “Mobile” and I invoke the test using that id, so ideally I should get a product with the product name mobile.
/// <summary>
 /// Service should return product if correct id is supplied
 /// </summary>
 [Test]
 public void GetProductByRightIdTest()
 {
     var mobileProduct = _productService.GetProductById(2);
     if (mobileProduct != null)
     {
         Mapper.CreateMap();
         var productModel = Mapper.Map(mobileProduct);
         AssertObjects.PropertyValuesAreEquals(productModel,
                                               _products.Find(a => a.ProductName.Contains("Mobile")));
     }
 }
The above code is self-explanatory except the line AssertObjects.PropertyValuesAreEquals.
_productService.GetProductById(2); line fetches the product with product id 2.
Mapper.CreateMap();
var productModel = Mapper.Map(mobileProduct);
The above code maps the returned custom ProductEntity to DataModel.Product
AssertObjects is one more class I have added inside the TestHelper class. The purpose of this class is to compare the properties of two objects. This is a common generic class applicable for all type of class objects having properties. Its method PropertyValuesAreEquals() checks for equality of the properties.

AssertObjects class

using System.Collections;
using System.Reflection;
using NUnit.Framework;

namespace TestsHelper
{
    public static class AssertObjects
    {
        public static void PropertyValuesAreEquals(object actual, object expected)
        {
            PropertyInfo[] properties = expected.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                object expectedValue = property.GetValue(expected, null);
                object actualValue = property.GetValue(actual, null);

                if (actualValue is IList)
                AssertListsAreEquals(property, (IList)actualValue, (IList)expectedValue);
                else if (!Equals(expectedValue, actualValue))
                if (property.DeclaringType != null)
                Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
            }
        }

        private static void AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList)
        {
        if (actualList.Count != expectedList.Count)
            Assert.Fail("Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", 
            property.PropertyType.Name,
            property.Name, expectedList.Count, actualList.Count);

            for (int i = 0; i < actualList.Count; i++)
            if (!Equals(actualList[i], expectedList[i]))
            Assert.Fail("Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", property.PropertyType.Name, property.Name, expectedList[i], actualList[i]);
        }
    }
}
Running the test,

4. GetProductByWrongIdTest ()

In this test we test the service method with wrong id and expect null in return.
/// <summary>
/// Service should return null
/// </summary>
[Test]
public void GetProductByWrongIdTest()
{
    var product = _productService.GetProductById(0);
    Assert.Null(product);
}

5. AddNewProductTest ()

In this unit test we test the CreateProduct() method of ProductService. Following is the unit test written for creating a new product.
/// <summary>
/// Add new product test
/// </summary>
[Test]
public void AddNewProductTest()
{
    var newProduct = new ProductEntity()
    {
    ProductName = "Android Phone"
    };

    var maxProductIDBeforeAdd = _products.Max(a => a.ProductId);
    newProduct.ProductId = maxProductIDBeforeAdd + 1;
    _productService.CreateProduct(newProduct);
    var addedproduct = new Product() {ProductName = newProduct.ProductName, ProductId = newProduct.ProductId};
    AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last());
    Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId));
}
In the above code I have created a dummy product with product name “Android Phone” and assigned the product id as the incremented id to the maximum value of productId of the product that lies in _products list. Ideally if my test is success, the added product should reflect in _products list as last product with maximum product id. To verify the result, I have used two asserts. The first one checks the properties of expected and actual product and second one verifies the product id.
var addedproduct = new Product() {ProductName = newProduct.ProductName, ProductId = newProduct.ProductId};
addedProduct is the custom product that is expected to be added in the _products list and_products.Last() gives us last product of the list. So,
AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last()); checks for all the properties of dummy as well as last added product and,
Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId)); checks if the last product added has the same product id as supplied while creating the product.
After full execution,
The test passes, that means the expected value that was product id 6 was equal to the product id of the last added product in _products list. And we can also see that, earlier we had only five products in _products list and now we have added a 6th one.

6. UpdateProductTest ()

This is the unit test to check if the product is updated or not. This test is for UpdateProduct() method ofProductService.
/// <summary>
/// Update product test
/// </summary>
[Test]
public void UpdateProductTest()
{
    var firstProduct = _products.First();
    firstProduct.ProductName = "Laptop updated";
    var updatedProduct = new ProductEntity()
    {ProductName = firstProduct.ProductName, ProductId = firstProduct.ProductId};
    _productService.UpdateProduct(firstProduct.ProductId, updatedProduct);
    Assert.That(firstProduct.ProductId, Is.EqualTo(1)); // hasn't changed
    Assert.That(firstProduct.ProductName, Is.EqualTo("Laptop updated")); // Product name changed

}
In this test I am trying to update first product from _products list. I have changed the product name to “Laptop Updated” and invoked the UpdateProduct () method of ProductService. I have made two asserts to check the updated product from _products list, one for productId and second for product name. We see that we get the updated product while we assert.

7. DeleteProductTest ()

The following is the test for the DeleteProduct () method in ProductService.
/// <summary>
/// Delete product test
/// </summary>
[Test]
public void DeleteProductTest()
{
    int maxID = _products.Max(a => a.ProductId); // Before removal
    var lastProduct = _products.Last();

    // Remove last Product
    _productService.DeleteProduct(lastProduct.ProductId);
    Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId)));   // Max id reduced by 1
}
I have written the test to verify the max id of product from the list of products. Get max id of the product, delete the last product and check the max id of the product from the list. The prior max id should be greater than the last product’s product id.
Max id before delete was 5 and after delete is 4 that means a product is deleted from _products list therefore statement : Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); passes as 5 is greater than 4.
We have covered all the methods of ProductService under unit tests. The following is the final class that covers all the tests for this service.
#region using namespaces.
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using BusinessEntities;
using DataModel;
using DataModel.GenericRepository;
using DataModel.UnitOfWork;
using Moq;
using NUnit.Framework;
using TestsHelper;

#endregion

namespace BusinessServices.Tests
{
    /// <summary>
    /// Product Service Test
    /// </summary>
    public class ProductServicesTest
    {
        #region Variables

        private IProductServices _productService;
        private IUnitOfWork _unitOfWork;
        private List _products;
        private GenericRepository _productRepository;
        private WebApiDbEntities _dbEntities;
        #endregion

        #region Test fixture setup

        /// <summary>
        /// Initial setup for tests
        /// </summary>
        [TestFixtureSetUp]
        public void Setup()
        {
            _products = SetUpProducts();
        }

        #endregion

        #region Setup

        /// <summary>
        /// Re-initializes test.
        /// </summary>
        [SetUp]
        public void ReInitializeTest()
        {
            _dbEntities = new Mock().Object;
            _productRepository = SetUpProductRepository();
            var unitOfWork = new Mock();
            unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);
            _unitOfWork = unitOfWork.Object;
            _productService = new ProductServices(_unitOfWork);
        }

        #endregion

        #region Private member methods

        /// <summary>
        /// Setup dummy repository
        /// </summary>
        /// <returns></returns>
        private GenericRepository SetUpProductRepository()
        {
            // Initialise repository
            var mockRepo = new Mock<GenericRepository>(MockBehavior.Default, _dbEntities);

            // Setup mocking behavior
            mockRepo.Setup(p => p.GetAll()).Returns(_products);

            mockRepo.Setup(p => p.GetByID(It.IsAny()))
            .Returns(new Func(
            id => _products.Find(p => p.ProductId.Equals(id))));

            mockRepo.Setup(p => p.Insert((It.IsAny())))
            .Callback(new Action(newProduct =>
            {
                dynamic maxProductID = _products.Last().ProductId;
                dynamic nextProductID = maxProductID + 1;
                newProduct.ProductId = nextProductID;
                _products.Add(newProduct);
            }));

            mockRepo.Setup(p => p.Update(It.IsAny()))
            .Callback(new Action(prod =>
            {
                var oldProduct = _products.Find(a => a.ProductId == prod.ProductId);
                oldProduct = prod;
            }));

            mockRepo.Setup(p => p.Delete(It.IsAny()))
            .Callback(new Action(prod =>
            {
                var productToRemove =
                _products.Find(a => a.ProductId == prod.ProductId);

                if (productToRemove != null)
                    _products.Remove(productToRemove);
            }));

            // Return mock implementation object
            return mockRepo.Object;
        }

        /// <summary>
        /// Setup dummy products data
        /// </summary>
        /// <returns></returns>
        private static List SetUpProducts()
        {
            var prodId = new int();
            var products = DataInitializer.GetAllProducts();
            foreach (Product prod in products)
                prod.ProductId = ++prodId;
            return products;

        }

        #endregion

        #region Unit Tests

        /// <summary>
        /// Service should return all the products
        /// </summary>
        [Test]
        public void GetAllProductsTest()
        {
            var products = _productService.GetAllProducts();
            if (products != null)
            {
                var productList =
                products.Select(
                productEntity =>
                new Product { ProductId = productEntity.ProductId, ProductName = productEntity.ProductName }).
                ToList();
                var comparer = new ProductComparer();
                CollectionAssert.AreEqual(
                productList.OrderBy(product => product, comparer),
                _products.OrderBy(product => product, comparer), comparer);
            }
        }

        /// <summary>
        /// Service should return null
        /// </summary>
        [Test]
        public void GetAllProductsTestForNull()
        {
            _products.Clear();
            var products = _productService.GetAllProducts();
            Assert.Null(products);
            SetUpProducts();
        }

        /// <summary>
        /// Service should return product if correct id is supplied
        /// </summary>
        [Test]
        public void GetProductByRightIdTest()
        {
            var mobileProduct = _productService.GetProductById(2);
            if (mobileProduct != null)
            {
                Mapper.CreateMap();
                var productModel = Mapper.Map(mobileProduct);
                AssertObjects.PropertyValuesAreEquals(productModel,
                _products.Find(a => a.ProductName.Contains("Mobile")));
            }
        }

        /// <summary>
        /// Service should return null
        /// </summary>
        [Test]
        public void GetProductByWrongIdTest()
        {
            var product = _productService.GetProductById(0);
            Assert.Null(product);
        }

        /// <summary>
        /// Add new product test
        /// </summary>
        [Test]
        public void AddNewProductTest()
        {
            var newProduct = new ProductEntity()
            {
                ProductName = "Android Phone"
            };

            var maxProductIDBeforeAdd = _products.Max(a => a.ProductId);
            newProduct.ProductId = maxProductIDBeforeAdd + 1;
            _productService.CreateProduct(newProduct);
            var addedproduct = new Product() { ProductName = newProduct.ProductName, ProductId = newProduct.ProductId };
            AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last());
            Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId));
        }

        /// <summary>
        /// Update product test
        /// </summary>
        [Test]
        public void UpdateProductTest()
        {
            var firstProduct = _products.First();
            firstProduct.ProductName = "Laptop updated";
            var updatedProduct = new ProductEntity() { ProductName = firstProduct.ProductName, ProductId = firstProduct.ProductId };
            _productService.UpdateProduct(firstProduct.ProductId, updatedProduct);
            Assert.That(firstProduct.ProductId, Is.EqualTo(1)); // hasn't changed
            Assert.That(firstProduct.ProductName, Is.EqualTo("Laptop updated")); // Product name changed
        }

        /// <summary>
        /// Delete product test
        /// </summary>
        [Test]
        public void DeleteProductTest()
        {
            int maxID = _products.Max(a => a.ProductId); // Before removal
            var lastProduct = _products.Last();

            // Remove last Product
            _productService.DeleteProduct(lastProduct.ProductId);
            Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); // Max id reduced by 1
        }

        #endregion


        #region Tear Down

        /// <summary>
        /// Tears down each test data
        /// </summary>
        [TearDown]
        public void DisposeTest()
        {
            _productService = null;
            _unitOfWork = null;
            _productRepository = null;
            if (_dbEntities != null)
                _dbEntities.Dispose();
        }

        #endregion

        #region TestFixture TearDown.

        /// <summary>
        /// TestFixture teardown
        /// </summary>
        [TestFixtureTearDown]
        public void DisposeAllObjects()
        {
            _products = null;
        }

        #endregion
    }
}

TokenService Tests

Now that we have completed all the tests for ProductService, I am sure you must have got an idea on how to write unit tests for methods. Note that primarily unit tests are only written to publically exposed methods because the private methods automatically get tested through those public methods in the class. I’ll not explain too much theory for TokenService tests and only navigate through code. I’ll explain the details wherever necessary.

Tests Setup

Add a new class named TokenServicesTests.cs in BusinessServices.Tests project.
Declare variables
Define the private variable that we’ll use in the class to write tests,
#region Variables
private ITokenServices _tokenServices;
private IUnitOfWork _unitOfWork;
private List _tokens;
private GenericRepository _tokenRepository;
private WebApiDbEntities _dbEntities;
private const string SampleAuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77761";
#endregion
Here _tokenService will hold mock for TokenServices_unitOfWork for UnitOfWork class, __tokens will hold dummy tokens from DataInitializer class of TestHelper project, _tokenRepository and_dbEntities holds mock for Token Repository and WebAPIDbEntities from DataModel project respectively
Write Test Fixture Setup
#region Test fixture setup

/// <summary>
/// Initial setup for tests
/// </summary>
[TestFixtureSetUp]
public void Setup()
{
    _tokens = SetUpTokens();
}

#endregion
SetUpTokens () method fetches tokens from DataInitializer class and not from database and assigns a unique id to each token by iterating on them.
/// <summary>
/// Setup dummy tokens data
/// </summary>
/// <returns></returns>
private static List SetUpTokens()
{
    var tokId = new int();
    var tokens = DataInitializer.GetAllTokens();
    foreach (Token tok in tokens)
        tok.TokenId = ++tokId;
    return tokens;
}
The result data is assigned to __tokens list to be used in setting up mock repository and in every individual test for comparison of actual vs resultant output.
Write Test Fixture Tear Down
#region TestFixture TearDown.

/// <summary>
/// TestFixture teardown
/// </summary>
[TestFixtureTearDown]
public void DisposeAllObjects()
{
    _tokens = null;
}

#endregion
Write Test Setup
#region Setup

    /// <summary>
    /// Re-initializes test.
    /// </summary>
    [SetUp]
    public void ReInitializeTest()
    {
        _dbEntities = new Mock().Object;
        _tokenRepository = SetUpTokenRepository();
        var unitOfWork = new Mock();
        unitOfWork.SetupGet(s => s.TokenRepository).Returns(_tokenRepository);
        _unitOfWork = unitOfWork.Object;
        _tokenServices = new TokenServices(_unitOfWork);
    }

#endregion
Write Test Tear down
#region Tear Down

/// <summary>
/// Tears down each test data
/// </summary>
[TearDown]
public void DisposeTest()
{
    _tokenServices = null;
    _unitOfWork = null;
    _tokenRepository = null;
    if (_dbEntities != null)
        _dbEntities.Dispose();
}

#endregion
Mocking Repository
private GenericRepository SetUpTokenRepository()
{
// Initialise repository
var mockRepo = new Mock<GenericRepository>(MockBehavior.Default, _dbEntities);

// Setup mocking behavior
mockRepo.Setup(p => p.GetAll()).Returns(_tokens);

mockRepo.Setup(p => p.GetByID(It.IsAny()))
.Returns(new Func(
id => _tokens.Find(p => p.TokenId.Equals(id))));

mockRepo.Setup(p => p.GetByID(It.IsAny()))
.Returns(new Func(
authToken => _tokens.Find(p => p.AuthToken.Equals(authToken))));

mockRepo.Setup(p => p.Insert((It.IsAny())))
.Callback(new Action(newToken =>
{
dynamic maxTokenID = _tokens.Last().TokenId;
dynamic nextTokenID = maxTokenID + 1;
newToken.TokenId = nextTokenID;
_tokens.Add(newToken);
}));

mockRepo.Setup(p => p.Update(It.IsAny()))
.Callback(new Action(token =>
{
var oldToken = _tokens.Find(a => a.TokenId == token.TokenId);
oldToken = token;
}));

mockRepo.Setup(p => p.Delete(It.IsAny()))
.Callback(new Action(prod =>
{
var tokenToRemove =
_tokens.Find(a => a.TokenId == prod.TokenId);

if (tokenToRemove != null)
_tokens.Remove(tokenToRemove);
}));
//Create setup for other methods too. note non virtauls methods can not be set up

// Return mock implementation object
return mockRepo.Object;
}
Note, while mocking repository, I have setup two mocks for GetById(). There is a minor change I did in the database, I have marked AuthToken field as a primary key too. So it may be a situation where mock gets confused on calling the method that for which primary key the request has been made. So I have implemented the mock both for TokenId and AuthToken field:
mockRepo.Setup(p => p.GetByID(It.IsAny())).Returns(new Func(
id => _tokens.Find(p => p.TokenId.Equals(id))));

mockRepo.Setup(p => p.GetByID(It.IsAny())).Returns(new Func(
authToken => _tokens.Find(p => p.AuthToken.Equals(authToken))));
The overall setup is of same nature as we wrote for ProductService. Let us move on to unit tests.

1. GenerateTokenByUseridTest ()

This unit test is to test the GenerateToken method of TokenServices business service. In this method, a new token is generated in the database against a user. We’ll use _tokens list for all these transactions. Currently we have only two token entries in _tokens list generated from DataInitializer. Now when the test executes it should expect one more token to be added to the list.
[Test]
 public void GenerateTokenByUserIdTest()
 {
     const int userId = 1;
     var maxTokenIdBeforeAdd = _tokens.Max(a => a.TokenId);
     var tokenEntity = _tokenServices.GenerateToken(userId);
     var newTokenDataModel = new Token()
                                 {
                                     AuthToken = tokenEntity.AuthToken,
                                     TokenId = maxTokenIdBeforeAdd+1,
                                     ExpiresOn = tokenEntity.ExpiresOn,
                                     IssuedOn = tokenEntity.IssuedOn,
                                     UserId = tokenEntity.UserId
                                 };
     AssertObjects.PropertyValuesAreEquals(newTokenDataModel, _tokens.Last());
 }
I have taken a default user id as 1, and stored the max token id from the list of tokens. Call the service methodGenerateTokenEntity (). Since our service method returns BusinessEntities.TokenEntity, we need to map it to new DataModel.Token object for comparison. So the expected result is that all the properties of this token should match the last token of the _token list assuming that list is updated through the test.
Now since all the properties of the resultant and actual object match, so our test passes.

2. ValidateTokenWithRightAuthToken ()

/// <summary>
/// Validate token test
/// </summary>
[Test]
public void ValidateTokenWithRightAuthToken()
{
    var authToken = Convert.ToString(SampleAuthToken);
    var validationResult = _tokenServices.ValidateToken(authToken);
    Assert.That(validationResult,Is.EqualTo(true));
}
This test validates AuthToken through ValidateToken method of TokenService. Ideally if correct token is passed, the service should return true.
Here we get validationResult as true therefore test should pass.

3. ValidateTokenWithWrongAuthToken ()

Testing the same method for its alternate exit point, therefore, with the wrong token, the service should return false.
[Test]
 public void ValidateTokenWithWrongAuthToken()
 {
     var authToken = Convert.ToString("xyz");
     var validationResult = _tokenServices.ValidateToken(authToken);
     Assert.That(validationResult, Is.EqualTo(false));
 }
Here validationResult is false, and is compared to false value, so test should ideally pass.

UserService Tests

I have tried writing unit tests for UserService as per our service implementations, but encountered an error while mocking up our repositories Get () method that takes predicate or where condition as a parameter.
public TEntity Get(Func where)
     {
         return DbSet.Where(where).FirstOrDefault();
     }
Our service methods heavily depend on the Get method so none of the methods could be tested, but apart from this you can search for any other mocking framework that takes care of these situations. I guess this is a bug in the mocking framework. Alternatively, refrain from using Get method with predicate (I would not suggest this approach as it is against the testing strategy. Our tests should not be limited to technical feasibility of methods). I got the following error while mocking repository:
“Invalid setup on a non-virtual (overridable in VB)”. I have commented out all UserService Unit test code, you can find it in available source code.

Test through NUnit UI

We have completed almost all the BusinessServices test, now let us try to execute these test on NUnit UI.
  1. Step 1:Launch NUnit UI. I have already explained how to install NUnit on the windows machine. Just launch the NUnit interface with its launch icon
  2. Step 2 :Once the interface opens, click on File -> New Project and name the project as WebAPI.nunit and save it at any windows location.


  3. Step 3:Now, click on Project-> Add Assembly and browse for BusinessServices.Tests.dll (The library created for your unit test project when compiled)

  4. Step 4:Once the assembly is browsed, you’ll see all the unit tests for that test project gets loaded in the UI and are visible on the interface.
  5. Step 5:At the right hand side panel of the interface, you’ll see a Run button that runs all the tests of business service. Just select the node BusinessServices in the tests tree on left side and press Run button on the right side.

    Once you run the tests, you’ll get green progress bar on right side and tick mark on all the tests on left side. That means all the tests are passed. In case any test fails, you’ll get cross mark on the test and red progress bar on right side.

    But here, all of our tests are passed.

WebAPI Tests

Unit tests for WebAPI are not exactly like service methods, but vary in terms of testing HttpResponse, returned JSON, exception responses etc. Note that we’ll mock the classes and repository in a similar way in WebAPI unit tests as we did for services. One way of testing a web api is through web client and testing the actual endpoint or hosted URL of the service, but that is not considered as a unit test, that is called integration testing. In the next part of the article I’ll explain step by step procedure to unit test a web API. We’ll write tests for Product Controller.

Conclusion

In this article we learnt how to write unit tests for core business logic and primarily on basic CRUD operations. The purpose was to get a basic idea on how unit tests are written and executed. You can add your own flavor to this that helps you in your real time project. My next article which explains unit tests for WebAPI controllers will be the continuation of this part. I hope this was useful to you. You can download the complete source code of this article with packages from GitHub. Happy coding Smile | :)

 

 

RESTful Day #6: Request logging and Exception handling/logging in Web APIs using Action Filters, Exception Filters and NLog


Download Source Code from GitHub

Introduction

We have been learning a lot about WebAPI, its uses, implementations, and security aspects since last five articles of the series. This article of the series will explain how we can handle requests and log them for tracking and for the sake of debugging, how we can handle exceptions and log them. We’ll follow a centralized way of handling exceptions in WebAPI and write our custom classes to be mapped to the type of exception that we encounter and log the accordingly. I’ll use NLog to log requests and exceptions as well. We’ll leverage the capabilities of Exception Filters and Action Filters to centralize request logging and exception handling in WebAPI.

Roadmap

The following is the roadmap I have setup to learn WebAPI step by step,
I’ll purposely use Visual Studio 2010 and .NET Framework 4.0 because there are few implementations that are very hard to find in .NET Framework 4.0, but I’ll make it easy by showing how we can do it.

Request Logging

Since we are writing web services, we are exposing our end points. We must know where the requests are coming from and what requests are coming to our server. Logging could be very beneficial and helps us in a lot of ways like, debugging, tracing, monitoring and analytics.

We already have an existing design. If you open the solution, you’ll get to see the structure as mentioned below or one can also implement this approach in their existing solution as well.

Setup NLog in WebAPI

NLog serves various purposes but primarily logging. We’ll use NLog for logging into files and windows event as well. You can read more about NLog at http://NLog-project.org/
One can use the sample application that we used in Day#5 or can have any other application as well. I am using the existing sample application that we were following throughout all the parts of this series. Our application structure looks something like:

Step 1: Download NLog Package

Right click WebAPI project and select manage Nuget Packages from the list. When the Nuget Package Manager appears, search for NLog. You’ll get Nlog like shown in image below, just install it to our project.

After adding this you will find following NLog dll referenced in your application.

Step 2: Configuring NLog

To configure NLog with application add following settings in our existing WebAPI web.config file,

ConfigSection –

Configuration Section – I have added the section to configuration and defined the path and format dynamic target log file name, also added the eventlog source to Api Services.

As mentioned in above target path, I have also created to “APILog” folder in the base directory of application.

Now we have configured the NLog in our application, and it is ready to start work for request logging. Note that in the rules section we have defined rules for logging in files as well as in windows events log as well, you can choose both of them or can opt for one too. Let’s start with logging request in application, with action filters –

NLogger Class

Add a folder “Helpers” in the API, which will segregate the application code for readability, better understanding and maintainability.

To start add our main class “NLogger“, which will responsible for all types of errors and info logging, to same Helper folder. Here NLogger class implements ITraceWriter interface, which provides “Trace” method for the service request.
#region Using namespaces.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Tracing;
using NLog;
using System.Net.Http;
using System.Text;
using WebApi.ErrorHelper;
#endregion

namespace WebApi.Helpers
{
    /// <summary>
    /// Public class to log Error/info messages to the access log file
    /// </summary>
    public sealed class NLogger : ITraceWriter
    {
        #region Private member variables.
        private static readonly Logger ClassLogger = LogManager.GetCurrentClassLogger();

        private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>>(() => new Dictionary<TraceLevel, Action<string>> { { TraceLevel.Info, ClassLogger.Info }, { TraceLevel.Debug, ClassLogger.Debug }, { TraceLevel.Error, ClassLogger.Error }, { TraceLevel.Fatal, ClassLogger.Fatal }, { TraceLevel.Warn, ClassLogger.Warn } });
        #endregion

        #region Private properties.
        /// <summary>
        /// Get property for Logger
        /// </summary>
        private Dictionary<TraceLevel, Action<string>> Logger
        {
            get { return LoggingMap.Value; }
        }
        #endregion

        #region Public member methods.
        /// <summary>
        /// Implementation of TraceWriter to trace the logs.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="category"></param>
        /// <param name="level"></param>
        /// <param name="traceAction"></param>
        public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action traceAction)
        {
            if (level != TraceLevel.Off)
            {
                if (traceAction != null && traceAction.Target != null)
                {
                    category = category + Environment.NewLine + "Action Parameters : " + traceAction.Target.ToJSON();
                }
                var record = new TraceRecord(request, category, level);
                if (traceAction != null) traceAction(record);
                Log(record);
            }
        }
        #endregion

        #region Private member methods.
        /// <summary>
        /// Logs info/Error to Log file
        /// </summary>
        /// <param name="record"></param>
        private void Log(TraceRecord record)
        {
            var message = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

            if (record.Request != null)
            {
                if (record.Request.Method != null)
                    message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);

            
            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }
        #endregion
    }
}

Adding Action Filter

Action filter will be responsible for handling all the incoming requests to our APIs and logging them using NLogger class. We have “OnActionExecuting” method that is implicitly called if we mark our controllers or global application to use that particular filter. So each time any action of any controller will be hit, our “OnActionExecuting” method will execute to log the request.

Step 1: Adding LoggingFilterAttribute class

Create a class LoggingFilterAttribute to “ActionFilters” folder and add following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Http.Controllers;
using System.Web.Http.Tracing;
using System.Web.Http;
using WebApi.Helpers;


namespace WebApi.ActionFilters
{
    public class LoggingFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            trace.Info(filterContext.Request, "Controller : " + filterContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + filterContext.ActionDescriptor.ActionName, "JSON", filterContext.ActionArguments);
        }
    }
}
The LoggingFilterAttribute class derived from ActionFilterAttribute, which is underSystem.Web.Http.Filters and overriding the OnActionExecuting method.
Here I have replaced the default “ITraceWriter” service with our NLogger class instance in the controller’s service container. Now GetTraceWriter() method will return our instance (instance NLogger class) and Info() will call trace() method of our NLogger class.
Note that the code below.
GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
is used to resolve dependency between ITaceWriter and NLogger class. Thereafter we use a variable namedtrace to get the instance and trace.Info() is used to log the request and whatever text we want to add along with that request.

Step 2: Registering Action Filter (LoggingFilterAttribute)

In order to register the created action filter to application’s filters, just add a new instance of your action filter toconfig.Filters in WebApiConfig class.
using System.Web.Http;
using WebApi.ActionFilters;

namespace WebApi.App_Start
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Filters.Add(new LoggingFilterAttribute());
        }
    }
}
Now this action filter is applicable to all the controllers and actions in our project. You may not believe but request logging is done. It’s time to run the application and validate our homework.

Running the application

Let’s run the application and try to make a call, using token based authorization, we have already covered authorization in day#5. You first need to authenticate your request using login service and then that service will return a token for making calls to other services. Use that token to make calls to other services. For more details you can read day 5 of this series.
Just run the application, we get
We already have our test client added, but for new readers, just go to Manage Nuget Packages, by right clicking WebAPI project and typing WebAPITestClient in searchbox in online packages
You’ll get “A simple Test Client for ASP.NET Web API”, just add it. You’ll get a help controller in Areas-> HelpPage like shown below:
I have already provided the database scripts and data in my previous article, you can use the same.
Append “/help” in the application url, and you’ll get the test client,
GET:
POST:
PUT:
DELETE:
You can test each service by clicking on it. Once you click on the service link, you’ll be redirected to test the service page of that particular service. On that page there is a button Test API in the right bottom corner, just press that button to test your service:
Service for Get All products:
In the below case, I have already generated the token and now I am using it to make call to fetch all the products from the products table in the database.

Here I have called allproducts API, Add the value for parameter Id and “Token” header with its current value and click to get the result:

Now let’s see what happens to our APILog folder in application. Here you find the API log has been created, with the same name we have configured in NLog configuration in web.config file. The log file contains all the supplied details like Timestamp, Method type, URL , Header information (Token), Controller name, action and action parameters. You can also add more details to this log which you deem important for your application.

Logging Done!

Exception Logging

Our logging setup is completed, now we’ll focus on centralizing exception logging as well, so that none of the exception escapes without logging itself. Logging exception is of very high importance, it keeps track of all the exceptions. No matter business or application or system exceptions, all of them have to be logged.

Implementing Exception logging

Step 1: Exception Filter Attribute

Now we will add an action filter in our application for logging the exceptions. For this create a class,GlobalExceptionAttribute to “ActionFilter” folder and add the code below, the class is derived fromExceptionFilterAttribute, which is under System.Web.Http.Filters.
I override the OnException() method and replace the default “ITraceWriter” service with our NLogger class instance in the controller’s service container, same as we have done in Action logging in above section. Now theGetTraceWriter() method will return our instance (instance NLogger class) and Info() will call trace()method of NLogger class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Http;
using System.Web.Http.Tracing;
using WebApi.Helpers;
using System.ComponentModel.DataAnnotations;
using System.Net.Http;
using System.Net;

namespace WebApi.ActionFilters
{
    /// <summary>
    /// Action filter to handle for Global application errors.
    /// </summary>
    public class GlobalExceptionAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            trace.Error(context.Request, "Controller : " + context.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + context.ActionContext.ActionDescriptor.ActionName, context.Exception);

            var exceptionType = context.Exception.GetType();

            if (exceptionType == typeof(ValidationException))
            {
                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "ValidationException", };
                throw new HttpResponseException(resp);

            }
            else if (exceptionType == typeof(UnauthorizedAccessException))
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.Unauthorized));
            }
            else
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.InternalServerError));
            }
        }
    }
}

Step 2: Modify NLogger Class

Our NLogger class is capable to log all info and events, I have done some changes in private method Log() to handle the exceptions
#region Private member methods.
/// <summary>
/// Logs info/Error to Log file
/// </summary>
/// <param name="record"></param>
private void Log(TraceRecord record)
{
var message = new StringBuilder();

if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

      if (record.Request != null)
{
       if (record.Request.Method != null)
            message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);

            if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))
            {
                var exceptionType = record.Exception.GetType();
                message.Append(Environment.NewLine);
                message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);
            }

            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }

Step 3: Modify Controller for Exception

Our application is now ready to run, but there is no exception in our code, so I added a throw exception code inProductController, just the Get(int id) method so that it can throw exception for testing our exception logging mechanism. It will throw an exception if the product is not there in database with the provided id.
  // GET api/product/5
 [GET("productid/{id?}")]
 [GET("particularproduct/{id?}")]
 [GET("myproduct/{id:range(1, 3)}")]
 public HttpResponseMessage Get(int id)
 {
var product = _productServices.GetProductById(id);
      if (product != null)
       return Request.CreateResponse(HttpStatusCode.OK, product);

 throw new Exception("No product found for this id");
      //return Request.CreateErrorResponse(HttpStatusCode.NotFound,   "No product found for this id");
 }

Step 4: Run the application

Run the application and click on Product/all API
Add the parameter id value to 1 and header Token with it’s current value, click on send button to get the result:
Now we can see that the Status is 200/OK, and we also get a product with the provided id in the response body. Let’s see the API log now:
The log has captured the call of Product API, now provide a new product id as parameter, which is not there in database, I am using 12345 as product id and result is:

We can see there is an 500/Internal Server Error now in response status, let’s check the API Log:

Well, now the log has captured both the event and error of same call on the server, you can see call log details and the error with provided error message in the log.

Custom Exception logging

In the above section we have implemented exception logging, but there is default system response and status (i.e. 500/Internal Server Error). It will be always good to have your own custom response and exceptions for your API. That will be easier for client to consume and understand the API responses.

Step 1: Add Custom Exception Classes

Add “Error Helper” folder to application to maintain our custom exception classes separately and add “IApiExceptions” interface to newly created “ErrorHelper” folder –
Add following code the IApiExceptions interface, this will serve as a template for all exception classes, I have added four common properties for our custom classes to maintain Error Code, ErrorDescription, HttpStatus (Contains the values of status codes defined for HTTP) and ReasonPhrase.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// IApiExceptions Interface
    /// </summary>
    public interface IApiExceptions
    {
        /// <summary>
        /// ErrorCode
        /// </summary>
        int ErrorCode { get; set; }
        /// <summary>
        /// ErrorDescription
        /// </summary>
        string ErrorDescription { get; set; }
        /// <summary>
        /// HttpStatus
        /// </summary>
        HttpStatusCode HttpStatus { get; set; }
        /// <summary>
        /// ReasonPhrase
        /// </summary>
        string ReasonPhrase { get; set; }
    }
}
Here, I divided our exceptions in three categories:
  1. API Exceptions – for API level exceptions.
  2. Business Exceptions – for exceptions at business logic level.
  3. Data Exceptions – Data related exceptions.
To implement this create a three new classes ApiException.cs, ApiDataException.cs and ApiBusinessExceptionclasses to same folder which implements IApiExceptions interface with following code to the classes.
#region Using namespaces.
using System;
using System.Net;
using System.Runtime.Serialization;
#endregion


namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }
        
        string reasonPhrase = "ApiException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }
        #endregion
    }
}
I have initialized ReasonPhrase property with different default values in these classes to differentiate the implementation, you can use implement your custom classes as per your application needs.
The directives applied on class as Serializable and DataContract to make sure that the class defines or implements a data contract is serializable and can be serialize by a serializer.
Note: Add reference of “System.Runtime.Serialization.dll” DLL if you facing any assembly issue.
In the same way add “ApiBusinessException” and “ApiDataException” classes into the same folder, with the following code –
#region Using namespaces.
using System;
using System.Net;
using System.Runtime.Serialization; 
#endregion

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Business Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiBusinessException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }

        string reasonPhrase = "ApiBusinessException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }
        #endregion

        #region Public Constructor.
        /// <summary>
        /// Public constructor for Api Business Exception
        /// </summary>
        /// <param name="errorCode"></param>
        /// <param name="errorDescription"></param>
        /// <param name="httpStatus"></param>
        public ApiBusinessException(int errorCode, string errorDescription, HttpStatusCode httpStatus)
        {
            ErrorCode = errorCode;
            ErrorDescription = errorDescription;
            HttpStatus = httpStatus;
        } 
        #endregion

    }
}

#region Using namespaces.
using System;
using System.Net;
using System.Runtime.Serialization;
#endregion

namespace WebApi.ErrorHelper
{
    /// <summary>
    /// Api Data Exception
    /// </summary>
    [Serializable]
    [DataContract]
    public class ApiDataException : Exception, IApiExceptions
    {
        #region Public Serializable properties.
        [DataMember]
        public int ErrorCode { get; set; }
        [DataMember]
        public string ErrorDescription { get; set; }
        [DataMember]
        public HttpStatusCode HttpStatus { get; set; }

        string reasonPhrase = "ApiDataException";

        [DataMember]
        public string ReasonPhrase
        {
            get { return this.reasonPhrase; }

            set { this.reasonPhrase = value; }
        }

        #endregion

        #region Public Constructor.
        /// <summary>
        /// Public constructor for Api Data Exception
        /// </summary>
        /// <param name="errorCode"></param>
        /// <param name="errorDescription"></param>
        /// <param name="httpStatus"></param>
        public ApiDataException(int errorCode, string errorDescription, HttpStatusCode httpStatus)
        {
            ErrorCode = errorCode;
            ErrorDescription = errorDescription;
            HttpStatus = httpStatus;
        }
        #endregion
    }
}

JSon Serializers

There are some objects need to be serialized in JSON, to log and to transfer through the modules, for this I have add some extension methods to Object class.
For that add “System.Web.Extensions.dll” reference to project and add “JSONHelper” class to Helpers folder, with following code:
#region Using namespaces.
using System.Web.Script.Serialization;
using System.Data;
using System.Collections.Generic;
using System;

#endregion

namespace WebApi.Helpers
{
    public static class JSONHelper
    {
         #region Public extension methods.
        /// <summary>
        /// Extened method of object class, Converts an object to a json string.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJSON(this object obj)
        {
            var serializer = new JavaScriptSerializer();
            try
            {
                return serializer.Serialize(obj);
            }
            catch(Exception ex)
            {
                return "";
            }
        }
         #endregion
    }
}
In the above code “ToJSON()” method is an extension of base Object class, which serializes supplied the object to a JSON string. The method using “JavaScriptSerializer” class which exists in “System.Web.Script.Serialization“.

Modify NLogger Class

For exception handling I have modified the Log() method of NLogger, which will now handle the different API exceptions.
/// <summary>
/// Logs info/Error to Log file
/// </summary>
/// <param name="record"></param>
private void Log(TraceRecord record)
{
var message = new StringBuilder();

      if (!string.IsNullOrWhiteSpace(record.Message))
                message.Append("").Append(record.Message + Environment.NewLine);

            if (record.Request != null)
            {
                if (record.Request.Method != null)
                    message.Append("Method: " + record.Request.Method + Environment.NewLine);

                if (record.Request.RequestUri != null)
                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);

                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)
                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);
            }

            if (!string.IsNullOrWhiteSpace(record.Category))
                message.Append("").Append(record.Category);

            if (!string.IsNullOrWhiteSpace(record.Operator))
                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);

            if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))
            {
                var exceptionType = record.Exception.GetType();
                message.Append(Environment.NewLine);
                if (exceptionType == typeof(ApiException))
                {
                    var exception = record.Exception as ApiException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else if (exceptionType == typeof(ApiBusinessException))
                {
                    var exception = record.Exception as ApiBusinessException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else if (exceptionType == typeof(ApiDataException))
                {
                    var exception = record.Exception as ApiDataException;
                    if (exception != null)
                    {
                        message.Append("").Append("Error: " + exception.ErrorDescription + Environment.NewLine);
                        message.Append("").Append("Error Code: " + exception.ErrorCode + Environment.NewLine);
                    }
                }
                else
                    message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);
            }

            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);
        }
The code above checks the exception object of TraceRecord and updates the logger as per the exception type.

Modify GlobalExceptionAttribute

As we have created GlobalExceptionAttribute to handle all exceptions and create response in case of any exception. Now I have added some new code to this in order to enable the GlobalExceptionAttribute class to handle custom exceptions. I am adding only modified method here for your reference .
public override void OnException(HttpActionExecutedContext context)
{
         GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogger());
            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();
            trace.Error(context.Request, "Controller : " + context.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + context.ActionContext.ActionDescriptor.ActionName, context.Exception);

            var exceptionType = context.Exception.GetType();

            if (exceptionType == typeof(ValidationException))
            {
                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "ValidationException", };
                throw new HttpResponseException(resp);

            }
            else if (exceptionType == typeof(UnauthorizedAccessException))
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.Unauthorized, new ServiceStatus() { StatusCode = (int)HttpStatusCode.Unauthorized, StatusMessage = "UnAuthorized", ReasonPhrase = "UnAuthorized Access" }));
            }
            else if (exceptionType == typeof(ApiException))
            {
                var webapiException = context.Exception as ApiException;
                if (webapiException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(webapiException.HttpStatus, new ServiceStatus() { StatusCode = webapiException.ErrorCode, StatusMessage = webapiException.ErrorDescription, ReasonPhrase = webapiException.ReasonPhrase }));
            }
            else if (exceptionType == typeof(ApiBusinessException))
            {
                var businessException = context.Exception as ApiBusinessException;
                if (businessException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(businessException.HttpStatus, new ServiceStatus() { StatusCode = businessException.ErrorCode, StatusMessage = businessException.ErrorDescription, ReasonPhrase = businessException.ReasonPhrase }));
            }
            else if (exceptionType == typeof(ApiDataException))
            {
                var dataException = context.Exception as ApiDataException;
                if (dataException != null)
                    throw new HttpResponseException(context.Request.CreateResponse(dataException.HttpStatus, new ServiceStatus() { StatusCode = dataException.ErrorCode, StatusMessage = dataException.ErrorDescription, ReasonPhrase = dataException.ReasonPhrase }));
            }
            else
            {
                throw new HttpResponseException(context.Request.CreateResponse(HttpStatusCode.InternalServerError));
            }
        }
In the above code I have modified the overrided method OnExeption() and created new Http response exception based on the different exception types.

Modify Product Controller

Now modify the Product controller to throw our custom exception form, please look into the Get method I have modified to throw the APIDataException in case if data is not found and APIException in any other kind of error.
// GET api/product/5
[GET("productid/{id?}")]
[GET("particularproduct/{id?}")]
[GET("myproduct/{id:range(1, 3)}")]
public HttpResponseMessage Get(int id)
{
if (id != null)
      {
       var product = _productServices.GetProductById(id);
            if (product != null)
             return Request.CreateResponse(HttpStatusCode.OK, product);

throw new ApiDataException(1001, "No product found for this id.", HttpStatusCode.NotFound);
      }
      throw new ApiException() { ErrorCode = (int)HttpStatusCode.BadRequest, ErrorDescription = "Bad Request..." };
}

Run the application

Run the application and click on Product/all API:
Add the parameter id value to 1 and header Token with its current value, click on send button to get the result:
Now we can see that the Status is 200/OK, and we also get a product with the provided id in the response body. Lets see the API log now –
The log has captured the call of Product API, now provide a new product id as parameter, which is not there in database, I am using 12345 as product id and result is:
We can see, now there is a custom error status code “1001” and messages “No product found for this id.” And the generic status code “500/Internal Server Error” is now replaced with our supplied code “404/ Not Found”, which is more meaningful for the client or consumer.
Lets see the APILog now:
Well, now the log has captured both the event and error of same call on the server, you can see call log details and the error with provided error message in the log with our custom error code, I have only captured error description and error code, but you can add more details in the log as per your application needs.

Update the controller for new Exception Handling

Following is the code for controllers with implementation of custom exception handling and logging:

Product Controller

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using AttributeRouting;
using AttributeRouting.Web.Http;
using BusinessEntities;
using BusinessServices;
using WebApi.ActionFilters;
using WebApi.Filters;
using System;
using WebApi.ErrorHelper;

namespace WebApi.Controllers
{
    [AuthorizationRequired]
    [RoutePrefix("v1/Products/Product")]
    public class ProductController : ApiController
    {
        #region Private variable.

        private readonly IProductServices _productServices;

        #endregion

        #region Public Constructor

        /// <summary>
        /// Public constructor to initialize product service instance
        /// </summary>
        public ProductController(IProductServices productServices)
        {
            _productServices = productServices;
        }

        #endregion

        // GET api/product
        [GET("allproducts")]
        [GET("all")]
        public HttpResponseMessage Get()
        {
            var products = _productServices.GetAllProducts();
            var productEntities = products as List ?? products.ToList();
            if (productEntities.Any())
                return Request.CreateResponse(HttpStatusCode.OK, productEntities);
            throw new ApiDataException(1000, "Products not found", HttpStatusCode.NotFound);
        }

        // GET api/product/5
        [GET("productid/{id?}")]
        [GET("particularproduct/{id?}")]
        [GET("myproduct/{id:range(1, 3)}")]
        public HttpResponseMessage Get(int id)
        {
            if (id != null)
            {
                var product = _productServices.GetProductById(id);
                if (product != null)
                    return Request.CreateResponse(HttpStatusCode.OK, product);

                throw new ApiDataException(1001, "No product found for this id.", HttpStatusCode.NotFound);
            }
            throw new ApiException() { ErrorCode = (int)HttpStatusCode.BadRequest, ErrorDescription = "Bad Request..." };
        }

        // POST api/product
        [POST("Create")]
        [POST("Register")]
        public int Post([FromBody] ProductEntity productEntity)
        {
            return _productServices.CreateProduct(productEntity);
        }

        // PUT api/product/5
        [PUT("Update/productid/{id}")]
        [PUT("Modify/productid/{id}")]
        public bool Put(int id, [FromBody] ProductEntity productEntity)
        {
            if (id > 0)
            {
                return _productServices.UpdateProduct(id, productEntity);
            }
            return false;
        }

        // DELETE api/product/5
        [DELETE("remove/productid/{id}")]
        [DELETE("clear/productid/{id}")]
        [PUT("delete/productid/{id}")]
        public bool Delete(int id)
        {
            if (id != null && id > 0)
            {
                var isSuccess = _productServices.DeleteProduct(id);
                if (isSuccess)
                {
                    return isSuccess;
                }
                throw new ApiDataException(1002, "Product is already deleted or not exist in system.", HttpStatusCode.NoContent );
            }
            throw new ApiException() {ErrorCode = (int) HttpStatusCode.BadRequest, ErrorDescription = "Bad Request..."};
        }
    }
}
Now you can see, our application is so rich and scalable that none of the exception or transaction can escapelogging.Once setup is inplaced, now you don’t have to worry about writing code each time for logging or requests and exceptions, but you can relax and focus on business logic only.

Conclusion

In this article we learnt about how to perform request logging and exception logging in WebPI. There could be numerous ways in which you can perform these operations but I tried to present this in as simple way as possible. My approach was to take our enterprise level to next level of development, where developers should not always be worried about exception handling and logging. Our solution provides a generic approach of centralizing the operations in one place; all the requests and exceptions are automatically taken care of. In my new articles, I’ll try to enhance the application by explaining unit testing in WebAPI and OData in WebAPI. You can download the complete source code of this article with packages from GitHub. Happy coding Smile | :)

RESTful Day #5: Security in Web APIs-Basic Authentication and Token based custom Authorization in Web APIs using Action Filters


Introduction

Security has always been a major concern we talk about enterprise level applications, especially when we talk about exposing our business through services. I have already explained a lot on WebAPI in my earlier articles of the series. I explained, how do we create a WebAPI, how to resolve dependencies to make it a loosely coupled design, defining custom routes, making use of attribute routing. My article will explain how we can achieve security in a WebAPI. This article will explain how to make WebAPI secure using Basic Authentication and Token based authorization. I’ll also explain how we can leverage token based authorization and Basic authentication in WebAPI to maintain sessions in WebAPI. There is no standard way of achieving security in WebAPI. We can design our own security technique and structure which suits best to our application.

Roadmap

Following is the roadmap I have setup to learn WebAPI step by step,

I’ll purposely use Visual Studio 2010 and .NET Framework 4.0 because there are few implementations that are very hard to find in .NET Framework 4.0, but I’ll make it easy by showing how we can do it.

Security in WebAPI

Security in itself is very complicated and tricky topic. I’ll try to explain how we can achieve it in WebAPI in my own way.
When we plan to create an enterprise level application, we especially want to take care of authentication and authorization. These are two techniques if used well makes our application secure, in our case makes our WebAPI more secure.

Authentication

Authentication is all about the identity of an end user. It’s about validating the identity of a user who is accessing our system, that he is authenticated enough to use our resources or not. Does that end user have valid credentials to log in our system? Credentials can be in the form of a user name and password. We’ll use Basic Authentication technique to understand how we can achieve authentication in WebAPI.

Authorization

Authorization should be considered as a second step after authentication to achieve security. Authorization means what all permissions the authenticated user has to access web resources. Is allowed to access/ perform action on that resource? This could be achieved by setting roles and permissions for an end user who is authenticated, or can be achieved through providing a secure token, using which an end user can have access to other services or resources.

Maintaining Session

RESTful services work on a stateless protocol i.e. HTTP. We can achieve maintaining session in Web API through token based authorization technique. An authenticated user will be allowed to access resources for a particular period of time, and can re-instantiate the request with an increased session time delta to access other resource or the same resource. Websites using WebAPIs as RESTful services may need to implement login/logout for a user, to maintain sessions for the user, to provide roles and permissions to their user, all these features could be achieved using basic authentication and token based authorization. I’ll explain this step by step.

Basic Authentication

Basic authentication is a mechanism, where an end user gets authenticated through our service i.e. RESTful service with the help of plain credentials such as user name and password. An end user makes a request to the service for authentication with user name and password embedded in request header. Service receives the request and checks if the credentials are valid or not, and returns the response accordingly, in case of invalid credentials, service responds with 401 error code i.e. unauthorized. The actual credentials through which comparison is don may lie in database , any config file like web.config or in the code itself.

Pros and Cons of Basic Authentication

Basic authentication has its own pros and cons. It is advantageous when it comes to implementation, it is very easy to implement, it is nearly supported by all modern browsers and has become an authentication standard in RESTful / Web APIs. It has disadvantages like sending user credentials in plain text, sending user credentials inside request header, i.e. prone to hack. One have to send credentials each time a service is called. No session is maintained and a user cannot logout once logged in through basic authentication. It is very prone to CSRF (Cross Site Request Forgery).

Token Based Authorization

Authorization part comes just after authentication, once authenticated a service can send a token to an end user through which user can access other resources. The token could be any encrypted key, which only server/service understands and when it fetches the token from the request made by end user, it validates the token and authorizes user into the system. Token generated could be stored in a database or an external file as well i.e. we need to persist the token for future references. Token can have its own lifetime, and may expire accordingly. In that case user will again have to be authenticated into the system.

WebAPI with Basic Authentication and Token Based Authorization

Creating User Service

Just open your WebAPI project or the WebAPI project that we discussed in the last part of learning WebAPI.
We have BusinessEntities, BusinessServices, DataModel, DependencyResolver and a WebApi project as well.
We already have a User table in database, or you can create your own database with a table like User Table as shown below,
I am using WebAPI database, scripts I have attached for download.

UserServices

Go to BusinessServices project and add a new interface IUserService and a service named UserServices implementing that interface,
Just define one method named Authenticate in the interface.
namespace BusinessServices
{
    public interface IUserServices
    {
        int Authenticate(string userName, string password);
    }
}
This method takes username and password as a parameter and returns particular userId if the user is authenticated successfully.
Just implement this method in UserServices.cs class, just like we created services earlier in the series,
using DataModel.UnitOfWork;

namespace BusinessServices
{
    /// <summary>
    /// Offers services for user specific operations
    /// </summary>
    public class UserServices : IUserServices
    {
        private readonly UnitOfWork _unitOfWork;

        /// <summary>
        /// Public constructor.
        /// </summary>
        public UserServices(UnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        /// <summary>
        /// Public method to authenticate user by user name and password.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public int Authenticate(string userName, string password)
        {
            var user = _unitOfWork.UserRepository.Get(u => u.UserName == userName && u.Password == password);
            if (user != null && user.UserId > 0)
            {
                return user.UserId;
            }
            return 0;
        }
    }
}
You can clearly see that Authenticate method just checks user credentials from UserRepository and returns the values accordingly. The code is very much self-explanatory.

Resolve dependency of UserService

Just open DependencyResolver class in BusinessServices project itself and add its dependency type so that we get UserServices dependency resolved at run time,so add
registerComponent.RegisterType();
line to SetUP method. Our class becomes,
using System.ComponentModel.Composition;
using DataModel;
using DataModel.UnitOfWork;
using Resolver;

namespace BusinessServices
{
    [Export(typeof(IComponent))]
    public class DependencyResolver : IComponent
    {
        public void SetUp(IRegisterComponent registerComponent)
        {
            registerComponent.RegisterType();
            registerComponent.RegisterType();
        }
    }
}

Implementing Basic Authentication

Step 1: Create generic Authentication Filter

Add a folder named Filters to the WebAPI project and add a class named GenericAuthenticationFilter under that folder.
Derive that class from AuthorizationFilterAttribute, this is a class under System.Web.Http.Filters.
I have created the generic authentication filter will be like,
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class GenericAuthenticationFilter : AuthorizationFilterAttribute
    {
      
        /// <summary>
        /// Public default Constructor
        /// </summary>
        public GenericAuthenticationFilter()
        {
        }

        private readonly bool _isActive = true;

        /// <summary>
        /// parameter isActive explicitly enables/disables this filetr.
        /// </summary>
        /// <param name="isActive"></param>
        public GenericAuthenticationFilter(bool isActive)
        {
            _isActive = isActive;
        }

        /// <summary>
        /// Checks basic authentication request
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnAuthorization(HttpActionContext filterContext)
        {
            if (!_isActive) return;
            var identity = FetchAuthHeader(filterContext);
            if (identity == null)
            {
                ChallengeAuthRequest(filterContext);
                return;
            }
            var genericPrincipal = new GenericPrincipal(identity, null);
            Thread.CurrentPrincipal = genericPrincipal;
            if (!OnAuthorizeUser(identity.Name, identity.Password, filterContext))
            {
                ChallengeAuthRequest(filterContext);
                return;
            }
            base.OnAuthorization(filterContext);
        }

        /// <summary>
        /// Virtual method.Can be overriden with the custom Authorization.
        /// </summary>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        protected virtual bool OnAuthorizeUser(string user, string pass, HttpActionContext filterContext)
        {
            if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
                return false;
            return true;
        }

        /// <summary>
        /// Checks for autrhorization header in the request and parses it, creates user credentials and returns as BasicAuthenticationIdentity
        /// </summary>
        /// <param name="filterContext"></param>
        protected virtual BasicAuthenticationIdentity FetchAuthHeader(HttpActionContext filterContext)
        {
            string authHeaderValue = null;
            var authRequest = filterContext.Request.Headers.Authorization;
            if (authRequest != null && !String.IsNullOrEmpty(authRequest.Scheme) && authRequest.Scheme == "Basic")
                authHeaderValue = authRequest.Parameter;
            if (string.IsNullOrEmpty(authHeaderValue))
                return null;
            authHeaderValue = Encoding.Default.GetString(Convert.FromBase64String(authHeaderValue));
            var credentials = authHeaderValue.Split(':');
            return credentials.Length < 2 ? null : new BasicAuthenticationIdentity(credentials[0], credentials[1]);
        }


        /// <summary>
        /// Send the Authentication Challenge request
        /// </summary>
        /// <param name="filterContext"></param>
        private static void ChallengeAuthRequest(HttpActionContext filterContext)
        {
            var dnsHost = filterContext.Request.RequestUri.DnsSafeHost;
            filterContext.Response = filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
            filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", dnsHost));
        }
    }
Since this is an AuthorizationFilter derived class, we need to override its methods to add our custom logic. Here “OnAuthorization” method is overridden to add a custom logic. Whenever we get ActionContext onOnAuthorization, we’ll check for its header, since we are pushing our service to followBasicAuthentication, the request headers should contain this information. I have used FetchAuthHeader to check the scheme, if it comes to be “Basic” and thereafter store the credentials i.e. user name and password in a form of an object of class BasicAuthenticationIdentity, therefore creating an identity out of valid credentials.
        protected virtual BasicAuthenticationIdentity FetchAuthHeader(HttpActionContext filterContext)
        {
            string authHeaderValue = null;
            var authRequest = filterContext.Request.Headers.Authorization;
            if (authRequest != null && !String.IsNullOrEmpty(authRequest.Scheme) && authRequest.Scheme == "Basic")
                authHeaderValue = authRequest.Parameter;
            if (string.IsNullOrEmpty(authHeaderValue))
                return null;
            authHeaderValue = Encoding.Default.GetString(Convert.FromBase64String(authHeaderValue));
            var credentials = authHeaderValue.Split(':');
            return credentials.Length < 2 ? null : new BasicAuthenticationIdentity(credentials[0], credentials[1]);
        }
I am expecting values to be encrypted using Base64 string; You can use your own encryption mechanism as well.
Later on in OnAuthorization method we create a genericPrincipal with the created identity and assign it to current Thread principal,
            var genericPrincipal = new GenericPrincipal(identity, null);
            Thread.CurrentPrincipal = genericPrincipal;
            if (!OnAuthorizeUser(identity.Name, identity.Password, filterContext))
            {
                ChallengeAuthRequest(filterContext);
                return;
            }
            base.OnAuthorization(filterContext);
Once done, a challenge to that request is added, where we add response and tell the Basic realm,
filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic
realm=\"{0}\"", dnsHost));
in ChallengeAuthRequest method.
If no credentials is provided in the request, this generic authentication filter sets generic authentication principal to the current thread principal.
Since we know the drawback that in basic authentication credentials are passed in a plain text, so it would be good if our service uses SSL for communication or message passing.
We have an overridden constructor as well that allows to stop the default behavior of the filter by just passing in a parameter i.e. true or false.
  public GenericAuthenticationFilter(bool isActive)
        {
            _isActive = isActive;
        }
We can use OnAuthorizeUser for custom authorization purposes.

Step 2: Create Basic Authentication Identity

Before we proceed further, we also need the BasicIdentity class, that takes hold of credentials and assigns it to Generic Principal. So just add one more class named BasicAuthenticationIdentity deriving fromGenericIdentity.
This class contains three properties i.e. UserNamePassword and UserId. I purposely added UserId because we’ll need that in future. So our class will be like,
using System.Security.Principal;

namespace WebApi.Filters
{
    /// <summary>
    /// Basic Authentication identity
    /// </summary>
    public class BasicAuthenticationIdentity : GenericIdentity
    {
        /// <summary>
        /// Get/Set for password
        /// </summary>
        public string Password { get; set; }
        /// <summary>
        /// Get/Set for UserName
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// Get/Set for UserId
        /// </summary>
        public int UserId { get; set; }

        /// <summary>
        /// Basic Authentication Identity Constructor
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        public BasicAuthenticationIdentity(string userName, string password)
            : base(userName, "Basic")
        {
            Password = password;
            UserName = userName;
        }
    }
}

Step 3: Create a Custom Authentication Filter

Now you are ready to use your own Custom Authentication filter. Just add one more class under that Filters project and call it ApiAuthenticationFilter, this class will derive from GenericAuthenticationFilter, that we created in first step. This class overrider OnAuthorizeUser method to add custom logic for authenticating a request it makes use of UserService that we created earlier to check the user,
protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
        {
            var provider = actionContext.ControllerContext.Configuration
                               .DependencyResolver.GetService(typeof(IUserServices)) as IUserServices;
            if (provider != null)
            {
                var userId = provider.Authenticate(username, password);
                if (userId>0)
                {
                    var basicAuthenticationIdentity = Thread.CurrentPrincipal.Identity as BasicAuthenticationIdentity;
                    if (basicAuthenticationIdentity != null)
                        basicAuthenticationIdentity.UserId = userId;
                    return true;
                }
            }
            return false;
        }
Complete class
using System.Threading;
using System.Web.Http.Controllers;
using BusinessServices;

namespace WebApi.Filters
{
    /// <summary>
    /// Custom Authentication Filter Extending basic Authentication
    /// </summary>
    public class ApiAuthenticationFilter : GenericAuthenticationFilter
    {
        /// <summary>
        /// Default Authentication Constructor
        /// </summary>
        public ApiAuthenticationFilter()
        {
        }

        /// <summary>
        /// AuthenticationFilter constructor with isActive parameter
        /// </summary>
        /// <param name="isActive"></param>
        public ApiAuthenticationFilter(bool isActive)
            : base(isActive)
        {
        }

        /// <summary>
        /// Protected overriden method for authorizing user
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
        {
            var provider = actionContext.ControllerContext.Configuration
                               .DependencyResolver.GetService(typeof(IUserServices)) as IUserServices;
            if (provider != null)
            {
                var userId = provider.Authenticate(username, password);
                if (userId>0)
                {
                    var basicAuthenticationIdentity = Thread.CurrentPrincipal.Identity as BasicAuthenticationIdentity;
                    if (basicAuthenticationIdentity != null)
                        basicAuthenticationIdentity.UserId = userId;
                    return true;
                }
            }
            return false;
        }
    }
}

Step 4: Basic Authentication on Controller

Since we already have our products controller,
   public class ProductController : ApiController
    {
        #region Private variable.

        private readonly IProductServices _productServices;

        #endregion

        #region Public Constructor

        /// <summary>
        /// Public constructor to initialize product service instance
        /// </summary>
        public ProductController(IProductServices productServices)
        {
            _productServices = productServices;
        }

        #endregion

        // GET api/product
        [GET("allproducts")]
        [GET("all")]
        public HttpResponseMessage Get()
        {
            var products = _productServices.GetAllProducts();
            var productEntities = products as List ?? products.ToList();
            if (productEntities.Any())
                return Request.CreateResponse(HttpStatusCode.OK, productEntities);
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Products not found");
        }

        // GET api/product/5
        [GET("productid/{id?}")]
        [GET("particularproduct/{id?}")]
        [GET("myproduct/{id:range(1, 3)}")]
        public HttpResponseMessage Get(int id)
        {
            var product = _productServices.GetProductById(id);
            if (product != null)
                return Request.CreateResponse(HttpStatusCode.OK, product);
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No product found for this id");
        }

        // POST api/product
        [POST("Create")]
        [POST("Register")]
        public int Post([FromBody] ProductEntity productEntity)
        {
            return _productServices.CreateProduct(productEntity);
        }

        // PUT api/product/5
        [PUT("Update/productid/{id}")]
        [PUT("Modify/productid/{id}")]
        public bool Put(int id, [FromBody] ProductEntity productEntity)
        {
            if (id > 0)
            {
                return _productServices.UpdateProduct(id, productEntity);
            }
            return false;
        }

        // DELETE api/product/5
        [DELETE("remove/productid/{id}")]
        [DELETE("clear/productid/{id}")]
        [PUT("delete/productid/{id}")]
        public bool Delete(int id)
        {
            if (id > 0)
                return _productServices.DeleteProduct(id);
            return false;
        }
    }
There are three ways in which you can use this authentication filter.
Just apply this filer to ProductController. You can add this filter at the top of the controller, for all API requests to be validated,
    [ApiAuthenticationFilter]
    [RoutePrefix("v1/Products/Product")]
    public class ProductController : ApiController
You can also globally add this in Web API configuration file , so that filter applies to all the controllers and all the actions associated to it,
GlobalConfiguration.Configuration.Filters.Add(new ApiAuthenticationFilter());
You can also apply it to Action level too by your wish to apply or not apply authentication to that action,
       // GET api/product
        [ApiAuthenticationFilter(true)]
        [GET("allproducts")]
        [GET("all")]
        public HttpResponseMessage Get()
        {
             …………………
        }
        // GET api/product/5
         [ApiAuthenticationFilter(false)]
        [GET("productid/{id?}")]
        [GET("particularproduct/{id?}")]
        [GET("myproduct/{id:range(1, 3)}")]
        public HttpResponseMessage Get(int id)
        {
             ……………………..
        }

Running the application

We have already implemented Basic Authentication, just try to run the application to test if it is working
Just run the application, we get,
We already have our test client added, but for new readers, just go to Manage Nuget Packages, by right clicking WebAPI project and type WebAPITestClient in searchbox in online packages,
You’ll get “A simple Test Client for ASP.NET Web API”, just add it. You’ll get a help controller in Areas-> HelpPage like shown below,
I have already provided the database scripts and data in my previous article, you can use the same.
Append “/help” in the application url, and you’ll get the test client,
GET:
POST:
PUT:
DELETE:
You can test each service by clicking on it. Once you click on the service link, you’ll be redirected to test the service page of that particular service. On that page there is a button Test API in the right bottom corner, just press that button to test your service,
Service for Get All products,
When you click on Send request, a popup will come asking Authentication required. Just cancel that popup and let request go without credentials. You’ll get a response of Unauthorized i.e. 401,
This means our authentication mechanism is working.
Just to double sure it, let’s send the request with credentials now. Just add a header too with the request. Header should be like ,
Authorization : Basic YWtoaWw6YWtoaWw=
Here “YWtoaWw6YWtoaWw=” is my Base64 encoded user name and password i.e. akhil:akhil
Click on Send and we get the response as desired,
Likewise you can test all the service endpoints.
This means our service is working with Basic Authentication.

Design discrepancy

This design when running on SSL is very good for implementing Basic Authentication. But there are few scenarios in which, along with Basic Authentication I would like to leverage authorization too and not even authorization but sessions too. When we talk about creating an enterprise application, it just does not limit to securing our endpoint with authentication only.
In this design, each time I’ll have to send user name and password with every request. Suppose I want to create such application, where authentication only occurs only once as my login is done and after successfully authenticated i.e. logging in I must be able to use other services of that application i.e. I am authorized now to use those services. Our application should be that robust that it restricts even authenticated user to use other services until he is not authorized. Yes I am talking about Token based authorization.
I’ll expose only one endpoint for authentication and that will be my login service .So client only knows about that login service that needs credentials to get logged in to system.
After client successfully logs in I’ll send a token that could be a GUID or an encrypted key by any xyz algorithm that I want when user makes request for any other services after login, should provide this token along with that request.
And to maintain sessions, our token will have an expiry too, that will last for 15 minutes, can be made configurable with the help of web.config file. After session is expired, user will be logged out, and will again have to use login service with credentials to get a new token. Seems exciting to me, let’s implement this Smile | :)

Implementing Token-based Authorization

To overcome above mentioned scenarios, let’s start developing and giving our application a shape of thick client enterprise architecture.

Set Database

Let’s start with setting up a database. When we see our already created database that we had set up in first part of the series, we have a token table. We require this token table for token persistence. Our token will persist in database with an expiry time. If you are using your own database, you can create token table as,

Set Business Services

Just navigate to BusinessServices and create one more Interface named ITokenServices for token based operations,
using BusinessEntities;

namespace BusinessServices
{
    public interface ITokenServices
    {
        #region Interface member methods.
        /// <summary>
        ///  Function to generate unique token with expiry against the provided userId.
        ///  Also add a record in database for generated token.
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        TokenEntity GenerateToken(int userId);

        /// <summary>
        /// Function to validate token againt expiry and existance in database.
        /// </summary>
        /// <param name="tokenId"></param>
        /// <returns></returns>
        bool ValidateToken(string tokenId);

        /// <summary>
        /// Method to kill the provided token id.
        /// </summary>
        /// <param name="tokenId"></param>
        bool Kill(string tokenId);

        /// <summary>
        /// Delete tokens for the specific deleted user
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        bool DeleteByUserId(int userId);
        #endregion
    }
}
We have four methods defined in this interface. Let’s create TokenServices class which implementsITokenServices and understand each method.
GenerateToken method takes userId as a parameter and generates a token, encapsulates that token in a token entity with Token expiry time and returns it to caller.
  public TokenEntity GenerateToken(int userId)
        {
            string token = Guid.NewGuid().ToString();
            DateTime issuedOn = DateTime.Now;
            DateTime expiredOn = DateTime.Now.AddSeconds(
                                              Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
            var tokendomain = new Token
                                  {
                                      UserId = userId,
                                      AuthToken = token,
                                      IssuedOn = issuedOn,
                                      ExpiresOn = expiredOn
                                  };

            _unitOfWork.TokenRepository.Insert(tokendomain);
            _unitOfWork.Save();
            var tokenModel = new TokenEntity()
                                 {
                                     UserId = userId,
                                     IssuedOn = issuedOn,
                                     ExpiresOn = expiredOn,
                                     AuthToken = token
                                 };

            return tokenModel;
        }
While generating token, it names a database entry into Token table.
ValidateToken method just validates that the token associated with the request is valid or not i.e. it exists in the database within its expiry time limit.
  public bool ValidateToken(string tokenId)
        {
            var token = _unitOfWork.TokenRepository.Get(t => t.AuthToken == tokenId && t.ExpiresOn > DateTime.Now);
            if (token != null && !(DateTime.Now > token.ExpiresOn))
            {
                token.ExpiresOn = token.ExpiresOn.AddSeconds(
                                              Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
                _unitOfWork.TokenRepository.Update(token);
                _unitOfWork.Save();
                return true;
            }
            return false;
        }
It just takes token Id supplied in the request.
Kill Token just kills the token i.e. removes the token from database.
  public bool Kill(string tokenId)
        {
            _unitOfWork.TokenRepository.Delete(x => x.AuthToken == tokenId);
            _unitOfWork.Save();
            var isNotDeleted = _unitOfWork.TokenRepository.GetMany(x => x.AuthToken == tokenId).Any();
            if (isNotDeleted) { return false; }
            return true;
        }
DeleteByUserId method deletes all token entries from the database w.r.t particular userId associated with those tokens.
public bool DeleteByUserId(int userId)
{
_unitOfWork.TokenRepository.Delete(x => x.UserId == userId);
_unitOfWork.Save();

var isNotDeleted = _unitOfWork.TokenRepository.GetMany(x => x.UserId == userId).Any();
return !isNotDeleted;
}
So with _unitOfWork and along with Constructor our class becomes,
using System;
using System.Configuration;
using System.Linq;
using BusinessEntities;
using DataModel;
using DataModel.UnitOfWork;

namespace BusinessServices
{
public class TokenServices:ITokenServices
{
#region Private member variables.
private readonly UnitOfWork _unitOfWork;
#endregion

#region Public constructor.
/// <summary>
/// Public constructor.
/// </summary>
public TokenServices(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
#endregion


#region Public member methods.

/// <summary>
///  Function to generate unique token with expiry against the provided userId.
///  Also add a record in database for generated token.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public TokenEntity GenerateToken(int userId)
{
string token = Guid.NewGuid().ToString();
DateTime issuedOn = DateTime.Now;
DateTime expiredOn = DateTime.Now.AddSeconds(
Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
var tokendomain = new Token
{
UserId = userId,
AuthToken = token,
IssuedOn = issuedOn,
ExpiresOn = expiredOn
};

_unitOfWork.TokenRepository.Insert(tokendomain);
_unitOfWork.Save();
var tokenModel = new TokenEntity()
{
UserId = userId,
IssuedOn = issuedOn,
ExpiresOn = expiredOn,
AuthToken = token
};

return tokenModel;
}

/// <summary>
/// Method to validate token against expiry and existence in database.
/// </summary>
/// <param name="tokenId"></param>
/// <returns></returns>
public bool ValidateToken(string tokenId)
{
var token = _unitOfWork.TokenRepository.Get(t => t.AuthToken == tokenId && t.ExpiresOn > DateTime.Now);
if (token != null && !(DateTime.Now > token.ExpiresOn))
{
token.ExpiresOn = token.ExpiresOn.AddSeconds(
Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
_unitOfWork.TokenRepository.Update(token);
_unitOfWork.Save();
return true;
}
return false;
}

/// <summary>
/// Method to kill the provided token id.
/// </summary>
/// <param name="tokenId">true for successful delete</param>
public bool Kill(string tokenId)
{
_unitOfWork.TokenRepository.Delete(x => x.AuthToken == tokenId);
_unitOfWork.Save();
var isNotDeleted = _unitOfWork.TokenRepository.GetMany(x => x.AuthToken == tokenId).Any();
if (isNotDeleted) { return false; }
return true;
}

/// <summary>
/// Delete tokens for the specific deleted user
/// </summary>
/// <param name="userId"></param>
/// <returns>true for successful delete</returns>
public bool DeleteByUserId(int userId)
{
_unitOfWork.TokenRepository.Delete(x => x.UserId == userId);
_unitOfWork.Save();

var isNotDeleted = _unitOfWork.TokenRepository.GetMany(x => x.UserId == userId).Any();
return !isNotDeleted;
}

#endregion
}
}

Do not forget to resolve the dependency of this Token service in DependencyResolver class.  Add  registerComponent.RegisterType();  to the SetUp method of DependencyResolver class in BusinessServices project.

  [Export(typeof(IComponent))]
    public class DependencyResolver : IComponent
    {
        public void SetUp(IRegisterComponent registerComponent)
        {
            registerComponent.RegisterType();
            registerComponent.RegisterType();
            registerComponent.RegisterType();

        }
    }
Do not forget to resolve the dependency of this Token service in DependencyResolver class. AddregisterComponent.RegisterType(); to the SetUp method ofDependencyResolver class in BusinessServices project.
  [Export(typeof(IComponent))]
    public class DependencyResolver : IComponent
    {
        public void SetUp(IRegisterComponent registerComponent)
        {
            registerComponent.RegisterType();
            registerComponent.RegisterType();
            registerComponent.RegisterType();

        }
    }

Setup WebAPI/Controller

Now since we decided, that we don’t want authentication to be applied on each and every API exposed, I’ll create a single Controller/API endpoint that takes authentication or login request and makes use of Token Service to generate token and respond client/caller with a token that persists in database with expiry details.
Add a new Controller under Controllers folder in WebAPI with a name Authenticate,

AuthenticateController

using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using AttributeRouting.Web.Http;
using BusinessServices;
using WebApi.Filters;

namespace WebApi.Controllers
{
    [ApiAuthenticationFilter]
    public class AuthenticateController : ApiController
    {
        #region Private variable.

        private readonly ITokenServices _tokenServices;

        #endregion

        #region Public Constructor

        /// <summary>
        /// Public constructor to initialize product service instance
        /// </summary>
        public AuthenticateController(ITokenServices tokenServices)
        {
            _tokenServices = tokenServices;
        }

        #endregion

       /// <summary>
       /// Authenticates user and returns token with expiry.
       /// </summary>
       /// <returns></returns>
        [POST("login")]
        [POST("authenticate")]
        [POST("get/token")]
        public HttpResponseMessage Authenticate()
        {
            if (System.Threading.Thread.CurrentPrincipal!=null && System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated)
            {
                var basicAuthenticationIdentity = System.Threading.Thread.CurrentPrincipal.Identity as BasicAuthenticationIdentity;
                if (basicAuthenticationIdentity != null)
                {
                    var userId = basicAuthenticationIdentity.UserId;
                    return GetAuthToken(userId);
                }
            }
           return null;
        }

        /// <summary>
        /// Returns auth token for the validated user.
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        private HttpResponseMessage GetAuthToken(int userId)
        {
            var token = _tokenServices.GenerateToken(userId);
            var response = Request.CreateResponse(HttpStatusCode.OK, "Authorized");
            response.Headers.Add("Token", token.AuthToken);
            response.Headers.Add("TokenExpiry", ConfigurationManager.AppSettings["AuthTokenExpiry"]);
            response.Headers.Add("Access-Control-Expose-Headers", "Token,TokenExpiry" );
            return response;
        }
    }
}
The controller is decorated with our authentication filter,
[ApiAuthenticationFilter]
public class AuthenticateController : ApiController
So, each and every request coming through this controller will have to pass through this authentication filter, that check for BasicAuthentication header and credentials.Authentication filter sets CurrentThreadprincipal to the authenticated Identity.
There is a single Authenticate method / action in this controller. You can decorate it with multiple endpoints like we discussed in fourth part of the series,
        [POST("login")]
        [POST("authenticate")]
        [POST("get/token")]
Authenticate method first checks for CurrentThreadPrincipal and if the user is authenticated or not i.e job done by authentication filter,
if (System.Threading.Thread.CurrentPrincipal!=null && 
    System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated)
When it finds that the user is authenticated, it generates an auth token with the help of TokenServices and returns user with Token and its expiry,
response.Headers.Add("Token", token.AuthToken);
response.Headers.Add("TokenExpiry", ConfigurationManager.AppSettings["AuthTokenExpiry"]);
response.Headers.Add("Access-Control-Expose-Headers", "Token,TokenExpiry" );
return response;
In our BasicAuthenticationIdentity class, I purposely used userId property so that we can make use of this property when we try to generate token, that we are doing in this controller’s Authenticate method,
var basicAuthenticationIdentity = System.Threading.Thread.CurrentPrincipal.Identity as BasicAuthenticationIdentity;
if (basicAuthenticationIdentity != null)
{
var userId = basicAuthenticationIdentity.UserId;
return GetAuthToken(userId);
}
Now when you run this application, You’ll see Authenticate api as well, just invoke this api with Baisc Authentication and User credentials, you’ll get the token with expiry,let’s do this step by step.
  1. Run the application.
  2. Click on first api link i.e. POST authenticate. You’ll get the page to test the api,
  3. Press the TestAPI button in the right corner.In the test console, provide Header information with Authorization as Basic and user credentials in Base64 format, like we did earlier. Click on Send.
  4. Now since we have provided valid credentials, we’ll get a token from the Authenticate controller, with its expiry time,
In database,
Here we get response 200, i.e. our user is authenticated and logged into system. TokenExpiry in 900 i.e. 15 minutes. Note that the time difference between IssuedOn and ExpiresOn is 15 minutes, this we did in TokenServices class method GenerateToken, you can set the time as per your need. Token is 604653d8-eb21-495c-8efd-da50ef4e56d3. Now for 15 minutes we can use this token to call our other services. But before that we should mark our other services to understand this token and respond accordingly. Keep the generated token saved so that we can use it further in calling other services that I am about to explain. So let’s setup authorization on other services.

Setup Authorization Action Filter

We already have our Authentication filter in place and we don’t want to use it for authorization purposes. So we have to create a new Action Filter for authorization. This action filter will only recognize Token coming in requests. It assumes that, requests are already authenticated through our login channel, and now user is authorized/not authorized to use other services like Products in our case, there could be n number of other services too, which can use this authorization action filter. For request to get authorized, nbow we don’t have to pass user credentials. Only token(received from Authenticate controller after successful validation) needs to be passed through request.
Add a folder named ActionFilters in WebAPI project. And add a class named AuthorizationRequiredAttribute
Deriving from ActionFilterAttribute,
Override the OnActionExecuting method of ActionFilterAttribute, this is the way we define an action filter in API project.
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using BusinessServices;

namespace WebApi.ActionFilters
{
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
private const string Token = "Token";

public override void OnActionExecuting(HttpActionContext filterContext)
{
//  Get API key provider
var provider = filterContext.ControllerContext.Configuration
.DependencyResolver.GetService(typeof(ITokenServices)) as ITokenServices;

if (filterContext.Request.Headers.Contains(Token))
{
var tokenValue = filterContext.Request.Headers.GetValues(Token).First();

// Validate Token
if (provider != null && !provider.ValidateToken(tokenValue))
{
var responseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "Invalid Request" };
filterContext.Response = responseMessage;
}
}
else
{
filterContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}

base.OnActionExecuting(filterContext);

}
}
}
The overridden method checks for “Token” attribute in the Header of every request, if token is present, it callsValidateToken method from TokenServices to check if the token exists in the database. If token is valid, our request is navigated to the actual controller and action that we requested, else you’ll get an error message saying unauthorized.

Mark Controllers with Authorization filter

We have our action filter ready. Now let’s mark our controller ProductController with this attribute. Just open Product controller class and at the top just decorate that class with this ActionFilter attribute,
    [AuthorizationRequired]
    [RoutePrefix("v1/Products/Product")]
    public class ProductController : ApiController
    {
We have marked our controller with the action filter that we created, now every request coming to the actions of this controller will have to be passed through this ActionFilter, that checks for the token in request.
You can mark other controllers as well with the same attribute, or you can do marking at action level as well. Supoose you want certain actions should be available to all users irrespective of their authorization then you can just mark only those actions which require authorization and leave other actions as they are like I explained in Step 4 of Implementing Basic Authentication.

Maintaining Session using Token

We can certainly use these tokens to maintain session as well. The tokens are issues for 900 seconds i.e. 15 minutes. Now we want that user should continue to use this token if he is using other services as well for our application. Or suppose there is a case where we only want user to finish his work on the site within 15 minutes or within his session time before he makes a new request. So while validating token in TokenServices, what I have done is, to increase the time of the token by 900 seconds whenever a valid request comes with a valid token,
        /// <summary>
        /// Method to validate token against expiry and existence in database.
        /// </summary>
        /// <param name="tokenId"></param>
        /// <returns></returns>
        public bool ValidateToken(string tokenId)
        {
            var token = _unitOfWork.TokenRepository.Get(t => t.AuthToken == tokenId && t.ExpiresOn > DateTime.Now);
            if (token != null && !(DateTime.Now > token.ExpiresOn))
            {
                token.ExpiresOn = token.ExpiresOn.AddSeconds(
                                              Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
                _unitOfWork.TokenRepository.Update(token);
                _unitOfWork.Save();
                return true;
            }
            return false;
        }
In above code for token validation, first we check if the requested token exists in the database and is not expired. We check expiry by comparing it with current date time. If it is valid token we just update the token into database with a new ExpiresOn time that is adding 900 seconds.
            if (token != null && !(DateTime.Now > token.ExpiresOn))
            {
                token.ExpiresOn = token.ExpiresOn.AddSeconds(
                                              Convert.ToDouble(ConfigurationManager.AppSettings["AuthTokenExpiry"]));
                _unitOfWork.TokenRepository.Update(token);
                _unitOfWork.Save();
By doing this we can allow end user or client to maintain session and keep using our services/application with a session timeout of 15 minutes. This approach can also be leveraged in multiple ways, like making different services with different session timeouts or many such conditions could be applied when we work on real time application using APIs.

Running the application

Our job is almost done.
We just need to run the application and test if it is working fine or not. If you have saved the token you generated earlier while testing authentication you can use same to test authorization. I am just again running the whole cycle to test application.

Test Authentication

Repeat the tests we did earlier to get Auth Token.Just invoke the Authenticate controller with valid credentials and Basic authorization header. I get,
And without providing Authorization header as basic with credentials I get,
I just saved the token that I got in first request.
Now try to call ProductController actions.

Test Authorization

Run the application to invoke Product Controller actions.Try to invoke them without providing any Token,
Invoke first service in the list,
Click send,
Here we get Unauthorized, i.e. because our ProductController is marked with authorization attribute that checks for a Token. So here our request is invalid. Now try calling this action by providing the token that we saved,
Click on Send and we get,
That means we got the response and our token was valid. Now we see our Authentication and Authorization, both functionalities are working fine. You can test Sessions by your own.
Likewise you can test all actions. You can create other controllers and test the security, and play around with different set of permutations and combinations.

Conclusion

We covered and learnt a lot. In this article I tried to explain about how we can build an API application with basic Authentication and Authorization. One can mould this concept to achieve the level of security needed. Like token generation mechanism could be customized as per one’s requirement. Two level of security could be implemented where authentication and authorization is needed for every service. One can also implement authorization on actions based on Roles.
I already stated that there is no specific way of achieving security, the more you understand the concept, the more secure system you can make. The techniques used in this article or the design implemented in this article should be leveraged well if you use it with SSL (Secure Socket Layer), running the REST apis on https. In my next article I’ll try to explain some more beautiful implementations and concepts. Till then Happy Coding Smile | :)
You can also download the complete source code with all packages from Github.

References

Read more:

Other Series

My other series of articles:

For more technical articles you can reach out to CodeTeddy.