Azure Cosmos DB – Angular with WebAPI

This article is about using Azure Cosmos DB with Angular and WebAPI. Why Azure Cosmos DB, Any web, mobile, gaming, and IoT application that needs to manage extensive amounts of data, reads, and writes, are great of use cases.

Few differences between a document DB and a relational database:-

Document DB Relational Database
De-normalize data (Think about JSON format, key value pairs) Normalized data (Plain SQL queries)
Referential integrity NOT enforced Referential integrity FORCED through normalization and relationship
Mixed data in a collection Uniform data in tables
Flexible schema The schema is not so flexible
SQL like language as well as Javascript Pure T-SQL

More info here – https://azure.microsoft.com/en-ca/services/cosmos-db/

We will create a project – beer tracker and it will use angular, webapi and cosmosdb. We use azure cosmos db emulator to not get into configuring Azure CosmosDB which will make it post a really long one.

Download Azure CosmosDB Emulator here – https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator

This is how the final demo would look:-

Please note that in this application we are using Cosmos DB local emulator instead of real Azure Cosmos DB service. Once installed properly, it should show like below in your browser. I have installed and it is working in my chrome browser.

We will start with WebAPI, let’s create a new WebAPI project from visual studio 2017. And post that we will hook up Azure cosmosDB into webAPI and last part will be froentend UI by Angular.

In the below step, we are going to install Microsoft.Azure.DocumentDB NuGet package. DocumentDB is a true schema-free NoSQL document database service designed for modern mobile and web applications.

Install-Package Microsoft.Azure.DocumentDB -Version 2.2.3

We need to enable CORS in our Web API to allow requests from front end Angular application. For that, install Microsoft.AspNet.WebApi.Cors using NuGet

Install-Package Microsoft.AspNet.WebApi.Cors -Version 5.2.7

Lets go the the AppStart and update the WebApiConfig.cs

public static class WebApiConfig
     {
         public static void Register(HttpConfiguration config)
         {
             // Web API configuration and services       
             // Web API routes
        config.MapHttpAttributeRoutes();

        EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

We will also update the web.config of our webapi project to use cosmosDB emulator. Later on it can be changed for Azure CosmosDB keys. It will have no impact on other part of this demo.

<!--config keys for cosmos DB--&gt;
<add key="endpoint" value="https://localhost:8081" /&gt;  
<add key="authKey" value="C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" /&gt;  
<add key="database" value="AngularBeerMeetup" /&gt;  
<add key="collection" value="BeerMeetupCollection" /&gt;
<!--config keys for cosmos DB--&gt;

Now lets add the models and API controllers.

namespace BeerMeetupSolution.Models
{
using Newtonsoft.Json;
public class BeerMeetup
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "uid")]
public string UId { get; set; }
[JsonProperty(PropertyName = "location")]
public string Location { get; set; }
[JsonProperty(PropertyName = "brand")]
public string Brand { get; set; }
[JsonProperty(PropertyName = "cheers")]
public string Cheers { get; set; }
}
}

We also create a DocumentDBRepository class, just to keep here CosmosDB CRUD operations. These CRUD methods will be called by API controllers.

public static class DocumentDBRepository where T : class
     {
         private static readonly string DatabaseId = ConfigurationManager.AppSettings["database"];
         private static readonly string CollectionId = ConfigurationManager.AppSettings["collection"];
         private static DocumentClient client;
    
public static async Task<T&gt; GetItemAsync(string id)
    {
        try
        {
            Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
            return (T)(dynamic)document;
        }
        catch (DocumentClientException e)
        {
            if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                return null;
            }
            else
            {
                throw;
            }
        }
    }

    public static async Task<IEnumerable<T&gt;&gt; GetItemsAsync()
    {
        IDocumentQuery<T&gt; query = client.CreateDocumentQuery<T&gt;(
            UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
            new FeedOptions { MaxItemCount = -1 })
            .AsDocumentQuery();

        List<T&gt; results = new List<T&gt;();
        while (query.HasMoreResults)
        {
            results.AddRange(await query.ExecuteNextAsync<T&gt;());
        }

        return results;
    }

    public static async Task<IEnumerable<T&gt;&gt; GetItemsAsync(Expression<Func<T, bool&gt;&gt; predicate)
    {
        IDocumentQuery<T&gt; query = client.CreateDocumentQuery<T&gt;(
            UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
            new FeedOptions { MaxItemCount = -1 })
            .Where(predicate)
            .AsDocumentQuery();

        List<T&gt; results = new List<T&gt;();
        while (query.HasMoreResults)
        {
            results.AddRange(await query.ExecuteNextAsync<T&gt;());
        }

        return results;
    }

    public static async Task<T&gt; GetSingleItemAsync(Expression<Func<T, bool&gt;&gt; predicate)
    {
        IDocumentQuery<T&gt; query = client.CreateDocumentQuery<T&gt;(
            UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
            new FeedOptions { MaxItemCount = -1 })
            .Where(predicate)
            .AsDocumentQuery();
        List<T&gt; results = new List<T&gt;();
        results.AddRange(await query.ExecuteNextAsync<T&gt;());
        return results.SingleOrDefault();
    }

    public static async Task<Document&gt; CreateItemAsync(T item)
    {
        return await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
    }

    public static async Task<Document&gt; UpdateItemAsync(string id, T item)
    {
        return await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
    }

    public static async Task DeleteItemAsync(string id)
    {
        await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
    }

    public static void Initialize()
    {
        client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
        CreateDatabaseIfNotExistsAsync().Wait();
        CreateCollectionIfNotExistsAsync().Wait();
    }

    private static async Task CreateDatabaseIfNotExistsAsync()
    {
        try
        {
            await client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
        }
        catch (DocumentClientException e)
        {
            if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                await client.CreateDatabaseAsync(new Database { Id = DatabaseId });
            }
            else
            {
                throw;
            }
        }
    }

    private static async Task CreateCollectionIfNotExistsAsync()
    {
        try
        {
            await client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
        }
        catch (DocumentClientException e)
        {
            if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                await client.CreateDocumentCollectionAsync(
                    UriFactory.CreateDatabaseUri(DatabaseId),
                    new DocumentCollection { Id = CollectionId },
                    new RequestOptions { OfferThroughput = 1000 });
            }
            else
            {
                throw;
            }
        }
    }
}

Here is the APIs which are accessible and can be tested by Fiddlers or PostMan tool. All these methods are exposed via end points and accessible by HTTP protocols. We have also used WebAPI route prefix, and this will help angular code to resolve the url and access them.

[RoutePrefix("api/beermeetup")]
namespace BeerMeetupSolution.Controllers
 {
     [RoutePrefix("api/beermeetup")]
     public class BeerMeetupController : ApiController
     {    
    [HttpGet]
    public async Task<IEnumerable<Models.BeerMeetup&gt;&gt; GetAsync()
    {

        IEnumerable<Models.BeerMeetup&gt; value = await DocumentDBRepository<Models.BeerMeetup&gt;.GetItemsAsync();
        return value;
    }

    [HttpPost]
    public async Task<Models.BeerMeetup&gt; CreateAsync([FromBody] Models.BeerMeetup objbm)
    {
        if (ModelState.IsValid)
        {
            await DocumentDBRepository<Models.BeerMeetup&gt;.CreateItemAsync(objbm);
            return objbm;
        }
        return null;
    }
    public async Task<string&gt; Delete(string uid)
    {
        try
        {
            Models.BeerMeetup item = await DocumentDBRepository<Models.BeerMeetup&gt;.GetSingleItemAsync(d =&gt; d.UId == uid);
            if (item == null)
            {
                return "Failed";
            }
            await DocumentDBRepository<Models.BeerMeetup&gt;.DeleteItemAsync(item.Id);
            return "Success";
        }
        catch (Exception ex)
        {
            return ex.ToString();
        }
    }
    public async Task<Models.BeerMeetup&gt; Put(string uid, [FromBody] Models.BeerMeetup o)
    {
        try
        {
            if (ModelState.IsValid)
            {
                Models.BeerMeetup item = await DocumentDBRepository<Models.BeerMeetup&gt;.GetSingleItemAsync(d =&gt; d.UId == uid);
                if (item == null)
                {
                    return null;
                }
                o.Id = item.Id;
                await DocumentDBRepository<Models.BeerMeetup&gt;.UpdateItemAsync(item.Id, o);
                return o;
            }
            return null; ;
        }
        catch (Exception ex)
        {
            return null;
        }

    }
}
}

Now we will switch to our front end. The Angular part. Ensure you have install NPM and its configured in your system.

Type into the black command prompt

ng new AngularUI 

It will take some time for Angular CLI to create a new project and once it completes we will switch to Visual Studio Code.

The boiler plate generated by AngularCLI would be ready, and we will start to build our frontend code.

Adding model for BeerMeetup,

export class BeerMeetup {  
uid: string;
location: string;
brand: string;
cheers: string;
}

After model, we add service which will have crud methods.

  
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { BeerMeetup } from './beermeetup';

const api = 'http://localhost:53090//api';

@Injectable()
export class BeerMeetupService {
constructor(private http: HttpClient) { }

getBM() {
return this.http.get<Array<BeerMeetup>>(`${api}/beermeetup`);
}

deleteBM(beermeetup: BeerMeetup) {
return this.http.delete(`${api}/beermeetup?uid=${beermeetup.uid}`);
}

addBM(beermeetup: BeerMeetup) {
return this.http.post<BeerMeetup>(`${api}/beermeetup/`, beermeetup);
}

updateBM(beermeetup: BeerMeetup) {
return this.http.put<BeerMeetup>(`${api}/beermeetup?uid=${beermeetup.uid}`, beermeetup);
}
}

Lastly, we will add the component

  
import { Component, OnInit } from '@angular/core';

import { BeerMeetup } from './beermeetup';
import { BeerMeetupService } from './beermeetup.service';

@Component({
selector: 'app-ohs',
templateUrl: './beermeetup.component.html'
})
export class BeerMeetupComponent implements OnInit {
addingBM = false;
deleteButtonSelected = false;
heroes: any = [];
selectedBM: BeerMeetup;

constructor(private beermeetupService: BeerMeetupService) { }

ngOnInit() {
this.getBM();
}

cancel() {
this.addingBM = false;
this.selectedBM = null;
}

deleteBM(hero: BeerMeetup) {
this.deleteButtonSelected = true;
let value: boolean;
value = confirm("Are you sure want to delete this meetup?");
if (value != true) {
return;
}
this.beermeetupService.deleteBM(oh).subscribe(res => {
this.ohs= this.heroes.filter(h => h !== oh);
if (this.selectedBM === oh) {
this.selectedBM = null;
}
});
}

getBM() {
return this.beermeetupService.getBM().subscribe(ohs=> {
this.ohs= ohs;
});
}

enableAddMode() {
this.addingBM = true;
this.selectedBM = new BeerMeetup();
}

onSelect(hero: BeerMeetup) {
if (this.deleteButtonSelected == false) {
this.addingBM = false;
this.selectedBM = oh;
}
this.deleteButtonSelected = false;
}

save() {
if (this.addingBM) {
this.beermeetupService.addBM(this.selectedBM).subscribe(
obj => {
this.addingBM = false;
this.selectedBM = null;
this.ohs.push(oh);
});
} else {
this.beermeetupService.updateBM(this.selectedBM).subscribe(obj=> {
this.addingBM = false;
this.selectedBM = null;
});
}
}
}

Once this is done, lets switch over to app.module.ts, we will ensure our modules are registered here.

  
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { BeerMeetupService } from './beermeetup.service';
import { BeerMeetupComponent } from './beermeetup.component';
@NgModule({
declarations: [
AppComponent,
BeerMeetupComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
providers: [BeerMeetupService],
bootstrap: [AppComponent]
})
export class AppModule { }



Now we will move to Visual Studio Code, Terminal and fire

ng serve -o
Advertisements

JWT Authentication for WebAPI

This post is about securing web api using JWT token based authentication. JWT stands for JSON Web Tokens. JSON Web Tokens are an open, industry standard method for representing claims securely between two parties. In token based authentication, the user sends a username and password, and in exchange gets a token that can be used to authenticate requests.

A JWT token look like:

Header.Payload.Signature

HEADER PAYLOAD SIGNATURE
AAAAAAAAAAAAA. BBBBBBBBBBBBBBBBB. CCCCCCCCCCCCC
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>

.NET has build in support for JWT tokens in the below namespace.

using System.IdentityModel.Tokens.Jwt;

JWT token has three sections:

  • Header: JSON format which is encoded as a base64
  • Claims: JSON format which is encoded as a base64.
  • Signature: Created and signed based on Header and Claims which is encoded as a base64.

In the below project, we will see how the JWT token authentication has been implemented.

Step 1 – A browser client is going to send a http request with username and password. This is going to be validated using WebAPI filter attribute.

AuthorizationFilterAttribute

Step 2 – Server validates the username and password and completes a handshake. Post handshake, the server generates the token and send it to the client.

The below code is going to generate the token for the user(client)


We need to add below two nuget packages from Nuget Package manager,

Install-Package Microsoft.IdentityModel.Tokens -Version 5.4.0   
Install-Package System.IdentityModel.Tokens.Jwt -Version 5.4.0

Step 3 — Check for token validation

We used System.IdentityModel.Tokens.Jwt library for generating and validating tokens. To implement JWT in Web API, we created a filter for authentication which will be executed before every request. It will verify the token contained in the request header and will deny/allow resource based on token.

Using Unity DI with Angular + WebAPI

Unity is a Dependency Injection container. Our objective usage of Unity framework is to inject the dependencies to the dependent object. 

The Dependency Injection pattern is an implementation of Inversion of Control. IoC means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source.

The advantages of using Dependency Injection pattern and Inversion of Control are the following:

  • Reduces class coupling
  • Increases code reusing
  • Improves code maintainability
  • Improves application testing

Unity has an excellent documentation and support for Unity WebAPI. Unity DI is open sourced, more info here at https://github.com/unitycontainer/unity

For this demo, we have a multilayered project, whose solution looks like below

Our first step is to add Unity.WebApi to TrackerFrontEnd is via the NuGet package. You can search for unity.webapi using the GUI or type the following into the package manager console.

Install-Package Unity
install-package Unity.WebApi

Once we have installed Unity on our main project, our reference would have added required Unity packages.

Second step is to go to, web application startup.cs file and register components using unity.

Hooking them up.
Once installed the NuGet package, we need to hook it up in order to get the framework to start resolving components via Unity. The old school way, involved calling Bootstrapper.Initialise(). For the new packages, we just change this line to UnityConfig.RegisterComponents(). Once UnityConfig has registered components, it is easy for us to start registering our interfaces types with actual implementations.

Now, post hooking up Unity DI, we can inject dependencies into any controller. I prefer using constructor injection.