Build and deploy a C# .Net Core service

Learn how to create a simple Hello World application, package it into a container image, upload the container image to Container Registry, and then deploy the container image to Cloud Run. You can use other languages in addition to the ones shown.


For step-by-step guidance on this task directly in Cloud Shell Editor, click Guide me:

Guide me


The following sections take you through the same steps as clicking Guide me.

Alternatively, follow this quickstart with a demo account on Qwiklabs.

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Cloud project. Learn how to confirm that billing is enabled for your project.

  4. Install and initialize the Cloud SDK.

Writing the sample application

To write an application in C#:

  1. Install .NET Core SDK 3.1. Note that we only need to do this to create the new web project in the next step: the Dockerfile, which is described later, will load all dependencies into the container.

  2. From the console, create a new empty web project using the dotnet command:

    dotnet new web -o helloworld-csharp
    
  3. Change directory to helloworld-csharp.

  4. Update the CreateHostBuilder definition in Program.cs to listen on the port defined by the PORT environment variable:

    using System;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    
    namespace helloworld_csharp
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args)
            {
                string port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
                string url = String.Concat("http://0.0.0.0:", port);
    
                return Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>().UseUrls(url);
                    });
            }
        }
    }

    This code creates a basic web server that listens on the port defined by the PORT environment variable.

  5. Create a file named Startup.cs and paste the following code into it:

    using System;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    namespace helloworld_csharp
    {
        public class Startup
        {
            // This method gets called by the runtime. Use this method to add services to the container.
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
            public void ConfigureServices(IServiceCollection services)
            {
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseRouting();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapGet("/", async context =>
                    {
                        var target = Environment.GetEnvironmentVariable("TARGET") ?? "World";
                        await context.Response.WriteAsync($"Hello {target}!\n");
                    });
                });
            }
        }
    }

    This code responds to requests with our "Hello World" greeting.

Your app is finished and ready to be containerized and uploaded to Container Registry.

Containerizing an app and uploading it to Container Registry

To containerize the sample app, create a new file named Dockerfile in the same directory as the source files, and copy the following content:

# Use Microsoft's official build .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-sdk/
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build
WORKDIR /app

# Install production dependencies.
# Copy csproj and restore as distinct layers.
COPY *.csproj ./
RUN dotnet restore

# Copy local code to the container image.
COPY . ./
WORKDIR /app

# Build a release artifact.
RUN dotnet publish -c Release -o out


# Use Microsoft's official runtime .NET image.
# https://hub.docker.com/_/microsoft-dotnet-core-aspnet/
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# Run the web service on container startup.
ENTRYPOINT ["dotnet", "helloworld-csharp.dll"]

To exclude files produced via local dotnet build operations from upload to Cloud Build add a .gcloudignore file in the same directory as the sample app's source files:

# The .gcloudignore file excludes file from upload to Cloud Build.
# If this file is deleted, gcloud will default to .gitignore.
#
# https://cloud.google.com/cloud-build/docs/speeding-up-builds#gcloudignore
# https://cloud.google.com/sdk/gcloud/reference/topic/gcloudignore

**/obj/
**/bin/

# Exclude git history and configuration.
.git/
.gitignore

If these lines are in a .gitignore file, you can skip this step because .gitignore is a default source for .gcloudignore configuration.

Copy these lines to a .dockerignore file for local container builds with the docker CLI.

Build your container image using Cloud Build, by running the following command from the directory containing the Dockerfile:

gcloud builds submit --tag gcr.io/PROJECT-ID/helloworld

where PROJECT-ID is your GCP project ID. You can get it by running gcloud config get-value project.

Upon success, you will see a SUCCESS message containing the image name (gcr.io/PROJECT-ID/helloworld). The image is stored in Container Registry and can be re-used if desired.

Deploying to Cloud Run

To deploy the container image:

  1. Deploy using the following command:

    gcloud run deploy --image gcr.io/PROJECT-ID/helloworld --platform managed

    If prompted to enable the API, Reply y to enable.

    Replace PROJECT-ID with your GCP project ID. You can view your project ID by running the command gcloud config get-value project.

    1. You will be prompted for the service name: press Enter to accept the default name, helloworld.
    2. You will be prompted for region: select the region of your choice, for example us-central1.
    3. You will be prompted to allow unauthenticated invocations: respond y .

    Then wait a few moments until the deployment is complete. On success, the command line displays the service URL.

  2. Visit your deployed container by opening the service URL in a web browser.

Cloud Run locations

Cloud Run is regional, which means the infrastructure that runs your Cloud Run services is located in a specific region and is managed by Google to be redundantly available across all the zones within that region.

Meeting your latency, availability, or durability requirements are primary factors for selecting the region where your Cloud Run services are run. You can generally select the region nearest to your users but you should consider the location of the other Google Cloud products that are used by your Cloud Run service. Using Google Cloud products together across multiple locations can affect your service's latency as well as cost.

Cloud Run is available in the following regions:

Subject to Tier 1 pricing

  • asia-east1 (Taiwan)
  • asia-northeast1 (Tokyo)
  • asia-northeast2 (Osaka)
  • europe-north1 (Finland)
  • europe-west1 (Belgium)
  • europe-west4 (Netherlands)
  • us-central1 (Iowa)
  • us-east1 (South Carolina)
  • us-east4 (Northern Virginia)
  • us-west1 (Oregon)

Subject to Tier 2 pricing

  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seoul, South Korea)
  • asia-southeast1 (Singapore)
  • asia-southeast2 (Jakarta)
  • asia-south1 (Mumbai, India)
  • australia-southeast1 (Sydney)
  • europe-central2 (Warsaw, Poland)
  • europe-west2 (London, UK)
  • europe-west3 (Frankfurt, Germany)
  • europe-west6 (Zurich, Switzerland)
  • northamerica-northeast1 (Montreal)
  • southamerica-east1 (Sao Paulo, Brazil)
  • us-west2 (Los Angeles)
  • us-west3 (Las Vegas)
  • us-west4 (Salt Lake City)

If you already created a Cloud Run service, you can view the region in the Cloud Run dashboard in the Cloud Console.

Congratulations! You have just deployed an application packaged in a container image to Cloud Run. Cloud Run automatically and horizontally scales out your container image to handle the received requests, then scales in when demand decreases. You only pay for the CPU, memory, and networking consumed during request handling.

Clean up

Removing your test project

While Cloud Run does not charge when the service is not in use, you might still be charged for storing the container image in Container Registry. You can delete your image or delete your Cloud project to avoid incurring charges. Deleting your Cloud project stops billing for all the resources used within that project.

  1. In the Cloud Console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

What's next

For more information on building a container from code source and pushing to Container Registry, see: