Create an Angular todo list with azure static web apps Part 4

In this series about Azure static web apps, we created an Angular Todo list app, an Azure function using JavaScript and linked both together. If you want to have a look at the previous parts, here are the links

In this post, we will store the todos in Cosmos DB and read it from our Azure function.

Create Cosmos DB

Azure Cosmos DB gives you a free account with upto 400 RU/s. You can use it for this demo. Go to Azure Portal, Click New Resource -> Under Databases select Azure Cosmos DB, choose the API as SQL API and add the account name, resource group and region and leave everything else with the default value then click Review + Create then Create.

Once the Azure Cosmos DB account is created, open it and go to Data Explorer and from the toolbar click New Database and give it a name

Once the database is created, click the three dots near the database name and click New Container. Provide a name for the container and type /id as the partition key then click ok

From the left menu click Keys and copy the PRIMARY CONNECTION STRING.

Azure Function Settings

To connect to the Azure Cosmos DB, we we will need to store the connection string somewhere. For this purpose, we will use the file local.settings.json under api folder.

Add a new key under the values key and name it CosmosConnectionString and paste the Cosmos DB connection string copied earlier.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CosmosConnectionString":""
  },"Host": {
    "CORS": "*"
  }
}

The local.settings.json file is not added to Git and should not be. This should include the connection strings and any secrets used locally.

Connect to Cosmos from the APIs

We have the database ready now and the connection string is set in our api. To read data from Cosmos, we need to install the package @azure/cosmos. Open command prompt and navigate to the api folder that has the function project and run the following command

npm i @azure/cosmos

Now open the index.js file inside the api/GetTodoList folder and paste the following code

const CosmosClient = require('@azure/cosmos').CosmosClient;

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    let cosmosClient = new CosmosClient(process.env['CosmosConnectionString']);
    let database = cosmosClient.database('todos');
    let container = database.container('todolist');
    let {resources} = (await container.items.query('SELECT c.id,c.title,c.isCompleted FROM c').fetchAll());

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: resources
    };
}

The code is straight forward, in line 1, we imported the CosmosClient class which will be used to connect to Cosmos DB. This is like an EntityFramework DBContext. Line 5,6, and 7 we create a client instance, use it to get a reference to the database and the container that has our data.

In line 8, we query the container to return only the id, title and isCompleted fields and return the results.

You can see that the field names are now pascal named (title instead of Title), you will have to update the binding in the TodoList component

 <td><input type="checkbox" [checked]="todo.isCompleted" disabled></td>

Test

Run your api project with func start and your Angular app with ng serve. You should see an empty list. Go back to your Cosmos DB instance in Azure Portal, click Data Explorer, select the db then the container and choose Items. You can add a new item by clicking the New Item button on the toolbar and then click Save. Repeat the process to add few items

Now try to refresh your app and you should see the data displayed in the Angular app

Deployment

Commit and push your changes and wait for the workflow action to finish. If you tried your site now it will not work as the function has no idea about the connection string. To add a new connection string, open your Azure Static Web App, click on Configuration and then click Add. Type CosmosConnectionString as the name and paste the connection string for the Cosmos DB in the value field. Save and refresh your app and now you should see the application displaying the data you saved in Cosmos DB

Source code: https://github.com/haitham-shaddad/ng-todo-list-az-static-webapp

Create an Angular todo list with azure static web apps Part 3

In part one of the serious, we created the SPA with Angular, deployed it to Azure Static Web Apps. In Part 2, we created the API part. In this post, we will link the both the Frontend with the Backend.

Create the Listing Component

Open CMD and navigate to the folder that has your angular app then run the command ng g c TodoList. This will generate an Angular component with the name TodoListComponent. Open the code for this component and put the following code.

<h1>Your Todos</h1>
<table>
    <thead> 
        <tr>
            <th>Todo</th>
            <th>Complete</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let todo of todos">
            <td>{{todo.Title}}</td>
            <td><input type="checkbox" checked="{{todo.Complete}}" readonly></td>
        </tr>
    </tbody>
</table>
import { TodoService } from './../todo.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.component.html',
  styleUrls: ['./todo-list.component.scss'],
})
export class TodoListComponent implements OnInit {
  todos: any;
  constructor(private todoService: TodoService) {}

  ngOnInit(): void {
    this.todoService.getTodoList().then((response) => response.json()).then(data =>{
       this.todos = data;
       console.log(data);
    });
  }
}

table{
    width:100%;
    border: 1px;
}

table tr th{
    background-color: lightslategray;
}

table tr td{
    text-align: center;
}

The first part is the HTML and the second is the component code and the third is the CSS.

Create the Todo Service

To communicate with the API, we will create an Angular service. Navigate to the app folder under the src directory and run the command ng g s Todo. This will create a new service with the name TodoService. The code should look like this

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class TodoService {



 getTodoList() {
    return fetch('api/GetTodoList');
  }
}

The getTodoList function calls the fetch method to make an Ajax request to the API. Notice the URL is just api/GetTodoList because our Angular app and the API runs in the same domain and the paths will be relative. If you are running it locally, the path would be prefixed with the correct URL. Ex:  return fetch('http://localhost:7071/api/GetTodoList');

Routing

Nowe we need to make the default route redirects to the TodoComponent. Open the app\app-routing.module.ts and change it as below:

import { SaveToDoComponent } from './save-to-do/save-to-do.component';
import { TodoListComponent } from './todo-list/todo-list.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
    component: TodoListComponent,
    path: '',
  },
  {
    component: TodoListComponent,
    path: 'todolist',
  },
  {
    component: SaveToDoComponent,
    path: 'new',
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Open the app.component.html and remove all the code after the style and only leave the <router-outlet></router-outlet>.

Testing our changes

Now commit and push the changes and wait for the GitHub action to run. Once deployment is completed, try your site and it should look like this:

Now you have a fully functioning SPA running in Azure Static Web App. In the next articles, we will refine it more to connect to a storage backend and do more authentication.

You can try the source code yourself at https://github.com/haitham-shaddad/ng-todo-list-az-static-webapp

Create an Angular todo list with azure static web apps Part 2

In the previous post , we created the first part of our todo list that will be deployed to Azure Static Web App service. In this post, we will add the backend as an Azure Function

List ToDos Azure Function

Create a new folder with the name api then make sure you have Azure Functions extension install in VS code. Press F1, this will show the command window in vs code, type functions and select Azure Functions: Create New Project, choose api\GetTodoList as the folder for the Azure Function, choose JavaScript as the language (As per today, Static Web Apps only support JavaScript functions), HttpTriger as the trigger and GetTodoList as the function name and finally Anonymous as the authentication method. This will create all the files needed for you function.

Get Todos implementation

Now, let’s put a dummy implementation for the GetToDos function.

Edit the index.js file with the following code. This will return 4 Todos. The implementation can be changed later to connect to any other data source

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    const responseMessage =  [
         { Title : "Read Microfronts book", IsCompleted : false},
         { Title : "Post a blog about Project Tye", IsCompleted : false},
         { Title : "Get some exercises", IsCompleted : true},
         { Title : "Do more stuff", IsCompleted : false},
    ];

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: responseMessage
    };
}

Go to your Az Functions Tools and run the function, it should show the funcion URL in the console window

Hit http://localhost:7071/api/GetTodoList in your browser and you should be able to see the results in JSON

You can follow the same steps to create another function to add and edit Todo.

Deploy the API to Azure Static Web App

Commit and push the changes to your GitHub Repo and watch GitHub actions building and packaging the application. All the code in the repo will be built and packaged including the Azure Function.

Validating deployment

Once the GitHub action finishes and show a success mark, open Azure Portal and go to your Azure Static Web App then click Functions on the left menu. You should be able to see the GetTodoList function there.

Function Configuration

Once you have the function deployed, you can add configuration keys under Configuration section. One of the configuration is APPINSIGHTS_INSTRUMENTATIONKEY that can be used to link your static web app to an application insights instance which will recive all the logs made by your function using the context.log function.

Testing your API

Its time to make sure everything works fine. Click the overview tab then click on the URL for the site, it should open the static site web created in previous post. To access the API, you have to append api/FUNCTION_NAME. in our case, it will be URL/api/GetTodoList

Inspect function behavior with application insights

Since our function is now working fine, a bonus point would be to check the logs generated from it. After you create an application insights instance and add a configuration key APPINSIGHTS_INSTRUMENTATIONKEY with the app insights instrumention key, invoke the function few times then go to your app insights instance and click Search from the left menu. You should be able to see the logs

As you can see above, not only you can see the messages logged from the function but also from the azure functions runtime.

In next post, we will link the SPA to our APIs and do more fancy stuff.

The source code can be found on my GitHub repository. All you need to do is to fork it, create a new static web app and link it to the repo. https://github.com/haitham-shaddad/ng-todo-list-az-static-webapp

Create an Angular todo list with azure static web apps Part 1

In this post, I will create a To Do List app using Angular and we will host it on the newly introduced Azure service called Static Web Apps.

Project Setup

Azure static web app is connected to GitHub repo, and the first thing to do is to create a new repo under your github account. Once you create it, clone it to your local machine and run the following commands. Make sure you have angular-cli tools installed

ng new AzTodoList

Choose yes for routing and select your preferred css processor and hit enter to create the project and install all needed packages. Once all packages are installed, run ng serve to make sure the app works fine. You should have something like this running on port 4200

Make sure all files exist in the root folder where you cloned the GitHub repo. If you cloned the repo in a folder called ToDoList and then ran the command ng new inside it, it will create another subfolder. If this happened, make sure to move the files in the inner folder to the ToDoList folder. Otherwise, the GitHub action won’t work since it will fail to determine the programing language used. Your folder structure should look like this:

Now commit the source code with git add . to add all files followed by git commit -m "Initial commit" and finally git push origin master to push the files to GitHub.

Create Azure Static Web App

Open Azure portal and create a new static web app, log in to your GitHub account and choose the ToDoList app

Click on Next: Build to move to the next screen and configure it as below. The artifact location is dist/AzTodoList but it can be different in your case depending on your angular project name. You can get the exact path from your angular.json file or run ng build and check your folder structure.

When you create the app, it will automatically created the necessary CI/CD on GitHub using GitHub Actions and you can view that by clicking on the link “Thank you for using Azure Static Web App! We have not received any content for your site yet. Click here to check the status of your GitHub Action runs.” . You can view the build status by going to your GitHub repo and click Actions

As you can see above, it failed few times because I put the Angular app in a folder inside the repo. Once I moved all the files from within the inner folder to the root folder, it worked.

Test the app

Now go back to your Azure Portal and in the overview tab for the static web app, click Browse and this is what you should see

In the next post, we will add the APIs that will be used to retrieve, add and delete ToDos

Source code: https://github.com/haitham-shaddad/ng-todo-list-az-static-webapp

Configure preview features with Azure App Configuration

In my preview post about implementing preview features in asp.net core, I explained how to introduce the concept of feature flags in your application and manage it with the default appsettings.json.

Managing your features from appsettings is not the best approach as it requires application restarts which will distrupt the application users.

In this post, I will explain how to do the configuration with a tool that was built just for this.

Azure App Configuration has feature management feature that allows you to manage your features, turn it on or off and set the filters for each feature flag. It also enables auto refresh which basically allows you to change a feature and this change will reflect immediately in your application.

Register Azure App Configuration as a Configuration Source

Asp.net core supports multiple configuration sources. When you call the CreateDefaultBuilder method in Program.cs, it automatically registers the following configuration sources for your application

appsettings.json
appsettings.{environment}.json
user secrets
environment variables
command line arguments

The registration happens in the same order above. You can have a look at the source code in this link If a specific key exists in a configuration source, you can override its value by adding it in the next configuration source. Ex: If the key ConnectionStrings:DefaultConnection exist in appsettins.json and also exist in user secrets, the one in user secrets will be used. This is good to override some values in your local dev environment such as passwords and connection strings to avoid pushing it to your source control

To register azure app config as an additional config source, you can add the following in Program.cs after installing the package Microsoft.Azure.AppConfiguration.AspNetCore

            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration(config =>
                {
                    var configuration = config.Build();
                    config.AddAzureAppConfiguration(azureAppConfig =>
                    {
                        var azureAppConfigConnectionString = configuration["AzureAppConfig:ConnectionString"];
                        azureAppConfig.ConfigureRefresh(refresh =>
                        {
                            refresh.SetCacheExpiration(TimeSpan.FromSeconds(5));
                        });
                        azureAppConfig.UseFeatureFlags();
                        azureAppConfig.Connect(azureAppConfigConnectionString);
                    });
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

From line 2-15, you can see that we are configuration the application configuration by adding a new configuration source in line 5. In line 7, we are reading the connection string from the previous configuration sources. This way you can add your connection string in appsettings.json or user secrets, I have added it here in appsettings.json under the name AzureAppConfig:ConnectionString. From line 8-11, we are configuring the caching time for the configuration. If you configure it for 5 seconds, the keys from azure app config will be cached and no requests will be done to azure app config to get the latest updates. Line 12 simply asks Azure App Configuration SDK to include the features when it reads all configurations and finally we use the connection string to connect to the azure config instance.

Creating Azure App Config

Log in to Azure Portal and create a new App Configuration resource. You can only create one free app configuration per subscription. Once it is created, go to Access Keys from the left menu and copy either the primary or secondary connection string and update your appsettings file

Now you should be all set. If you run the application and navigate to https://localhost:44375/PreviewFeatures, you should be able to see the page if your feature configuration allows it.

So far, we didn’t add any features to our Azure App Config instance yet, this means the application will fall back to the appsettings.json

Add Features in Azure App Configuration

To start managing your features from Azure App Config, Click Feature Manager from the left menu and Choose Add then type the feature name as PreviewFeatures and choose Off then click add

Now refresh the URL https://localhost:44375/PreviewFeatures, and if the feature PreviewFeatures was enabled in appsettings, it will still appear. So what are we doing wrong?

Enable Auto Refresh

By default, the Azure App Configuration does not do auto refresh in your asp.net core. You have to register a middleware that does that by adding the following line in the Configure method inside Startup.cs

app.UseAzureAppConfiguration();

Now, if you run the application again, the first time it starts, it will get the most recent values from Azure App Config and now you should see the PreviewFeatures controller not working. But if you enabled it again from azure portal by toggling the On/Off flag from the Feature Manager page, and wait for 5 seconds, you should refresh and see that the PreviewFeatures is now working again.

Notice that the toggle turns on or off the feature for everyone. If you need to use the feature filter, then click the 3 dots and choose Edit. Under Filters, click add and type the feature filter name, in this case UserFeatures which we created previously. Notice how the state changed from On/Off to Conditional. Now when you refresh, the filter will be executed to decide if the feature should be enabled or disabled for each user.

I have included all the updates on GitHub repo. Feel free to ask me any questions

Log to Azure Table Storage in asp.net core to

Asp.net core has abstracted the logging operations into the ILogger interface and instead of having too many frameworks for logging, you just need to add a logging provider such as Console, SeriLog, Windows Event Viewer. In this post, I will create a custom logging provider that logs to Azure table storage

Why Azure Table Storage?

Azure table storage can store petebytes of semi-structured data with high performance inserts and updates. It is also cheap which makes it very suitable for storing log messages. It also allow us to connect to the log messages from many tools such as Azure Storage explorer unlike the case when you log messages to the file system on an Azure App Service

Structure of a custom logger

Logger

This is where the actual code for logging will exist and it must implement the ILogger

public class AzureTableLogger : ILogger
{
Microsoft.WindowsAzure.Storage.Table.CloudTable loggingTable;

    public AzureTableLogger(string connectionString, string tableName)
    {
        var storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(connectionString);
        var cloudTableClient = storageAccount.CreateCloudTableClient();
        loggingTable = cloudTableClient.GetTableReference(tableName);
        loggingTable.CreateIfNotExistsAsync();
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        var log = new LogEntity
        {
            EventId = eventId.ToString(),
            LogLevel = logLevel.ToString(),
            Message = formatter(state, exception),//exception?.ToString(),
            PartitionKey = DateTime.Now.ToString("yyyyMMdd"),
            RowKey = Guid.NewGuid().ToString()
        };

        var insertOp = TableOperation.Insert(log);
        loggingTable.ExecuteAsync(insertOp).GetAwaiter().GetResult();
    }
}

public class LogEntity : Microsoft.WindowsAzure.Storage.Table.TableEntity
{
    public string LogLevel { get; set; }
    public string EventId { get; set; }
    public string Message { get; set; }
}

As you can see, we just use the Azure Table Storage SDK to connect to the storage account and create a cloud table client. The logger accepts the table name and connection string as a constructor parameter which will be injected using the LoggingProvider. This is the minimum version of a logger and it needs a lot of improvement but it is good as a start.

LoggingProvider

public class AzureTableLoggerProvider : ILoggerProvider
{
    private readonly string connectionStringName;
    private readonly string tableName;

    public AzureTableLoggerProvider(string connectionString, string tableName)
    {
        connectionStringName = connectionString;
        this.tableName = tableName;
    }
    public ILogger CreateLogger(string categoryName)
    {
        return new AzureTableLogger(connectionStringName, tableName);
    }

    public void Dispose()
    {

    }
}

In this provider, we just use the two parameters passed in the constructor to create a new logger instance

LoggingProviderExtension

 public static class AzureTableLoggerExtensions
    {
        public static ILoggerFactory AddTableStorage(this ILoggerFactory loggerFactory, string tableName, string connectionString)
        {
            loggerFactory.AddProvider(new AzureTableLoggerProvider(connectionString, tableName));
            return loggerFactory;
        }
    }

This last block is not a must but its for the sake of clean code and clarity. In this step, we just inject our logging provider into the ILoggerFactory. When the application starts, we will have to call the AddTableStorage method to be able to use the new logger.

Add the provider in startup.cs

   public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            loggerFactory.AddTableStorage("LoggingSample", "UseDevelopmentStorage=true");
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
    }

Now, our application is ready to log messages to Azure Table Storage. The sample above is using local storage emulator and will create a table named LoggingSample. Lets create a controller and log some messages

    [ApiController]
    [Route("[controller]")]
    public class CustomersController : Controller
    {
        private ILogger<CustomersController> logger;

        public CustomersController(ILogger<CustomersController> logger)
        {
            this.logger = logger;
        }

        public IActionResult Index()
        {
            logger.LogInformation("This is a message from customers controller");
            return Ok();
        }
    }

In the Index action, we called the logger to add a test message. Notice that you don’t have to specify anything other than the ILogger. Asp.net core DI will inject the proper logger at runtime.

Notice the new columns added to the table such as EventId and LogLevel. These are properties in the LogEntity classes added in the first code snippet. Notice also that it logs all messages logged by the asp.net infrastructure not just the test message that we added

Next steps

Our next step would be adding a middleware that will show a nice UI that will display log messages. This can come handy when you want to debug something and need to see the error messages

Migrate your asp.net settings to Azure App Configuration

Before asp.net core, we only had the web.config file to configure and read the application settings from code. The framework didn’t have a plugable way of adding an extra configuration providers. Any other confiruation data sources meant a custom solution and custom code to read and update configuration keys.

With asp.net core, we got the new appsettings.json as one source of configuration. Along with it came the environment variables, other files, secret keys that can be used to omit connection strings and passwords from being stored on source control.

Things event got better with Azure App Service that has a settings/configuration section that can override the application settings and connection strings sections. This applies to both asp.net framework and asp.net core.

Isn’t this enough already?

It is good as a start. but, it has a major issue. If you change any value in your configuration keys, it means the application must be restarted which affects the logged in users and may cause data loss.
Another issue is that our application code and configuration exists in the same place which contradicts with the twelve factor . These configuration keys cannot also be shared with other applications except using copy/paste

Azure App Configuration

Azure App Configuration is a service that is still in preview that can be a central place for all your configuration keys and feature flags.
It is so easy to add it to your asp.net core configuration provider using the provided nuget packages.

Add the need packages

First, install the package Microsoft.Azure.AppConfiguration.AspNetCore . You may need to check that you enabled prerelease versions if you are using visual studio

In your Program.cs file, add the following code which will inject Azure app configuration as a configuration provider. Notice that you will have to add a key named “AppConfig” in your connectionStrings section in appsettings.json that will store the connection string for your Azure App Configuration

public static IWebHostBuilder CreateWebHostBuilder(string&#091;] args) =>
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            var settings = config.Build();
            config.AddAzureAppConfiguration(settings&#091;"ConnectionStrings:AppConfig"]);
        })
        .UseStartup<Startup>();

Now, your application is ready to read any configuration keys from Azure App Configuration. All you need to do is to create a new instance by following this link

Reuse your existing configuration keys

It’s not only too easy to add Azure App Configuration to your asp.net core app but also migrating your existing keys. You don’t want to end up with a situation where you have to spend hours moving your keys manually or writing scripts to do it. Azure App Configuration can do that for you.

As you can see above, it is too simple. Just choose Import/export from the left menu then choose where you want App Configuration to import the values from:

  1. App Configuration: you can import the values from another Azure App Configuration instance
  2. App Service: which can be perfect in our case since it will import the values from your Azure App Service
  3. Configuration File: you can pass the appsettings.json directly and it will import the values from there

Once you did that, you will have all keys/connection strings imported and ready to go.

Conclusion

Azure App Configuration is a great service that still in preview but it enables you to offload your application from configuration keys and connection strings. It also has the auto refresh which will allow your app to always have the latest config keys without the need to restart your application and impact your users.
It also has feature management which is a great addition but we will talk about it in future posts.

Understanding Azure Bot State

When you chat with a bot built with Azure Bot Service, you will have to maintain user state. Example, the options that the user chose last time, or the usernames of all users in a conversation.

Conversation State Types

Azure Bot Service has 3 different states:

User State
This state is related to the user on a specific channel regardless how many conversation they have. So, if the user is chatting with a bot from Facebook channel and connected to the same bot in another conversation , any values saved in user state will be visible in both chats. This is useful in scenarios where you want to save an info about the user like the username or preference that will be used in all conversation for this user.

Conversation State
This state is scoped to the conversation only but not to each user. If you have 3 users chatting with the bot, any data saved in conversation state will be shared across all users. This is used in cases where the data saved is not related to a specific user such as statistics. If the user connected to another session with the bot, the info saved her will not be visible in the other conversation

Private Conversation State
Here, the framework manages the state for each user in each conversation. Imagine a scenario where the user is submitting a ticket. You want the ticket info to be scoped to this conversation only because they may be submitting another ticket with another conversation.

The state storage saves each data in a key/value store. The keys used for each state type is as below:

  • User Sate: {Activity.ChannelId}/users/{Activity.From.Id}#YourPropertyName
  • Conversation state: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}#YourPropertyName
  • Private conversation: {Activity.ChannelId}/conversations/{Activity.Conversation.Id}/users/{Activity.From.Id}#YourPropertyName

Conversation Storage

By default, the state variables are stored in memory. But you can change that from the startup.cs. In the example below, I have configured it to use Azure Table storage to store the state, this makes it persistent. You can create your own state by inheriting from IStorage

Next, you configure which state types you want to use, in this example, I use the conversation state. To use the user state, you have to create an instance of UserState and add it as a singleton just like conversation state.

public void ConfigureServices(IServiceCollection services)
        {
          //IStorage dataStore = new MemoryStorage(); 
          IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage("connection string", storageContainer);

          var conversationState = new ConversationState(dataStore);
            services.AddSingleton(conversationState);
        }

State property accessors

https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/bot-builder-state.png?view=azure-bot-service-4.0

Now, its time to use the state in our bot. To do that, you have to use a property accessor which allows you to read and update data to the state storage. Note that calling the GetAsync and SetAsync on the state accessor doesn’t actually save the state data in the storage system. You have to call the SaveChangesAsync as you can see from the sequence diagram above.

To understand more about state property accessors and how to use it to read and update data into bot state, go through this link

Azure Bot Service Overview

Today, I started learning Azure BOT Service, I will summarise each section into a blog post.

What is BOT?

A BOT is a modern way of user interaction. Instead of user clicking buttons and typing data in text fields, the user will be chatting or talking to an application that will understand the human language and respond accordingly.
This of course increase the human interaction with your site or application and also decrease the need for employees to handle user requests.
Imagine a user who wants to know about car insurance quote, instead of calling the insurance company, they can chat with the bot or even call it and ask them about the prices and the bot can respond as if it was a human or delegate the call to a human if it is not able to assist. This can save a lot for the company.

How BOT works?

Users interact with the BOT through a channel. A channel can be DirectLine like the case when you chat directly with the BOT from web site. It can be Facebook Messenger, Twitter, or any other popular social media platform.
The chat between users and BOT can be a text messages, a card that display graphic content to the user or a voice message or even an interactive form that ask the user to enter some information like SSN or Policy Number.
BOT can also use AI services such as Azure Congnitive Services to make it smarter.

https://haithamshaddad.files.wordpress.com/2019/02/84064-1xmuakcv_xkoszd4odvrika.png

BOT HTTP Communication

The communication between the BOT and Users/Channels take place through HTTP Post requests. When a user joins a conversation, an HTTP message is posted to the BOT service and the BOT just acknowledge the message with 200 OK response. Then, the BOT joins the conversation and again another HTTP Post message is sent to the channel and the channel replies back with a 200 Ok. These messages are called ConversationUpdate messages.
All these messages between the BOT and the channel are called activities. During the ConversationUpdate activity, you can check the members added or removed.
Once the connection is established, the messages send from the channel to the BOT are sent as an HTTP Post requests and the BOT replies back with a different HTTP Post not via response to the original HTTP Post request. So, as you can see from the image below, the Channel sent a Hi message, the BOT just echoed the message but it can send a different message. Then, the channel confirmed with a 200 Ok to the BOT and finally the BOT replies back to the original hi message with 200 Ok.
With the current version (4) it may not be very clear about the HTTP post messages but if you tried with the older version (3), it was very clear and when you create a new project you can clearly see an API controller called MessagesController and you can access it via /api/messages.

activity diagram
https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/bot-builder-activity.png

Defining Rounds

Humans talk one at a time, one talk and the others listen (At least this is what should happen 🙂 ).

activity processing stack
https://docs.microsoft.com/en-us/azure/bot-service/v4sdk/media/bot-builder-activity-processing-stack.png

The important thing to note in the above image is the TurnContext
which holds information about whose turn and what data was sent (Typically JSON) and the middleware which holds some components that execute in order to do something with the activity received. After all middleware components finish execution, it passes the control to the Turn Handler which will execute the application logic that will decide the response that will be sent to the channel/user.
The middleware is executed on the incoming activity received from the channel and also on the outbound activity sent from the bot to the channel itself.

Azure Functions anatomy – Part 2 – What is inside a Function App?

In the previous post (Azure Functions 2.0 Anatomy- Part 1), we saw the structure of a function app. In this part, I will explain the different components of an Azure Function.

Components

Every Azure Function 2.0 consists of the following components:

  • Trigger
  • Bindings (one of which is the trigger). Binding can be input or output
  • Value Converter/Binder
  • Listener

A binding can be a Blob file, a queue message, an event from event hub or event grid or any custom binding developed by anyone. One of these bindings can initiate the function call and in this case it is called a Trigger.
A binding can also be Input or Output. Input binding delivers data to the function and output binding is used by the function to write data.

Now, assume we have the following function and its configuration

        [FunctionName("SampleFunction")]
        public static void Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")]string myQueueItem, [Blob("sample-output")]Stream output, TraceWriter log)
        {
            log.Info($"C# Queue trigger function processed: {myQueueItem}");
        }

This function has 2 binding parameters. myQueueItem which is both an input binding and a trigger, and output which is an output binding.

How Azure Functions call this method and convert the queue message to a string and the stream to a Blob file?

Binding, Listener, Value Provider and Converter

When the azure function app starts, it scans all functions that exist in the app directory like we saw in the previous post, and for each function it reads the input, output and trigger from the function config JSON file.

The scanning process uses a descriptor provider which creates the input binding, output binding, trigger and an invoker

Once all functions are loaded, it tried to load the types for each function that was developed outside the portal. It uses the scriptFile and EntryPoint as you can see below. The entry point in the previous code snippet is FunctionApp1.Function1.Run method that exist in the assembly FunctionApp1.dll

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.14",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "timerTrigger",
      "schedule": "0 */5 * * * *",
      "useMonitor": true,
      "runOnStartup": false,
      "name": "myTimer"
    }
  ],
  "disabled": false,
  "scriptFile": "../bin/FunctionApp1.dll",
  "entryPoint": "FunctionApp1.Function2.Run"
}

Each function app can either have a DLL function or a function created by portal. But not both.

Now, lets see what are the other components inside a binding:

  • Listener (IListener): This one has a method named StartAsync, which basically start listening for an event to trigger the function. For Azure Blob trigger, it scans the logs for new or modified files. For Queue trigger, it check for new messages in the specified queue.
  • Value Provider (IValueProvider): Once the listener has the event that should trigger the function, it uses the value provider to fill all input parameters. If the trigger was a blog trigger, then the value will be the file, the metadata, the name and content of the file itself. For a Queue, it will be content of the message and so on and so forth.
  • Value Converter (IAsyncConverter): This will be used to convert the values found in the value provider to all the input parameters configured for the function. In the previous example, StorageQueueMessageToStringConverter will be used to convert the CloudQueueMessage instance to the string parameter named myQueueItem. The same will be used to write data to output parameters, the framework will choose the best converter that matches the Output parameter type (Stream) and the type of variable that will be used to write to stream, ex: String or any Stream Writer.
  • Executor (ITriggerExecutor): Now we know that the function should be triggered, we have the data from input binding and we bound all input parameters, now we need to call the function body. This takes place using an implementation of ITriggerExecutor which can use reflection to call the function or in a very special case, it may get executed as a web hook like the case with HTTP trigger.

In the next post, I will dig more into Azure Function App to explore the extensions and host.