Categories
Azure

Azure Functions & .NET 5 – State of Play

.NET 5 was released on November 10th 2020 and contains features (specifically C#9 support and thus Record Types) that we were keen to use in our products at Matchnet.

See the source imageAs we’re heavily based on Azure Functions, I was happy to see an announcement of a preview of Azure Functions on .NET 5. We went ahead and evaluated it, and here’s what we found:

  • No support for rich function types such as Durable Functions.
  • Visual Studio support is not there yet, but promised soon
  • HTTP trigger interface uses simplistic HTTP message abstraction (HttpMessageData instead of HttpRequest)

Durable Functions

This was the most disappointing issue, as we’re using Durable Functions in a few places. They’re a useful implementation of a saga/orchestration.

The implementation of the .NET 5 Azure Functions is based around “an out-of-process model where a .NET worker process runs alongside the runtime”. On the face of it this sounds good, as it decouples us from the runtime’s version support. However, it means we also don’t have access to the extension code running in the host, which is what Durable Functions relies on. See this GitHub issue comment.

The team will be updating the host to the .NET 6 LTS, which will mean .NET based functions being deployed in the conventional way, directly to the host and not out of process, so Durable Functions should work fine. Roll on November 2021.

Visual Studio

As of Visual Studio 16.8.4 there isn’t a project template for the out-of-process .NET 5 functions. Instead you create an ASP.NET Core project and build around that. The readme on the GitHub preview site has the details.

We had trouble getting local debugging running. The only way that seemed successful was to start the program then attach to the “dotnet.exe” process, if you can find the right one. It’s a bit of a hassle but I expect that will get sorted out with official Visual Studio support.

HTTP Trigger’s HttpMessageData

This is the class used to convey the payload for an HTTP trigger. It’s a wrapper on top of a RpcHttp class, part of a .NET implementation of gRPC. As such it has a very simple interface and doesn’t provide for the full suite of normal HTTP capabilities including cookies and attaching files, both of which are possible in the standard Azure Functions HTTP trigger via the HttpRequest class.

Conclusion

We’re going to skip it for now, though we’ll keep an eye on where it goes. It doesn’t sound to me like the out-of-process model is where the function team’s heart is at right now for .NET functions, so I hold out more hope for the upgrade of the host to .NET 6.

Advertisement
Categories
Computers and Internet

Referencing a .NET assembly in a compile time safe manner

If you need to provide a System.Reflection.Assembly instance to an API [1], there are several mechanisms for doing so. They roughly split into two camps:

  • Run-time assembly loading
  • Assemblies known at compile time

The run-time assembly loading includes scenarios such as having a plug-in architecture where the code being referenced cannot be known at the time of compilation.

For the other camp, if we know exactly which assembly we need to reference at compile time we have a couple of options. We can use the name of the assembly as a string like so:

Assembly.Load(“MyCompany.Util”);

(Note that if the assembly is already loaded the runtime will just return the loaded instance of that assembly and won’t attempt to load it again.)

Alternatively we can use a type from that assembly like so:

Assembly.GetAssembly(typeof(MyCompany.Util.AnyOldClass);

The problem with the assembly name string approach is that there is no compile time checking. The typeof approach allows for compile time checking but introduces an artificial dependency in the calling code on a class that it only needs for the purposes of getting the assembly. This calling code is then subject to any renaming or removal of that class when in reality it cares only about the assembly and not the type.

The solution I’ve gone for is to create a static, empty class with a similar name to the assembly in the root of the default namespace of the assembly I wish to reference and use this in the typeof:

using MyCompany.Util;
/* … */
Assembly.GetAssembly(typeof(MyCompanyUtil));

This provides us with a compiler error if the assembly reference is dropped or the assembly is renamed. It will take part in any necessary refactoring operations and is not dependent on irrelevant types.

 

[1] Examples include Autofac’s MVC and WebApi integration: ContainerBuilder.RegisterControllers & ContainerBuilder.RegisterApiControllers