Monthly Archives: January 2019

A Few Coding Patterns with the MongoDB C# API

In the February 2019 issue of MSDN Magazine (Exploring the Multi-Model Capability of Azure Cosmos DB Using Its API for MongoDB), my Data Points column explored working with the MongoDB model of Azure Cosmos DB using the mongocsharpdriver. I started by working against a local instance of MongoDB and then the Azure instance. But the column was a little bit long so I cut out a few extraneous sections . So I’m placing them here and linking to this blog post from the article.

In the article I used an IMongoCollection object to query and store data into the database. You must specify a type for the collection object to serialize and deserialize. In the article I typed the collection to my classes, e.g.,  Collection<Ship>. It’s also possible to type the collection generically to a BsonDocument. Here’s some information about that and a little bit of code.

Typing Collections to BsonDocument

Another path for mapping is to use a BsonDocument typed collection object that isn’t dependent on a particular type. This would allow you to have more generic methods. But it also means manually serializing and deserializing your objects, which is easy using ToBsonDocument for serializing:

var coll = db.GetCollection<BsonDocument> ("Ships");
coll.InsertOne (ship.ToBsonDocument());

Given that the documents have discriminators, you can then specify a type in your query to retrieve specific types although, by default, hierarchies don’t get accounted for. The article refers to documentation on polymorphism for the C# API. Here’s the link. Check  to learn how to properly implement polymorphism in more detail . The following code will only pull back documents where _t matches the configured discriminator for Ship into ships and for DecommissionedShip into dShips:

var coll = db.GetCollection<BsonDocument> ("Ships");
var ships = coll.AsQueryable().OfType<Ship>().ToList();
var dShips = coll.AsQueryable()
                  .OfType<DecommissionedShip>().ToList();

Encapsulating the MongoClient, Database and Collection

Specifying a typed collection instance repeatedly, as I did in the article demos, can become a drag. You could set them up in advance, for example in a class that acts as a context for interacting with the database, as shown here:

public class ExpanseContext
{
  public IMongoDatabase ExpanseDb { get; private set; }
  public IMongoCollection<Ship> Ships { get; private set; }
  public IMongoCollection<Character> Characters {get;private set;}
  public ExpanseContext()
  {
    ExpanseDb=new MongoClient().GetDatabase("ExpanseDatabase");
    Ships=ExpanseDb.GetCollection<Ship>("ships");
    Characters=ExpanseDb.GetCollection<Character>("ships"); 
  } 
}

This refactored code to insert a document is much more readable:

private static void InsertViaContext ()
{
  var context = new ExpanseContext ();
  var ship = new Ship { Name = "Agatha King" };
  context.Ships.InsertOne (ship);
}

Building C# Project-based Azure Functions in Visual Studio Code

I’ve been using the Azure Functions for Visual Studio Code for some time now and they continue to evolve in great ways. The latest shift threw me for a loop so I thought I would document some of it for those who may not have started yet. I should also state that for the past year or so I have focused on writing my functions with JavaScript just because I like to mix things up a bit and it also makes it easier to share Azure Functions with devs who are not .NET focused.

I’ve also written about creating Azure Functions with VS Code in MSDN Magazine but again, this has changed since I wrote about it. I’ve been using the version 2 APIs for a while so I’m not talking (well, writing) about that change from v1 to v2 here but the change in the experience using the Azure Functions extension.

Also notable is that the Azure Functions team actually recommends using Visual Studio for building C# based apps and VS Code for JavaScript. But I’m so often on my MacBook and love using VS Code so I am going down this path with C# anyway.

Having revisited the docs enough times to finally notice some key information, I realize why the experience has changed with the extension working with C#. Previously, I’d worked with C# script functions (.csx) which is the same as what you use when you work directly in the portal. But the extension templates now drive you to C# project functions and there’s a big difference. C# script functions are more like the javascript functions. They depend on a manually created function.json file to define the bindings and can install the appropriate extension packages based on the bindings. The csx files are compiled at run time. With a C# class library, you develop as you would other C# class libraries – installing the relevant packages and then using attributes to identify methods as Azure Functions as well as trigger, input and output bindings. When you compile the library, the Azure Functions tooling will generate a function.json file for you that gets deployed.

Because I was used to creating functions with JavaScript or the C# script path, the new default for the Azure Function extension that uses C# class libraries instead really threw me for a loop. So I decided to document walking through this workflow as I has to learn it. I think I still prefer the lighter weight C# script (.csx) or JavaScript flow but that might align with my preference in many scenarios for VS Code over Visual Studio.

Preparing Visual Studio Code

So first things first: you’ll need to install the Azure Functions and Azure Account extensions into VS Code, Azure Functions extension relies on the Azure Functions Core Tools. The extension installation instructions will help  you get all that you need and the extension does check for updates and prompt you to update those tools as needed. In fact, I got this prompt last night.2019-01-16_09-28-10.png

With the extensions installed, it is time to create a function app project. You should already have a folder created to house your project and you might as well have it open in VS Code. Mine is named AzureFunctionProj.

Then you can click on the “Create New Project” icon on the function bar (the icons show up when you hover over the bar) to create a new Function App project inside your folder.

2019-01-17_18-11-39.png

This part of the workflow has not changed.

  1. It will ask you to point to a folder and the open folder should be there as a default to select.
  2. It will then have you select a language you’ll use in your app. From the options (C#, JavaScript, Python (still a preview) and Java (also a preview), I’ll choose C#.

As a result a new .NET Core project will be created using the template and you’ll see the following in the folder explorer:

2019-01-17_18-19-58.png

All of these files inside AzureFunctionProj folder were created by the template. Most importantly the csproj file where I’ve highlighted some of the most relevant settings.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <AzureFunctionsVersion>v2</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
   <PackageReference Include="Microsoft.NET.Sdk.Functions"
                     Version="1.0.24" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Creating a function in the function app is where things are quite a bit different.

You begin as always with the “add a function” icon2019-01-17_18-11-39 copy.png

The first step is familiar, selecting which folder has the function app that the function should be in:

2019-01-17_22-06-37.png

I’ll choose AzureFunctionProj.

Then there are a number of trigger templates to choose from which is nice but more interesting are the three options at the bottom:

2019-01-17_16-42-25.pngFirst is the project runtime and I definitely want v2 (“~2”). You can use different languages for different functions in the function app. This is showing the default I chose already: C#. And finally, the list of trigger templates is filtered to “Verified”.

You can change these options by clicking on them.

The filter options are Verified, Core and All. Core and All currently reveal the same list, which includes a few extra preview triggers: DurableFunctionsOrchestration, SendGrid, EventHubTrigger and IotHubTrigger.

2019-01-17_16-43-20.png

Now in the past I was creating JavaScript functions inside my .NET Core Function App but now I am going to continue with C# because this is where things really surprised me. I’ll choose  HttpTrigger and am then prompted to provide a name. I’ll just leave the default: HttpTriggerCSharp. I’m then asked to provide a namespace name for the class that will be created. Default is “Company.Project”. I’ll change it to FunctionTests.HttpTest1. The final bit of info to be collected is that you need to choose the security for the function. Of the options, I will select Anonymous because its a demo and I don’t want to have to deal with credentials.

That’s it. The function is created.

Some More Class Library Project Differences

My past experience gave me the expectation that a new folder is created inside the app function folder with the name of the function and inside there, would be a class file for the function and a function.json file to contain the binding configurations. the class file was there (though not in its own folder). But there was no function.json file. Also  interesting and new to me were the FunctionName attribute on the Run method and  the HttpTrigger attribute on the HttpRequest in the Run method’s signature. Also, I’m not used to having all of those using statements when using csx script.2019-01-19_15-16-45.png

When building the project, .NET Core reads that attribute and builds a function.json that goes in the bin folder for deployment. 2019-01-17_22-38-03.png

But it’s more than just the familiar bindings. Notice the generatedBy , configurationSource , scriptFile and entryPoint tags.

So the first binding, the httpTrigger binding, looks familiar to me. The function will respond to httpTrigger.

You can test out this default either by running or debugging. To run, you can use VS Code’s CTRL-F5 keyboard combo or, if you prefer using the CLI, you use Azure Function CLI command:

func host start

That will run the function and provide a url to try out. The template “stake-in-the-ground” method is written to accept either a query parameter or JSON in the body. I’ll just use a query parameter:

http://localhost:7071/api/HttpTriggerCSharp?name=Julie

And the browser outputs

2019-01-19_15-57-04.png

Adding an Output Binding to
Azure Cosmos DB

What if I wanted to add an output binding? I’m used to doing that by editing function.json. But since I’m on this path of attribute defined bindings, I will add the binding that way. Let’s add an output binding for Azure Cosmos DB. That way this function will respond to an HTTP Request and insert some data into a Cosmos DB database. I already have an Azure Cosmos DB account, so I will define this to target a new collection in a new database in the existing account.

In order to use work with a Azure Cosmos DB binding, I need to add the relevant package to my project. Because I’m building my function using a C# class library, I can just do this as I would for any other Nuget package…by adding it directly to csproj or adding the package with the dotnet core CLI:

But now I’m just writing a C# class library so I can add the package either with the dotnet CLI or just add it manually into .csproj. I’ll use the CLI:

dotnet add package Microsoft.Azure.WebJobs.Extensions.CosmosDB --version 3.0.3

Note that if I were building the function with JavaScript or  C# script, I would need to register the package using the tools CLI (func extensions install -p packagename).

Now the package is in csproj:

<ItemGroup>
  <PackageReference 
    Include="Microsoft.Azure.WebJobs.Extensions.CosmosDb"
    Version="3.0.3"/>
  <PackageReference
    Include="Microsoft.NET.Sdk.Functions"
    Version="1.0.24"/>
</ItemGroup>
After restoring, I can add the output binding. Currently the default function is asynchronous and you can’t add out parameters to an async method. Return values are one option. See https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings#using-the-function-return-value for details. ICollector or IAsyncCollector is another (https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library#writing-multiple-output-values).
But I’m going to  just make the Run method synchronous and create an output parameter instead. Like the trigger binding parameter, I’ll need to add an attribute to the output parameter to specify the binding. I’m also supplying parameters for the database and collection names, the name of the setting that has the connection string to the database account and one last setting to ensure the database and collection get created if needed.
[FunctionName("HttpTriggerCSharp")]
public static ActionResult Run(
   [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post",                 Route = null)]
   HttpRequest req,
   [CosmosDB(databaseName: "CSharpDatabase",
             collectionName: "CSharpCollection",
             ConnectionStringSetting = "MyCosmosDBConnection",
             CreateIfNotExists=true)] out dynamic document,
   ILogger log)
I added the MyCosmosDBConnection is defined in the local.settings.json file:
{
  "IsEncrypted": false,
  "Values": {
     "AzureWebJobsStorage": "",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet",
     "MyCosmosDBConnection": "this is where my connection string goes",
   }
}
Note that if you were creating a new function with an Azure Cosmos DB trigger, the tooling would prompt you for all of the relevant database information, include that an attribute in the function code and add them to the function.json.
Now there is just one last puzzle piece. The function expects me to provide a value to the document variable which the binding will then insert into the database. The full class listing is below and in there the single line for populating the document with a Name and Added property is highlighted in red. The function and the binding will do all of the rest.
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace FunctionTests.HttpTest1
{
  public static class HttpTriggerCSharp
  {
    [FunctionName("HttpTriggerCSharp")]
    public static ActionResult Run(
      [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
      HttpRequest req, 
      [CosmosDB(databaseName: "CSharpDatabase",
                collectionName: "CSharpCollection",
                ConnectionStringSetting = "MyCosmosDBConnection",
                CreateIfNotExists=true)] out dynamic document,   
      ILogger log)
    {
      log.LogInformation("C# HTTP trigger function processed a request.");
      string name = req.Query["name"];
      document=new { Name = name, Added = DateTime.Now };
      return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string");
     }
  }
}
Based on my previous experience of manually configuring function.json, I expected after building, the function.json in the bin folder to include the CosmosDB output binding information but it didn’t. Again, this is due to the differences between JavaScript/C# script functions and C# library functions.
Within VS Code I can run or debug the function. Debug is F5 or the debug icon. To run, without debugging, you can use CTRL-F5 or  the tools CLI command:
func host start
When using the CLI command, I found in my testing that the version I’m using seems to require me to run dotnet clean first for it to succeed. CTRL-F5 does that step for you . I made a note of this in a pre-existing GitHub issue. You can read that here.
There is a lot of useful info in the official docs. Two that I leaned on are:

Logging in EF Core 2.2 Has a Simpler Syntax–More like ASP.NET Core

Logging EF Core’s memory operations and SQL operations has evolved a few times since EF Core arrived. It takes advantage of the same underlying features that ASP.NET Core uses. If you are using ASP.NET Core, logging is baked in and it is really simple to turn it on for EF Core and add filtering. See Shawn Wildermuth’s blog post about EF Core logging in ASP.NET Core.

But if you aren’t using ASP.NET Core, it’s a little more complicated. Not terribly, but still there’s some extra work to do. It involves setting up an ILoggerFactory in your DbContext and defining any filters at the same time.

I wrote an article about this (with the focus being on taking advantage of the various available filters for EF Core logging) in MSDN Magazine earlier this …oh wait, it’s Jan 1, so I can say “last  year”.  Data Points – Logging SQL and Change-Tracking Events in EF Core. I also used it heavily in my EF Core 2 Getting Started course, EF Core 2:Mappings and EF Core 2.1: What’s New courses on Pluralsight. (Note that I’ve updated the sample code for the Getting Started course to EF Core 2.2 and put it on GitHub at github.com/julielerman/PluralsightEFCore2GettingStarted)

My article and courses were using Console apps to demonstrate EF Core behavior and therefore the ConsoleLoggerProvider to tie the logger to the console. Note that the Data Points article contains a lot of good details about the various types of filtering. So you can use the new syntax (below) to specify that there should be a filter, but be sure to read the article to learn about the flavors of filtering and what type of details you’ll be able to see based on the choices you make.

But the logging API has continued to evolve and is providing some of the same shortcuts that ASP.NET had created. And the ConsoleLoggerProvider has been deprecated. The API is not part of EF Core. It’s part of .NET Core. Both EF Core and ASP.NET Core use it.

If you are using EF Core 2.2, the syntax has changed (simplified) and it’s going to get even more streamlined in 3.0.

In fact, if you use the earlier syntax with 2.2, you’ll get a warning about the ConsoleLoggerProvider:

Obsolete(“This method is obsolete and will be removed in a future version. The recommended alternative is using LoggerFactory to configure filtering and ConsoleLoggerOptions to configure logging options.”)

For a point of comparison, here is an example of using theold syntax to turn on logging, only show logs related to database commands and only show messages that are tagged as “Information”.

EF Core 2.0 & 2.1 Logic

public static readonly LoggerFactory MyConsoleLoggerFactory
            = new LoggerFactory(new[] {
              new ConsoleLoggerProvider((category, level)
                => category == DbLoggerCategory.Database.Command.Name
               && level == LogLevel.Information, true) });

Once your logger factory field is defined in the context class you tell the DbContext to use it when configuring.

protected override void OnConfiguring
  (DbContextOptionsBuilder optionsBuilder)
{
  var connectionString = 
    ConfigurationManager.ConnectionStrings["WPFDatabase"].ToString();
  optionsBuilder
    .UseLoggerFactory(MyConsoleLoggerFactory)
    .EnableSensitiveDataLogging(true)
    .UseSqlServer(connectionString);
}

So it’s the creation of the logger factory whose syntax is a little convoluded. The newer API follows how ASP.NET Core lets you filter with an AddFilter method that takes the filters as parameters. No lambdas needed. Also configuring the filter is a separate bit of logic that tellig the logger that it should be tied to the console.

EF Core 2.2 Logic

With EF Core 2.2, you can set up the logger factory in the constructor or another method as long as it’s available when you are configuring the option builder. I’m creating it in a method then using that method as a parameter of UseLoggerFactory. I’m still filtering on showing only database commands and log details flagged as Information.

private ILoggerFactory GetLoggerFactory()
{
  IServiceCollection serviceCollection = new ServiceCollection();
  serviceCollection.AddLogging(builder =>
         builder.AddConsole()
                .AddFilter(DbLoggerCategory.Database.Command.Name, 
                           LogLevel.Information)); 
  return serviceCollection.BuildServiceProvider()
          .GetService<ILoggerFactory>();
}

and then I’m calling GetLoggerFactory() in the UseLogging method on the optionsbuilder:

optionsBuilder.UseLoggerFactory(GetLoggerFactory())

Packages and References

In order to use the AddConsole() method, you still have to use the Microsoft.Extensions.Logging.Console package that the earlier ConsoleLoggerProvider was in. However, you do not need a using statement for the namespace (as you did for the ConsoleLoggerProvider).