Real World Cloud App - From Start To Finish - The Communications Layer

In the fourth article in this series, I talked about and showed how to code the business layer for this cloud solution that included an Azure Service Bus Queue and an Azure Function. In this article, I’m going to add on top of that the communications layer, so apps and other services can get to the ad data stored in Cosmos DB.

Real World Cloud App - From Start To Finish - The Communications Layer 

Architecture Change

If you remember way back when I started writing this series of articles, my goal was to use all the latest and greatest features of Azure. Well, like most projects, I am quickly approaching a deadline to get this done before I go out of the country to present it at conferences starting in April. Since I’m only one person and I have a limited number of hours I can spend on the project before then, I need to go to my backup plan.

My intent was to use a Service Fabric application not only since it is new to the list of Azure offerings, but I really wanted to use the caching that a stateful service offers. In my conference sessions and books, I talk about how important it is to cache data on the server and client side to improve the perceived speed of the application.

After struggling with understanding how it works and the issues with it running in Azure, I decided to go back to what I know and that is to use an App Service that uses Web API. Web API has been around for a long time and is easy to create and publish to Azure.

Before I went to this backup plan, I did watch a Pluralsight course on Service Fabric a few times, read a lot on the web and even tapped some of my Azure MVP friends. Unfortunately, I couldn’t get the issues solved in a timely manner. I do hope that the Visual Studio and ASP.NET teams at Microsoft will make this process simpler in the future since I am not a DevOps expert. So, let’s get started.

Creating the App Service

Now that I have decided to use Web API, it’s time to get this service up and running as fast as possible. Here are the steps I took. In Visual Studio I added a new project to the solution and chose ASP.NET Core Web Application and pressed Ok which brings up the following screen,

Real World Cloud App - From Start To Finish - The Communications Layer 

I chose API and checked Configure for HTTPS. I don’t see any reason why HTTP wouldn’t work, but the new Microsoft guideline is to make all web traffic HTTPS. Plus, this allows me to possibly surface data that needs HTTPS in the future.

Creating the Ads Repository

To communicate with the Cosmos DB database via the dotNetTips.App.Ads.DataAccess assembly (discussed in a previous article), I added a new folder to the project called Repositories and then created a new class file called LiveAdsRepository. My intent with this repository is to return data only (no Post, Delete etc.). I will add other repositories when I need them for the Blazor app in the next article.

Since much of the heavy lifting to retrieve data has already been written in the DataAccess assembly, this repository will be simple. Below is the code,

  1. public class LiveAdsRepository  
  2. {  
  3.     private readonly string _databaseId;  
  4.     private readonly string _endpointUrl;  
  5.     private readonly string _masterKey;  
  6.   
  7.     public LiveAdsRepository(string endpointUrl, string databaseId,   
  8.                              string masterKey)  
  9.     {  
  10.         this._databaseId = databaseId;  
  11.         this._endpointUrl = endpointUrl;  
  12.         this._masterKey = masterKey;  
  13.     }  
  14.     public IEnumerable<Ad> GetLiveAds(Entities.Models.App app)  
  15.     {  
  16.         using (var context = new AdsDataContext(this._endpointUrl,  
  17.                this._databaseId, this._masterKey))  
  18.         {  
  19.             var result = context.GetLiveAds(app);  
  20.             return result;  
  21.         }  
  22.     }  
  23. }  

The GetLiveAds method will return ad data for the requested App. The default value for App is All, so all ads, that are enabled to run, will be returned which is not an issue right now since I have only defined one App so far.

Create the Ads Controller

The controller to retrieve ads that are enabled is simple too. I added a new controller class and called it AdsController. The attributes and constructor for this controller look like this,

  1. [ApiController]  
  2. [Produces("application/json")]  
  3. [Route("data/[controller]")]  
  4. public class AdsController : ControllerBase  
  5. {  
  6.     private readonly IConfiguration _config;  
  7.     public AdsController(IConfiguration config)  
  8.     {  
  9.         this._config = config;  
  10.     }  

As you can see from the code above, I am just capturing the IConfiguration object, so I can use it in the Get method. I also changed the route to be “data/[controller]” and I added the [Produces("application/json")] attribute. I then added the following Get method,

  1. [HttpGet]  
  2. [ProducesResponseType((int)HttpStatusCode.OK)]  
  3. [ProducesResponseType((int)HttpStatusCode.NoContent)]  
  4. public ActionResult<IEnumerable<Ad>> Get([FromQuery]Entities.Models.App app)  
  5. {  
  6.     var repository = new LiveAdsRepository(  
  7.                            _config.GetValue<string>("cosmosDB:EndpointUrl"),  
  8.                            _config.GetValue<string>("cosmosDB:DatabaseId"),  
  9.                            _config.GetValue<string>("cosmosDB:MasterKey"));  
  10.     var ads = repository.GetLiveAds(app);  
  11.     return ads != null ? new ActionResult<IEnumerable<Ad>>(ads) :  
  12.                        StatusCode((int)HttpStatusCode.NoContent);  
  13. }  

The Get method above takes the App value from the query string, calls the repository and returns the ads an IEnumerable<Ad> collection. If no ads were returned, then I set the http status code to NoContent. Now let’s publish it.

Publishing

Since Web API has been around for a while now, publishing is easy. To get started, simply right-click on the project and select Publish. Once on the Publish screen select New Profile, since we have not created the app service in Azure yet.

Real World Cloud App - From Start To Finish - The Communications Layer 

I set the App Name to dotNetTips-App-Ads-Api, selected my subscription and then created a new resource group and hosting plan. I also, configured Application Insights as shown above. After selecting Create, the app will be built and then published to Azure for the first time. At this point, it won’t connect to Cosmos DB, so let’s do that next.

Configuration

For now, I am just going to use application settings for the values needed to connect to Cosmos DB. Maybe in a later article, I will switch it to the Azure Key Vault. After publishing, go back to Publish and select Edit App Service Settings. I then added the configuration values using this dialog,

Real World Cloud App - From Start To Finish - The Communications Layer 

The settings I added, start with “cosmosDB”, the others were added by Visual Studio. The final publish screen looks like this,

Real World Cloud App - From Start To Finish - The Communications Layer 

Publish again, and the newly configured application settings will be published to Azure.

What I just showed you works in Azure but what about local development? Well, the configuration values I added previously are only added to the settings for the app in Azure, but they aren’t available for local development. For that, I needed to add them to the appsettings.json file as shown below,

  1. {  
  2.   "Logging": {  
  3.     "LogLevel": {  
  4.       "Default""Warning"  
  5.     }  
  6.   },  
  7.   "AllowedHosts""*",  
  8.   "cosmosDB": {  
  9.     "EndpointUrl""https://addata.documents.azure.com:443/",  
  10.     "DatabaseId""Ads",  
  11.     "MasterKey""NjpQtPF7s8zj9JAc2MrdVUqB7J18WPdCr4eRg23RJVB7Gp=="  
  12.   }  
  13. }  

Now, the app can be tested locally. I wish that when adding new configuration values, Visual Studio would also add the values to the appsettings.json file, but it doesn’t, so you will need to manually.

Testing the Service App

After publishing simply navigate to https://dotnettips-app-ads-api.azurewebsites.net/data/ads or https://localhost:44386/data/ads locally and the data will be returned as shown below,

Real World Cloud App - From Start To Finish - The Communications Layer 

Summary

If in the future I need a stateful service, then I will learn Service Fabric since it would be trivial to add what I showed you today.

Resources

  1. Source for this solution can be found here: http://bit.ly/RealWorldAppSource
  2. Utility Dev App: http://bit.ly/DevUtility. This is the app I will be connecting to this cloud app at the end of this article series. I hope you will check it out!

Next Article

In the next article, I will be coding the user experience layer using ASP.NET and Blazor, so check back here soon. Please make any comments below.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!