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

Demo – WPF TDD with xUNIT

This demo is about using WPF Test driven development with xUnit framework. xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework.

xUnit.net has two different types of unit tests: facts and theories.

  • Facts are tests which are always true. They test invariant conditions.
  • Theories are tests which are only true for a particular set of data.

In the below demo, We write few failing tests, make them pass, then repeat the process. I have installed and configured below tools and packages.

  • Visual Studio 2017 Community,
  • WPF
  • TDD with xUNIT Framework
  • Autofac for dependency injection

Our solution would look like this, 4 layers


  • WPFTDDxUNIT.Model — This contains the domain entity which is being used in the project. It is a good practice to keep domain changes to a separate project so that this is not changed accidentally by other team members.
  • WPFTDDxUNIT.DataAccess — In this demo project, Data access is carrying an in-memory collection of records. All the friend’s list is loaded from this project. You can use any relational database like SQL Server or MySQL or any other to save this data.
  • WPFTDDxUNIT.UI.WPF — WPF User Interface is carrying our front end. We want to focus on separation of concerns, so we have not crammed data access and domain into this project.
  • WPFTDDxUNIT.UITests — This is what this blog post is about. We will use this project in the solution to unit tests our view models and other classes to ensure our actual code is backed by units tests. We will use xUnit TDD framework for this task.

The weird interface would look like this, :p

Before we proceed for units test, need to confirm if the below package is installed from nuget:-


Install-Package xunit.runner.visualstudio -Version 2.4.1

If you have Visual Studio Community (or Pro or Enterprise), you can run your xUnit.net tests within Visual Studio’s built-in test runner (i.e Test Explorer).

If not installed the nuget package, please Right click on the project in Solution Explorer and choose Manage NuGet Packages. Search for (and install) a package named xunit.runner.visualstudio:

Now We go to our Unit tests projects, and they can be seen at Test Explorer. Luckily all the unit tests are green.

In the below unit test, we will violate single responsibility principle and cram multiple things to be checked. Here, we use the [Fact] attribute to denote a parameterless unit test.

We can also do the assert check for .net property change events. In the below code, we see the fact is simply going to check if the RaisePropertyChangedEvent is triggered for the friend.

In order to run single test, we can use Ctrl+R, T or Click the Run All link in the Test Explorer window, to see the results update in the Test Explorer window as the tests are run:

5 considerations to save your sql database from bottleneck

We all write sql queries and fetch the data from the database. Many a times, an inefficient query may pose a bottleneck on the production database’s resources, and cause slow performance for other users if the query contains errors. Most time, we write blind queries and get all the possible data, which is not even required or to be shown to the end user on the form or GRID. In most scenarios, there are few tweaks you can do to your sql queries to optimize for better good.

  1. Indexes

Database novices often find indexes mysterious or difficult. They either index nothing or they try to index everything.

2. Less is more, so select * [STAR] carefully

A common way of retrieving the desired columns is to use the * symbol even though not all the columns are really needed. If you only need a limited number of rows you should use the LIMIT clause (or your database’s equivalent). Take a look at the following code:

SELECT name, price FROM products;

SELECT name, price FROM products LIMIT 10;

3. Say no to correlated subqueries

A correlated subquery is a subquery which depends on the outer query. It uses the data obtained from the outer query in its WHERE clause. Suppose you want to list all users who have made a donation. You could retrieve the data with the following code:

SELECT user_id, last_name FROM users WHERE EXISTS (SELECT * FROM donationuser WHERE donationuser.user_id = users.user_id);

SELECT DISTINCT users.user_id FROM users INNER JOIN donationuser ON users.user_id = donationuser.user_id;

4. Avoid Wildcards

In SQL, wildcard is provided for us with ‘%’ symbol. We should be considerate for using wildcard, which will definitely slow down your query especially for table that are really huge. We can optimize our query with wildcard by doing a postfix wildcard instead of pre or full wildcard. Below are few examples.

#Full wildcard
SELECT * FROM TABLE WHERE COLUMN LIKE ‘%hello%’;
#Postfix wildcard
SELECT * FROM TABLE WHERE COLUMN LIKE ‘hello%’;
#Prefix wildcard
SELECT * FROM TABLE WHERE COLUMN LIKE ‘%hello’;
5. COUNT VS EXIST, you decide

Some of us might use COUNT operator to determine whether a particular data exist. There are many instances where we can make use of Exists. Example below:-

SELECT COLUMN FROM TABLE WHERE COUNT(COLUMN) > 0

This is a very bad query since count will search for all record exist on the table to determine the numeric value of field ‘COLUMN’.