This tutorial shows you how to migrate Contoso University, a traditional Microsoft ASP.NET Framework MVC + Entity Framework sample that was built with .NET Framework 4.5 and EntityFramework 6. In this tutorial, you migrate the Contoso University application to .NET 5 and run it in a Linux container on Google Cloud Run, a fully serverless environment. You also use Cloud SQL for SQL Server, a managed Microsoft SQL Server 2017 database in Google Cloud. The migrated Contoso University application uses Google Diagnostics and Cloud Logging for ASP.NET Core as well as Google Secret Manager. This tutorial also and demonstrates how you can use Cloud Build to build the container and automatically deploy it to Cloud Run.
This tutorial provides end-to-end guidance on how to migrate the Contoso University application to .NET 5, including the specific changes that need to be applied to the application's original ASP.NET MVC code. For more detailed guidance about migrating from ASP.NET to ASP.NET Core, see the Microsoft documentation.
- Prerequisites
- Setup
- Migrate
- Refactor
- Using .NET 5 Configuration
- Deploying to Google Cloud
- Using Google Secret Manager
- Adding Google Cloud Logging & Monitoring
- Putting it all together
-
You must have access to Visual Studio 2019 – either download and install the free Community edition, or if you have a licesnse for Visual Studio, then any of the licensed editions.
-
(Optional) Install Docker on your local machine. If you can't install Docker in your environment, there is a workaround later in this tutorial.
-
Install .NET 5 SDK
-
Download and install the Google Cloud SDK following these instructions.
Either download the original Microsoft sample and unzip it to a local directory, or clone this repository and checkout the start
tag:
git clone https://github.com/jjdelorme/ContosoUniversity
git checkout start
If you've not already done so, make sure to enable the following APIs in your project. In Cloud Shell, use the following command:
gcloud services enable containerregistry.googleapis.com run.googleapis.com compute.googleapis.com cloudbuild.googleapis.com secretmanager.googleapis.com
In this section, you set up the Google Cloud SQL for SQL Server instance.
-
Create an instance. For the purposes of this tutorial you can use the SQL Server 2017 Express Edition which is free to license. For this tutorial, you put all resources in the
us-central1
region. If you prefer to use a different region, make sure to change that in all region in this tutorial. -
Add a user to connect to the database.
-
Allow access to your Cloud SQL instance:
-
Accessing the instance from a GCE VM and Cloud Run: Follow the instructions to configure a private IP for your Cloud SQL instance. Note the instance's private IP, as you use it later in this tutorial.
-
Accessing from your own machine (from the internet): Make sure that the IP address that you want to connect to the database from is added to your authorized networks. Alternatively, for the purposes of this tutorial, you can allow all public IPs (0.0.0.0/0) to connect, as shown in the following screenshot:
-
-
Open the
ContosoUniversity.sln
solution file with Visual Studio 2019. -
Using the Cloud SQL Server IP address, user and password you created preceding, modify your connection string in the
Web.config
file:<connectionStrings> <add name="SchoolContext" connectionString="Data Source=[INSTANCE_IP];Initial Catalog=ContosoUniversity;User ID=[USER];Password=[PASSWORD];" providerName="System.Data.SqlClient" /> </connectionStrings>
For the [INSTANCE_IP], use either the SQL Server instance's private or public IP address, according to where you are running the code from. For example, if you are running from your local machine, use the instance's public IP address.
-
In Visual Studio, open the Package Manager Console from the View menu -> Other Windows -> Package Manager Console. Enter the following command:
PM> update-database
This creates the schema and seeds the database with data automatically using Entity Framework and the DAL\SchoolInitializer.cs
class.
Confirm the application builds and functions as desired before starting the migration.
-
In Visual Studio 2019, press
Ctrl+F5
to build and run the project. -
Verify the application can access the database by selecting one of the tabs, for example, Departments.
You are now ready to migrate to application from .NET Framework to .NET 5.
If you want to first test the .NET Framework web application in a Windows container on GKE, refer to the GKE tutorial.
In this section, you use the .NET Upgrade Assistant to automate some steps of the migration to .NET 5. This will get you about 80% of the way there for this tutorial application. This automation is also a good starting point for most .NET Framework to .NET 5 upgrades.
-
Close your Visual Studio instance
-
Open a command prompt in the solution folder where you extracted the sample, for example,
c:\repos\ContosoUniversity\
-
Install the .NET Upgrade Assistant and dependents:
dotnet tool install -g try-convert dotnet tool install -g upgrade-assistant
-
Run the upgrade assistant:
upgrade-assistant upgrade ContosoUniversity.sln --non-interactive --skip-backup
The output of the Upgrade Assistant is the converted .NET 5 project. A
upgrade-assistant.clef
file contains a log of the changes. -
Run the following commands to remove unused assemblies and update packages to their recent version:
dotnet add package Newtonsoft.Json dotnet remove reference System.Net
In this section, you make some manual changes to get the application to enable you to build under .NET 5. At this point, we recommend that you switch to Visual Studio Code which is much lighter weight, open source IDE for developing in .NET Core. However, you can continue to use Visual Studio if you choose.
The downloaded source code directory structure should resemble the following tree. The root \
of the directory contains the ContainerUniversity.sln
solution file and the project directory is .\ContosoUniversity\
:
.
..
├── ContosoUniversity.sln
├── ContosoUniversity
│ ├── ContosoUniversity.csproj
│ ├── Global.asax
│ ├── Global.asax.cs
│ └── App_Start
│ └── BundleConfig.cs
│ ├── FilterConfig.cs
│ └── RouteConfig.cs
│ ├── Scripts
│ ├── Content
│ └── ...
| ...
To use ASP.NET Core, you must remove all the files from the ContosoUniversity\App_Start
directory as well as ContosoUniversity\Global.asax*
files.
Bundling and minification changed in ASP.NET Core, so you need to remove the file ContosoUniversity\App_Start\BundleConfig.cs
. To replace it you use the BuildBundlerMinifier
nuget package to bundle and minify at build time.
-
Add the
BuildBundlerMinifier
package:cd ContosoUniversity dotnet add package BuildBundlerMinifier
-
Add a new file in the project directory
ContosoUniversity\bundleconfig.json
with the following contents to instructBuildBundlerMinifier
to create the necessary bundled files in thewwwroot
directory at build time.[ { "outputFileName": "wwwroot/css/styles.css", "inputFiles": [ "Content/**/!(*.min).css" ] }, { "outputFileName": "wwwroot/js/jquery.js", "inputFiles": [ "Scripts/jquery-1.10.2.js", "Scripts/jquery-1.10.2.intellisense.js" ] }, { "outputFileName": "wwwroot/js/bs-bundle.js", "inputFiles": [ "Scripts/bootstrap.js", "Scripts/respond.js" ] }, { "outputFileName": "wwwroot/js/modernizr.js", "inputFiles": [ "Scripts/modernizr-2.6.2.js" ] } ]
-
Remove
@Scripts.Render
and@Styles.Render
references (-
lines below) from all.cshtml
files and replace with the+
lines below. VS Code has built in support for regex in Find (CTRL-F
) then pressALT+R
to use regular expression mode and search for(~/Content)|(~/bundles)
. If you use Visual Studio it can be helpful to useFind
dialog like this:- @section Scripts { - @Scripts.Render("~/bundles/jqueryval") - } + <script src="~/js/jqueryval.js"></script>
- @Styles.Render("~/Content/css") + <link href="~/css/styles.css" rel="stylesheet" />
- @Scripts.Render("~/bundles/modernizr") + <script src="~/js/modernizr.js"></script>
- @Scripts.Render("~/bundles/jquery") + <script src="~/js/jquery.js"></script>
- @Scripts.Render("~/bundles/bootstrap") + <script src="~/js/bs-bundle.js"></script>
-
Delete
ContosoUniversity\App_Start\BundleConfig.cs
if you didn't already.
Routing and middleware in ASP.NET Core is configured in the new ContosoUniversity\Startup.cs
file that was added by the .NET Upgrade Assistant which is documented in App startup in ASP.NET Core.
-
Delete
ContosoUniversity\App_Start\RouteConfig.cs
andContosoUniversity\App_Start\FilterConfig.cs
. -
Delete
ContosoUniversity\Global.asax
andContosoUniversity\Global.asax.cs
. See this for more information.
The sample application uses the PagedList.Mvc
library which you must replace with PagedList.Core.Mvc
.
-
Replace the package
del "ContosoUniversity - Backup.csproj" dotnet remove package PagedList.Mvc dotnet add package PagedList.Core.Mvc
-
In the
ContosoUniversity\Controllers\StudentController.cs
controllers replace theusing
reference:- using PagedList; + using PagedList.Core;
-
Update the
ContosoUniversity\Views\Student\Index.cshtml
file to change the references:- @model PagedList.IPagedList<ContosoUniversity.Models.Student> - @using PagedList.Mvc; + @model PagedList.Core.IPagedList<ContosoUniversity.Models.Student> + @using PagedList.Core.Mvc;
-
Add the PagedList tag helper to the
ContosoUniversity\Views\_ViewImports.cshtml
file:@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers + @addTagHelper *, PagedList.Core.Mvc
-
Replace the
PagedListPager
component:- @Html.PagedListPager(Model, page => Url.Action("Index", - new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })) + <pager class="pager-container" list="@Model" asp-action="Index" asp-controller="Student" />
ASP.NET MVC Core uses different return result objects for the controller's action methods. Because there are many of these objects scattered throughout the ContosoUniversity\Controllers\
classes, to replace all malformed return results, we recommend that you look at the build errors table for your IDE. Look for errors in controllers action methods that are because of an unknown return type:
- return new StatusCodeResult(HttpStatusCode.BadRequest);
+ return new BadRequestResult();
and:
- return HttpNotFound();
+ return new NotFoundResult();
The TryUpdateModel
method is replaced by an async
method in .NET 5. To use this method, there are several changes you need to make to each of the controllers including adding a using, changing the method to return Task<ActionResult>
and waiting for the result, for example:
+using System.Threading.Tasks;
...
- public ActionResult EditPost(int? id)
+ public async Task<ActionResult> EditPost(int? id)
- if (TryUpdateModel(courseToUpdate, "",
- new string[] { "Title", "Credits", "DepartmentID" }))
+ // Note that you do not need to include the field names:
+ if (await TryUpdateModelAsync(courseToUpdate))
...
You must make minor change in the Bind
attribute in each of the controllers to remove the Include=
parameter from the Bind
attribute, for example:
- public ActionResult Create([Bind(Include = "CourseID,Title,Credits,DepartmentID")]Course course)
+ public ActionResult Create([Bind("CourseID,Title,Credits,DepartmentID")]Course course)
Because each of these is slightly different, it's best to search in your IDE for [Bind(Include
and manually edit each attribute.
The SelectList
object is now part of the Microsoft.AspNetCore.Mvc.Rendering
namespace, so you must update the using
directive to the new namespace in every controller where SelectList
is used, namely in the ContosoUniversity/Controllers/CourseController.cs
and ContosoUniversity/Controllers/DepartmentController.cs
files:
+using Microsoft.AspNetCore.Mvc.Rendering;
...
// GET: Department/Create
public ActionResult Create()
{
ViewBag.InstructorID = new SelectList(db.Instructors, "ID", "FullName");
return View();
}
In .NET 5, configuration in ASP.NET Core isn't read from the Web.config
configuration file, so you must move your connection string over to use one of the pluggable configuration providers which gives you more flexibility. However, the amount of flexibility will vary depending on the environment that you deploy the application to.
-
Open the
appsettings.Development.json
file and copy your connection string fromWeb.config
as follows:{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } - } + }, + "ConnectionStrings": { + "SchoolContext": "Data Source=[INSTANCE_IP];Initial Catalog=ContosoUniversity;User ID=[USER];Password=[PASSWORD];" + } +}
-
ASP.NET Core configures app behavior based on the runtime environment using an environment variable. Set the
ASPNETCORE_ENVIRONMENT
environment variable toDevelopment
so that it will load theappsettings.Development.json
file:set ASPNETCORE_ENVIRONMENT=Development
-
Delete the
Web.config
file.
The best pattern to use a common service like the database context in ASP.NET Core is to use Dependency Injection.
-
Add a constructor to the
SchoolContext
class in theContosoUniversity\DAL\SchoolContext.cs
file, with the connection string as a parameter.+ public SchoolContext(string connectString) : base(connectString) {}
-
To add the database context to the service container, add the following code to the
ConfigureServices
method in theContosoUniversity\Startup.cs
file:+ using ContosoUniversity.DAL; ... { options.UseMemberCasing(); }); + services.AddScoped<SchoolContext>(_ => + new SchoolContext(Configuration.GetConnectionString("SchoolContext")) + ); }
-
Change each of the
ContosoUniversity\controllers
to consume this injected service. Repeat this pattern for each controller as demonstrated withStudentController
:public class StudentController : Controller { - private SchoolContext db = new SchoolContext(); + private SchoolContext db = null; + + public StudentController(SchoolContext db) + { + this.db = db; + }
In each of the controller classes, make sure you change the name of the new constructor method to resemble the name of the class.
The application should now compile and run successfully as a .NET 5 application. To build and launch the migrated .NET 5 application, run the following command from the ContosoUniversity\
directory:
dotnet run
You see the following output, which shows the application listening on ports 5000 & 5001:
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:\repos\ContosoUniversity\ContosoUniversity
If for some reason you can't use one of these ports, an easy alternative is to instruct the dotnet
command to run on port 3333 instead:
dotnet run -- --urls=http://localhost:3333
You should now have your fully migrated .NET 5 application up and running again. The application should be connected to Google Cloud SQL for SQL Server just as the .NET Framework version was. Go ahead and poke around in the application to test the functionality more thoroughly.
Another benefit of moving to .NET 5 is that you can now run the application in a lightweight Linux container. With Linux containers you can avoid the it works on my machine paradigm by encapsulating all of your dependencies in a small, portable format that can be run anywhere that can host a Docker container, including Kubernetes or fully serverless platforms like Cloud Run.
The next step is to create a Dockerfile which runs in a .NET Docker container created by Microsoft.
Create the Dockerfile
file in the root solution directory. This directory is also where the ContosoUniversity.sln
file resides:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /source
COPY ./ContosoUniversity /source
RUN dotnet publish -r linux-x64 --self-contained true -c Release -o /deploy
FROM mcr.microsoft.com/dotnet/runtime-deps:5.0 AS runtime
WORKDIR /app
COPY --from=build /deploy .
# Default port for Cloud Run
ENV ASPNETCORE_URLS="http://0.0.0.0:8080"
ENTRYPOINT ["/app/ContosoUniversity"]
In this step you use a Docker multi-stage build. This guarantees that the build environment is always the same. The output of the build
stage is a self-contained executable that does not require .NET 5 to be installed, further reducing the image size and startup time. The runtime
stage copies only the runtime components necessary and sets a default URL to listen on as an environment variable. The ENTRYPOINT
is the name of the self-contained executable that was generated in the build
stage.
If you have Docker installed on your local machine you can build and start the container with the following commands from the solution directory where you created the Dockerfile
file:
docker build -t contosouniversity:v1 -f Dockerfile .
docker run -it contosouniversity:v1 -p 8080:8080
This command will run the application and expose port 8080 to the localhost
, so that you can launch a browser at http://localhost:8080
on your local machine to test.
Rather than running Docker locally, you can use the managed Cloud Build service to build the container and automatically push it to your Google Container Registry.
-
To enable Cloud Run to access your SQL Server instance, you need to configure the application's connection string with the instance's private IP address. If you already configured this, then you can skip this step. If you used the SQL Server instance's public IP address in your connection string, open the
appsettings.Development.json
file and change the IP address of the SQL Server instance to the instance's private IP address. -
Get your Google Cloud Project ID using the
gcloud
tool, for example:gcloud config list [compute] region = us-central1 [core] account = xyz@example.com project = my-sample-project
Don't worry if the project or region are not listed for you. If you haven't previously set your default project, log in to the Google Cloud Console and create your first project or get the name of an existing project.
-
Submit your artifacts to cloud build and tag the docker image. Replace
[PROJECT_ID]
with your project ID:gcloud builds submit --tag gcr.io/[PROJECT_ID]/contosouniversity:v1
Your complete Docker build now runs in the cloud and you should see the output of the build printed to your console while it runs.
Now that you've built your container and published it to Google Container Registry, you can deploy the application to Cloud Run.
-
Create a Serverless VPC Access connector to enable your Cloud Run service to connect to your Cloud SQL instance through your VPC. Configure the connector with the following settings:
- Name:
contoso-university
- Region:
us-central1
- Name:
-
Run the following commands to deploy the application to Cloud Run and enable everyone to access it:
gcloud run deploy contosouniversity --image gcr.io/[PROJECT_ID]/contosouniversity:v1 --platform managed --update-env-vars ASPNETCORE_ENVIRONMENT=Development --region us-central1 --allow-unauthenticated --vpc-connector contoso-university gcloud run services add-iam-policy-binding contosouniversity --member="allUsers" --role="roles/run.invoker" --region us-central1
Replace
[PROJECT_ID]
with your own project name. -
Copy the service URL from the output and open the URL in a browser. Click the Students tab to verify the application is able to query the SQL Server database.
For a complete tutorial on Cloud Run with C#, see Build and deploy a C# .Net Core service.
While your application is now deployed and running, one issue is that your database connection string in appsettings.json
is stored in plain text and is being shipped around with your source code. To fix this, in this section, you use Secret Manager to securely store the connection string. If you are using Visual Studio Code at this point, you can use the Cloud Code extension to easily create and manage secrets.
Follow the next steps to create the secret, according to whether you use Visual Studio code or not.
NOTE: Next, you create a secret, but are not asked to remove the existing connection string from the appsettings.Development.json
file. This is so that you can test the application locally while developing. Later in this tutorial, you configure it so that the appsettings.Development.json
file is excluded from the build process and from the remote git repository, and is only available locally on your machine.
-
Copy the
connectionStrings
block fromappsettings.Development.json
. -
Install the extension and click on the Cloud Code - Secret Manager icon:
-
Click to create a Secret and name it
connectionstrings
(use lowercase letters). -
In the Enter a value text box, add a leading and trailing curly braces and then paste the text you copied between the two curly braces. The value should resemble the following:
{ "ConnectionStrings": { "SchoolContext": "Data Source=[INSTANCE_IP];Initial Catalog=ContosoUniversity;User ID=[USER];Password=[PASSWORD];" } }
-
Click Create Secret.
-
Copy the
connectionStrings
block fromappsettings.Development.json
. -
Follow the instructions for creating a secret in the Google Cloud Console. Use the following information for the secret:
- Name:
connectionstrings
(use lowercase letters). - Secret value: Add a leading and trailing curly braces and paste the text you copied between the two curly braces. The value should resemble the following:
{ "ConnectionStrings": { "SchoolContext": "Data Source=[INSTANCE_IP];Initial Catalog=ContosoUniversity;User ID=[USER];Password=[PASSWORD];" } }
- Name:
-
Click Create Secret.
There are multiple ways to read the secrets from your application, including using the SDK API directly. However, Cloud Run has built-in support for Secrets which mount into the container as files at runtime.
In this section, you use Cloud Run to mount the connection string to: /app/secret/appsettings.json
and add code for ASP.NET Core to load configuration files from the secret
folder if it exists.
-
Add the following code to the
ContosoUniversity\Program.cs
file:public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration(AddSecretConfig) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
-
Still in the
ContosoUniversity\Program.cs
file, add the implementation ofAddSecretConfig
:private static void AddSecretConfig(HostBuilderContext context, IConfigurationBuilder config) { const string secretsPath = "secrets"; var secretFileProvider = context.HostingEnvironment.ContentRootFileProvider .GetDirectoryContents(secretsPath); if (secretFileProvider.Exists) foreach (var secret in secretFileProvider) config.AddJsonFile(secret.PhysicalPath, false, true); }
-
Give the
Secret Manager Secret Accessor
role to the Cloud Run service account. For instructions, see the Cloud run documentation.NOTE: By default, Cloud Run revisions execute as the Compute Engine default service account.
In this section, you centralize logging and monitoring. It's common for Cloud Native applications to adopt the Twelve-Factor App pattern and treat logs as streams. ASP.NET Core by default writes logs to stdout
as desired. By default, all Cloud Run logs written to stdout
by the container will be available in Cloud Logging. However, structured logging allows you to make more sense of the logs, and enables easier querying, with machine and human readability.
There are several ways to get ASP.NET to automatically structure the logs without changing your logging code. In this section you will enable structured logging using the Google.Cloud.Diagnostics.AspNetCore
package.
-
Add the package to your project
dotnet add package Google.Cloud.Diagnostics.AspNetCore
-
Modify
ContosoUniversity\Program.cs
to use the new library:+using Google.Cloud.Diagnostics.AspNetCore; ... public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration(AddSecretConfig) .ConfigureWebHostDefaults(webBuilder => { + if (webBuilder.GetSetting("ENVIRONMENT") == "Production") + { + webBuilder.UseGoogleDiagnostics(); + } webBuilder.UseStartup<Startup>(); });
The application uses Cloud Logging only for production environments, such as when the application is deployed to Cloud Run. The
ENVIRONMENT
setting is controlled by theASPNETCORE_ENVIRONMENT
environment variable that you set earlier. If you don't set this variable, ASP.NET Core uses the valueProduction
By default.
At this stage, you're now using Cloud Build to build and publish your container to Container Registry, Secret Manager to store the connection string, and Cloud Run to run your application. To pull all of these actions together, in this section you create the cloudbuild.yaml
file to automate your build and deployment. Cloud Build can even be configured to run when you push to your git repository, for example to enable continuous integration and continuous deployment (CI/CD).
-
Ensure you have the proper permissions for Cloud Build to deploy to Cloud Run. For instructions on how to enable Service Account permissions, see the Deploying to Cloud Run How-to Guide:
-
Alternatively, open Cloud Shell and set permissions with the following script:
PROJECT_ID=`gcloud config list --format 'value(core.project)' 2>/dev/null` PROJECT_NUMBER=`gcloud projects describe $PROJECT_ID --format='value(projectNumber)'` gcloud projects add-iam-policy-binding $PROJECT_ID \ --member "serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \ --role roles/run.admin gcloud iam service-accounts add-iam-policy-binding \ $PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --member "serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \ --role "roles/iam.serviceAccountUser"
-
Create
cloudbuild.yaml
in the solution directory, as shown in the following code:steps: # Build the container image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/contosouniversity:$BUILD_ID', '.'] # Push the container image to Container Registry - name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/$PROJECT_ID/contosouniversity:$BUILD_ID'] # Deploy container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: - 'beta' - 'run' - 'deploy' - 'contosouniversity' - '--image' - 'gcr.io/$PROJECT_ID/contosouniversity:$BUILD_ID' - '--region' - 'us-central1' - '--platform' - 'managed' - '--allow-unauthenticated' - '--update-secrets=/app/secrets/appsettings.json=connectionstrings:latest' - '--vpc-connector' - 'contoso-university' images: - gcr.io/$PROJECT_ID/contosouniversity:$BUILD_ID
Cloud Build will automatically substitute the
$PROJECT_ID
and$BUILD_ID
when you run it. -
To prevent the gcloud command from including binaries and other unrequired files in the build process, can create a
.gitignore
file, and set its content to the following:.vscode/ **/bin/ **/obj/ **/wwwroot/ **/appsettings.Development.json *.csproj.user # Exclude git history and configuration. .git/ .gitignore
-
Submit the build from the solution directory:
gcloud builds submit
-
Run the following command to get the newly deployed service URL. Open the URL in a browser and then click the Students tab to verify the application is able to query the SQL Server database.
gcloud run services describe contosouniversity --region us-central1 --format="value(status.url)"
- Converting to .NET Core too much work for your workload? Check out building a Windows Container and deploying to GKE with no code changes.