.NET for Google Cloud Functions (Alpha)
I spoke at many .NET conferences over the last 3-4 years and one of the top requests I always received was: When will .NET be supported on Cloud Functions?
Unfortunately, I didn’t have a good answer for a while. That all changed last month with the following tweet from Jon Skeet from our C# team:
I'm thrilled that .NET support is coming to Google Cloud Functions, along with the .NET Functions Framework. Sign up for the public alpha at https://t.co/nASIACFCrg
— Jon Skeet (@jonskeet) June 10, 2020
.NET support is coming to Cloud Functions and it is currently public alpha. You need to sign up here to gain access.
In this blog post, I want to give the .NET support of Cloud Functions a try and see how it works. Along the way, we’ll also learn about Functions Framework that powers the .NET support of Cloud Functions under the covers.
All the code I’ll share here are already in my GitHub repo: cloud-functions-dotnetcore.
Why Cloud Functions
Before I dive into the .NET support of Cloud Functions, one question that’s worth answering is: Why Cloud Functions for .NET? There are already multiple ways of running .NET on Google Cloud, so why one more?
To recap the current options, you can run .NET Framework on Windows on Compute Engine or .NET Core containers on Linux in App Engine (Flex), Kubernetes Engine and most recently Cloud Run. Cloud Run has been my default choice to run .NET Core because of its fast deployments, its awesome DevEx and its serverless scaling and billing model. However, the unit of deployment in Cloud Run is a container. Going from .NET code to a Docker image via Dockerfile is usually straightforward but not trivial. Making sure that the Dockerfile is optimized and secure is even more work.
Sometimes, you just want to write code and deploy it without having to worry about containers. This is what Cloud Functions enable you to do. Cloud Functions also tend to have better integration with different Google Cloud events, as of today.
Functions Framework
Functions
Framework tries
to simplify writing and deploying portable functions across different platforms such
as Cloud Functions, Cloud Run, Cloud Run on GKE or pure Knative. It’s also
useful for local development and debugging. It supports HTTP
and CloudEvent
consuming functions.
Functions Framework for .NET does the same for .NET and it is the foundation for the .NET support in Cloud Functions.
Templates for Cloud Functions
Functions Framework for .NET comes with some templates for dotnet
to make
it easier to get started. Installing templates is a single command:
dotnet new -i Google.Cloud.Functions.Templates::1.0.0-alpha08
You’ll see the following new templates:
Templates Short Name Language Tags
--------------------------------------------------------------------------------------------------------------------------------
Google Cloud Functions CloudEvent Function gcf-event [C#], F#, VB Google/Cloud/Functions/Events
Google Cloud Functions CloudEvent Function (Untyped) gcf-untyped-event [C#], F#, VB Google/Cloud/Functions/Events
Google Cloud Functions HttpFunction gcf-http [C#], F#, VB Google/Cloud/Functions/Http
The first two for CloudEvent
consuming functions and the last one is for
HTTP
consuming functions. We’ll explore all next.
HTTP Function
Creating an HTTP
consuming function is as easy as:
dotnet new gcf-http
This creates a new project with a Function.cs file:
public class Function : IHttpFunction
{
/// <summary>
/// Logic for your function goes here.
/// </summary>
/// <param name="context">The HTTP context, containing the request and the response.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task HandleAsync(HttpContext context)
{
await context.Response.WriteAsync("Hello, Functions Framework.");
}
}
This is the function that will handle HTTP
requests and send HTTP
responses back.
I like the simplicity of the API and it’s a bonus that we don’t need to worry
about containers.
To deploy the function, you’d use dotnet3
runtime and trigger-http
flag:
gcloud functions deploy hello-http-function \
--runtime dotnet3 \
--trigger-http \
--entry-point HelloHttpFunction.Function
In a minute or two, you should see the function deployed:
CloudEvent Function
Functions Framework for .NET starts shining when you start consuming
CloudEvents
. The framework does a good job in not only parsing the
CloudEvent
but it also tries to parse the data within the CloudEvent
into
strong types.
For example, Google Cloud Storage emits CloudEvents
. To consume those
events, you’d first create a CloudEvent
consuming function:
dotnet new gcf-event
This creates a
Function.cs
that parses a CloudEvent
and also the data of the CloudEvent
into a
StorageObjectData
object:
public class Function : ICloudEventFunction<StorageObjectData>
{
public Task HandleAsync(CloudEvent cloudEvent, StorageObjectData data, CancellationToken cancellationToken)
{
This is very useful! To deploy the function, you need to specify the
trigger-event
and trigger-resource
accordingly:
gcloud functions deploy hello-cloudevent-storage-function \
--runtime dotnet3 \
--entry-point HelloCloudEventStorageFunction.Function \
--trigger-event google.storage.object.finalize \
--trigger-resource ${BUCKET_NAME} \
--allow-unauthenticated
If you want to consume Pub/Sub messages instead, you can
go through the same process but change StorageObjectData
to
MessagePublishedData
in
Function.cs
to make sure the data is parsed for Pub/Sub message:
public class Function : ICloudEventFunction<MessagePublishedData>
{
public Task HandleAsync(CloudEvent cloudEvent, MessagePublishedData data, CancellationToken cancellationToken)
{
And you need to deploy with trigger-topic
in this case:
gcloud functions deploy hello-cloudevent-pubsub-function \
--runtime dotnet3 \
--entry-point HelloCloudEventPubSubFunction.Function \
--trigger-topic ${TOPIC_NAME}
You can see the full list of what triggers are supported in a strongly typed way in deployment page.
If you simply want to listen for CloudEvent
without parsing the specific
data
type, you can create an untyped function as follows:
dotnet new gcf-untyped-event
This creates a
Function.cs
with a simple CloudEvent
signature:
public class Function : ICloudEventFunction
{
public Task HandleAsync(CloudEvent cloudEvent, CancellationToken cancellationToken)
{
Dependency injection
The last thing I want to mention with the .NET support in Cloud Functions is its handy dependency injection.
For example, if you want the logger to be injection into your functions, you can
simply add the following to your Function.cs
:
private readonly ILogger _logger;
public Function(ILogger<Function> logger) =>
_logger = logger;
In you need to do more complicated dependency injection, you can create a
Startup.cs
class extending FunctionsStartup
and do additional injection in
Configure
method as shown in Function.cs:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder) =>
builder.Services
.AddSingleton<IOperationSingleton, Operation>()
.AddScoped<IOperationScoped, Operation>();
}
This wraps up my discussion of .NET on Cloud Functions. Exciting times for .NET on Google Cloud for sure!
- Sign up for public alpha here.
- Check out my code and instructions here.
- Questions/comments? Reach out to me on Twitter (@meteatamel).