ASP.NET MVC on Platform.sh

Goal

To deploy an ASP.NET core application on Platform.sh.

Preparation

You will need:

Problems

Configuring .NET applications to run on Platform.sh only takes slight modifications to the application itself (mostly so that it knows to look for Platform.sh-specific environment variables) along with the addition of our configuration YAML files that define its builds, request handling, and its services.

This example goes through the steps necessary to modify the simple “Getting Started” ASP.NET MVC application tutorial to deploy on Platform.sh

Steps

1. Create a template ASP.NET MVC project

The dotnet utility comes installed with the .NET Core SDK, and can be used to quickly generate an ASP.NET template application with the dotnet new command. Since this example follows the ASP.NET MVC “Getting started” guide linked above, run the command below to generate a Model View Controller (MVC) template for the ASP.NET framework:

dotnet new mvc -o PlatformAspNetCore

Once the template files are created in the new PlatformAspNetCore directory, run a local web server and view the application:

cd PlatformAspNetCore
dotnet run

Note
The getting started guide also recommends that you run dotnet dev-certs https --trust in order to trust a development certificate for local development. A certificate was likely created when following the above steps, but the dotnet utility will prompt if it is missing.

Initialize the PlatformAspNetCore repository and commit the changes:

git init
git add .
git commit -m "Create an MVC app."

2. Configure for Platform.sh

In order to deploy the application, a set of Platform.sh-specific configuration files will need to be added to the project.

Add a .platform directory to the project root that contains two empty files - routes.yaml and services.yaml.

mkdir .platform
touch .platform/routes.yaml
touch .platform/services.yaml

The first file, routes.yaml, defines how incoming requests to the application are handled by Platform.sh. A very simple routes.yaml will work for this application, and looks like this:

# .platform/routes.yaml

"https://www.{default}/":
    type: upstream
    upstream: "app:http"

"https://{default}/":
    type: redirect
    to: "https://www.{default}/"

A route will be generated for every environment (branch) at the upstream domain www.{default}, which is directed at the application with the name app. A redirect route will handle requests to the application without the www prefix to that same application.

Typically, the services.yaml file would be where you would define some of Platform.sh’s managed services, such as a database. This simple application doesn’t include any services, so it can remain empty.

Note: Services and ASP.NET Core

Consult the original getting started guide alongside the ASP.NET Core Template to see how a DbContext that reads from the PLATFORM_RELATIONSHIPS environment variable can be used to connect to a database.

The final configuration file necessary to deploy on Platform.sh is the .platform.app.yaml file, which needs to be in the project root.

touch .platform.app.yaml

This file will define how the application will be built and deployed on Platform.sh. Name the application app to match the routes.yaml configuration and define its persistent disk.

Specify the .NET runtime dotnet with a version that Platform.sh supports.

name: app

type: dotnet:2.2

disk: 512

Next, define how the application builds on Platform.sh in the build hook.

hooks:
  build: |
    set -xe
    dotnet publish --output "$PLATFORM_OUTPUT_DIR" -p:UseRazorBuildServer=false -p:UseSharedCompilation=false

For simple applications like this one, using the dotnet publish default framework-dependent deployment method is sufficient for building in .NET containers. Pass to that command the environment variable PLATFORM_OUTPUT_DIR, the output directory for compiled languages at build time on Platform.sh, as the output directory. In this case, that output directory will be the final application directory, /app.

Typically, .NET builds will start a collection of build servers, which can be helpful for repeated builds. On Platform.sh, however, if this process is not disabled, the build process will not finish until the idle timeout is reached. As a result, it’s recommended to include -p toggles that disable the Razor compiler for dynamic cshtml pages (UseRazorBuildServer) and the .NET msbuild compiler (UseSharedCompilation).

Finally, define the start command to launch the app

web:
  commands:
    start: 'dotnet PlatformshAspNetCore.dll'

which runs the built application PlatformAspNetCore using the dotnet utility directly.

The final minimal .platform.app.yaml file looks like this:

name: app

type: dotnet:2.2

disk: 512

hooks:
  build: |
    set -xe
    dotnet publish --output "$PLATFORM_OUTPUT_DIR" -p:UseRazorBuildServer=false -p:UseSharedCompilation=false

web:
  commands:
    start: 'dotnet PlatformshAspNetCore.dll'

Then commit the changes.

git add .
git commit -m "Add Platform.sh configuration files."

3. Modify the MVC application for Platform.sh

Once the Platform.sh configuration files have been added, the ASP.NET MVC project will contain the following:

.
├── .platform/
├── bin/
├── Controllers/
├── Models/
├── obj/
├── Properties/
├── Views/
├── wwwroot/
├── .platform.app.yaml
├── appsettings.Development.json
├── appsettings.json
├── PlatformshAspNetCore.csproj
├── Program.cs
└── Startup.cs

The Program.cs files acts as the entry point for the application. It defines the web server, and it will need to be modified to listen to the correct ports and sockets on Platform.sh once it’s deployed. These values are accessible as environment variables on Platform.sh projects.

Modify the Main method to assign CreateWebHostBuilder(args) to its own variable builder. Then use the Kestrel web server implementation for ASP.NET Core to define those environment variables for the server.

// Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace PlatformshAspNetCore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = CreateWebHostBuilder(args);

            builder.UseKestrel(options =>
            {
                var port = Environment.GetEnvironmentVariable("PORT");
                if (port != null && Int16.TryParse(port, out var portNum))
                {
                  options.ListenLocalhost(portNum);
                }

                var socket = Environment.GetEnvironmentVariable("SOCKET");
                if (socket != null)
                {
                  options.ListenUnixSocket(socket);
                }
            });

            builder.Build().Run();
        }

        private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();
    }
}

Then just commit the changes.

git add .
git commit -m "Platformify the app."

4. Push to Platform.sh

That’s it! The template ASP.NET MVC application has now been completely configured to build and deploy on Platform.sh. All that’s left is to create a project and push it there.

Create a project with the CLI using platform project:create, and then use the resulting project ID to set the project as a remote for the local repository.

platform project:set-remote <project ID>

Then just commit the changes and push to Platform.sh.

git push platform master

When the build has completed, visit the deployed application through the management console under “URLs” for the Master environment or directly via the CLI using the command platform url.

Conclusion

In this tutorial you have seen how to:

  • Create a simple template ASP.NET MVC application using the dotnet utility
  • Modify that application to run on Platform.sh

.NET applications will have similar considerations in order to run on Platform.sh, so you can use this guide to know what needs to be modified on other projects.

Although we didn’t cover how to configure services to work with the application here, you can consult our ASP.NET Core template to get a better idea of how to go about doing so.