The moment I came to play with .NET Standard 2.0…
I’ve been playing around with Azure Functions, the Bot Framework and the .NET Standard 2.0 framework recently and I’ve come across some quite interesting challenges that I want to share with you.
I’ve been developing a system that has the following layout:
As you can see, I have an Azure Function (Time Trigger) that pushes data to an Azure SQL database. I have an ASP.NET Core Web API (targeting the .NET Core 2.0 framework) that is the data abstraction for anything that wants to consume my data. Right now, only the Bot (Bot Framework) is the client.
To have a functional and reusable ecosystem, I created some libraries to interact with my system which includes the Data Access Layer (DAL), Domain and Services libraries. All those libraries target the .NET Standard 2.0 framework as well.
My DAL library consists of my repositories/unit of work. For the database communication, I use Entity Framework Core (EFCore) 2.0. They haven’t yet migrated all features of EF6 (some have been dropped), but they are getting there (see this post for more the roadmap). Considering the nature of my project, the features not implemented are not big deal to me. I want to make use of certain new features such as the InMemory provider for my unit testing. The ease of setup and integration with .NET Core projects (my Web API is one) is a plus.
As a quick mention, the other libraries of interest are the domain library which consists of all the models and business logic used in my system and my service library, which acts as the abstraction between my DAL and the clients of my system.
The fun starts now
.NET Standard is pretty new (RTM was announced mid August of this year). As you know, the .NET Standard was created to unify all the .NET implementations. The .NET Standard is a formal specification of .NET APIs that are intended to be available on all .NET implementations1. However, not everything from the .NET Full Framework is available on .NET Standard. Certain classes and implementations have been removed (some due to cross platform compatibility) or have not yet been ported.
Bot Framework
The Bot Framework is built using ASP.NET MVC and does not implement OWIN. It targets by default the .NET Full Framework 4.6. Knowing this, I configured OWIN and I bumped the target Framework of the project to 4.7.1, as starting with the .NET Full Framework 4.6.1, all versions implement .NET Standard 2.0 (see this table for more information).
I then referenced my service library and started the Bot. When my bot was not interacting, I promptly looked at the debug window of Visual Studio to realize a System.MissingMethodException had been thrown. Lo and behold, there seems to be a problem with System.Net.Http and the bindings. It has been documented in this GitHub issue. To remedy the problem, I had to do a binding redirect.
I edited web.config and added the following in the <runtime><assemblyBindings> section:
1 2 3 4 |
<dependentAssembly> <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" /> </dependentAssembly> |
This tells .NET to use the version 4.2.0.0, the version included in the project and in the .NET Framework
After adding this, the Bot was able to run properly!
Azure Functions V2
Next step for the project: my time trigger Azure Function (V2 since V1 does not support .NET Standard 2.0). I added an Azure Function project to my solution. This uses the Azure functions SDK (Microsoft.NET.Sdk.Functions). I updated this SDK from 1.0.6 to 1.0.7 and referenced my DAL library to communicate with my database. I started the function in debug through Visual Studio (my version being 15.5.2) to be able to debug it.
Problem #1:
The listener for function ‘DataChecker’ was unable to start. System.Private.CoreLib: One or more errors occurred. (Invalid storage account ‘devstoreaccount1’. Please make sure your credentials are correct.). Microsoft.Azure.WebJobs.Host: Invalid storage account ‘devstoreaccount1’. Please make sure your credentials are correct.
An azure function requires storage to work. In developement mode, you need to be able to emulate that, and this is done by having the following values in your local.settings.json file.
1 2 3 4 |
"Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "AzureWebJobsDashboard": "UseDevelopmentStorage=true" } |
I had forgotten to start it. I started the Azure Storage Emulator, initialized it (it uses localdb as data storage) and then started it. This fixed the above error message.
Note:
If, when you init the storage, you get an error message of the type “Cannot Create Database”, you may need to delete the database and let init create it again. This can happen in case of an update. See this post for more information.
If you have an error message such as:
Caught exception while probing for SQL endpoint. A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified) Number of Sql Errors Reported: 1 Sql Error: System.Data.SqlClient.SqlError: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)
See this post for how to fix that.
Problem #2:
Could not load file or assembly Microsoft.EntityFrameworkCore, Version=2.0.1.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified
Well it seems that there is a problem in Visual Studio with Azure Functions SDK. This GitHub issue mentions the problem. Here is an excerpt of the problem:
Currently, when building with Visual Studio, regardless of what Functions SDK version you’ve specified, it will run against the version of the CLI that it wants. For V1 functions, this comes from a feed, which always has the latest CLI. For V2 functions, it is currently bound to the version that comes with the Functions extension.
So, in short, if you want to build and run V2 Functions in Visual Studio, you must stick with Functions SDK v1.0.6 (for now).
You also need to reference EFCore 2.0.0. Version 2.0.1 does not seem to be compatible as well. Hopefully that can be fixed soon. (Thanks to Boris on StackOverFlow for the tip!)
It is not the end…
I was told that if you want the best of Azure Functions, it is best to use the .NET Full Framework with them. That being said, I like living on the edge, so I will continue my quest with the .NET Standard 2.0 framework on this project and see how far it brings me. Stay tuned for more updates!