Running with C# on GCP Cloud Run

Garrett Wong
Google Cloud - Community
6 min readApr 17, 2020

TLDR; We will walkthrough the practical aspects of building a simple AspNet Core Random Translation Web API and Deploying it onto Cloud Run.

First, a quick primer around DotNet Core and C#

DotNet Core was officially released June 27 of 2016. We are nearing its fourth birthday and it has gone through 3 sets of Major Version Releases to date and the magical jump from Version 3.X.X to version 5.0.0 is just around the corner. A long standing framework with thorough history built from the strengths and lessons of DotNet which has been around since the early 2000s.

Next, a quick intro to Cloud Run on GCP

Cloud Run is a fully managed service that can autoscale stateless Docker Containers. If you’re looking for a quick and easy way of quickly hosting a stateless application, Cloud Run is a solid bet. Cloud Run was released to GA on November 14 of 2019.

Let’s get Running

As promised, we want to take you from Nothing to Running in Cloud Run.

For those of you all who are new to Google Cloud Platform, head on over to https://console.cloud.google.com/ and spin yourself a free GCP Account. For first time users, you’ll get an initial $300 of credit to explore GCP products and resources.

I favor sequential approaches to blog posts that attempt to get somewhere so that they are easier to follow along.

Step 1: Activate Cloud Shell

Click the button with an icon of a Terminal. This will open the integrated Cloud Shell.

Note: If this is your first time opening Cloud Shell, it may take a few minutes to provision the environment.

Step 2: Upgrade your DotNet Version

While the dotnet executable is already available by default within Cloud Shell, it isn’t the latest-latest stable version (it is currently version 3.0.103).

Let’s use the latest stable version of dotnet core by using apt-get and running the following commands in the Cloud Shell Terminal.

sudo apt-get update
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-3.1
dotnet --version # 3.1.201

dotnet --version now returns version 3.1.201.

3. Bootstrap your DotNet Core Application

Let’s bootstrap our app with the dotnet cli.

dotnet new webapi -o google_translation_apicd google_translation_api/

Let’s open Program.cs and add the following line to line 24:

vi Program.cs# line to add:
# webBuilder.UseUrls("http://0.0.0.0:8080");

The file should now appear as below.

Make edits and save the file with :wq

Now let’s test our app, to ensure it runs within Cloud Shell.

dotnet run

Now click the Web Preview button to preview the app on Port 8080. But, wait… Initially you’ll get an error, so verify the app is running by Navigating to the /WeatherForecast URL endpoint.

4. Let’s add a second controller, “The Random Translation Controller”

This API Controller will take in a word and it will return back that word, translated in a random language.

As we will be tinkering with the Google Translate API, we’ll need to enable the service.

gcloud services enable translate.googleapis.com

Let’s add the package below.

dotnet add package Google.Cloud.Translation.V2 --version 2.0.0

Let’s create another controller under Controllers, called RandomTranslationController.cs .

Copy and paste the below contents into that file and save.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Cloud.Translation.V2;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace google_translation_api.Controllers {
[ApiController]
[Route ("[controller]")]
public class RandomTranslationController : ControllerBase {
private string[] _languageCodes = null;
private readonly ILogger<RandomTranslationController> _logger;
public RandomTranslationController (ILogger<RandomTranslationController> logger) {
_logger = logger;
}
[HttpGet]
public string RandomTranslate (string text) {
using (var client = TranslationClient.Create ()) {
var response = client.TranslateText (text, _getRandomLanguageCode ());
return response.TranslatedText;
}
}
private List<string> _getLanguageCodes () {
using (var client = TranslationClient.Create ()) {
var languages = client.ListLanguages (LanguageCodes.English).ToList ();
return languages.Select (k => k.Code).ToList ();
}
}
private string _getRandomLanguageCode () {
if (_languageCodes == null) {
_languageCodes = _getLanguageCodes ().ToArray ();
}
var length = _languageCodes.Length;
var random = new Random ();
var randomIndex = random.Next (0, length);
return _languageCodes[randomIndex];
}
}
}

In Cloud Shell Editor, your code structure should look similar to this.

As an aside, if you want to test your code locally, re-run dotnet run and navigate over to the path, /RandomTranslation?text=Welcome. As we are using a Google API, you will need to set the Default Credentials via generating a Service Account JSON Key File and setting it via export GOOGLE_APPLICATION_CREDENTIALS="sa-key.json" prior to running the app.

5. Now we move onto Dockerizing our Application

Add a file Dockerfile at the root of our application, right where Program.cs resides. You can run the following command to create the file.

cat > Dockerfile << EOF
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "google_translation_api.dll"]
EOF

Note: If you called your application something other than google_translation_api, you’ll need to change the ENTRYPOINT call accordingly.

Now let’s build our docker image.

docker build -t gcr.io/$DEVSHELL_PROJECT_ID/csharp-translation-api .

$DEVSHELL_PROJECT_ID is a special environment variable auto-set in Cloud Shell, reflective of the Project ID that you selected. If this ENV VAR is not available, either SET it or replace the above variable with the Project ID.

Let’s push our docker image to Google Container Registry (GCR)

docker push gcr.io/$DEVSHELL_PROJECT_ID/csharp-translation-api

6. Deployment Time

The part we’ve all been waiting for. Deploying our Docker Container to Cloud Run.

Let’s enable the service and deploy the app onward to Cloud Run.

gcloud services enable run.googleapis.comgcloud run deploy csharp-translation-api --image gcr.io/$DEVSHELL_PROJECT_ID/csharp-translation-api --platform managed --region us-central1 --allow-unauthenticated

Given that the deployment succeeded, you will see the URL in which to navigate to, listed within the terminal. Load that URL up in your web browser and head over to the path, /RandomTranslation?text=enter%20your%20text%20here

Once the page is loaded, you will get a translation of the english phrase passed in, using a random language from the set of many languages supported within the Translation API. Hooray!

Conclusion

So we’ve made it through a first example of deploying a C# application onto GCP’s serverless container platform, Cloud Run. That’s a major accomplishment and precursor towards many more intriguing opportunities for rapid, scalable development. The sky is the limit, be creative and build from what we’ve covered here.

In the comments, let me know your thoughts and feedback and don’t hesitate to reach out if you hit a roadblock along the way.

--

--

Garrett Wong
Google Cloud - Community

Google Cloud Strategic Cloud Engineer, 11x GCP certified