Restart .NET Core Web Application on FTP upload

Yes, Continuous Delivery is a thing; but what about teeny-weeny side projects? Or, even worse, what if a CD isn’t available?

Instead of copy/past and start/stop the remote Web-Server, one could simply use the integrated Visual Studio FTP upload + some hacky scripts to detect file changes, triggering a dotnet application restart.

Step 1 – Let’s make a step back

In order to get things up and running, what prerequisite do we need?

  • An FTP Server (install + setup not covered in this article)
  • An up and running ASP .NET Core Runtime
  • A Visual Studio FTP publishing profile, featuring “Delete all existing files prior to publish”

To keep things simple, the FTP directory and the .NET Core application are located within the same path. Otherwise, one would have to replicate all changes onto the .NET Core application’s folder as well. In my case, the FTP and .NET Core application have been placed to “/home/pi/dbct/

ASP.NET Core Startup Configuration

After a system reboot we may still want your page up and running. Thus, we add a new systemd service entry.

sudo nano /etc/systemd/system/webapp.service
                                      
[Unit]
Description=Description of the webapp

[Service]
WorkingDirectory=/home/pi/dbct/ #path of the webapp
ExecStart=/usr/bin/dotnetcore/dotnet /home/pi/dbct/DBCT.WebApp.dll --urls=http://0.0.0.0:5000 #.net core application to launch
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=30
SyslogIdentifier=dbct-webapp
User=pi
Environment=ASPNETCORE_ENVIRONMENT=Development

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable webapp.service
sudo systemctl restart webapp.service

If the configuration has been done properly, we can verify whether the application is currently executing by

sudo systemctl status webapp.service

● webapp.service - Description of the webapp
   Loaded: loaded (/etc/systemd/system/webapp.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-03-27 14:36:14 GMT; 2h 3min ago
 Main PID: 1572 (dotnet)
    Tasks: 17 (limit: 4915)
   Memory: 42.3M
   CGroup: /system.slice/webapp.service
           └─1572 /usr/bin/dotnetcore/dotnet /home/pi/dbct/DBCT.WebApp.dll --urls=http://0.0.0.0:5000

Mar 27 14:36:18 bernd dbct-webapp[1572]: info: Microsoft.Hosting.Lifetime[0]
Mar 27 14:36:18 bernd dbct-webapp[1572]:       Now listening on: http://0.0.0.0:5000
Mar 27 14:36:18 bernd dbct-webapp[1572]: info: Microsoft.Hosting.Lifetime[0]
Mar 27 14:36:18 bernd dbct-webapp[1572]:       Application started. Press Ctrl+C to shut down.
Mar 27 14:36:18 bernd dbct-webapp[1572]: info: Microsoft.Hosting.Lifetime[0]
Mar 27 14:36:18 bernd dbct-webapp[1572]:       Hosting environment: Development
Mar 27 14:36:18 bernd dbct-webapp[1572]: info: Microsoft.Hosting.Lifetime[0]
Mar 27 14:36:18 bernd dbct-webapp[1572]:       Content root path: /home/pi/dbct
Mar 27 16:01:41 bernd dbct-webapp[1572]: warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
Mar 27 16:01:41 bernd dbct-webapp[1572]:       Failed to determine the https port for redirect.

Add the hacky script

Our goal is to restart the webapp.service after a FTP deployment. Hence, we need to detect any file-changes within the FTP directory. Here the inotifywait tool comes in pretty handy. It allows us to watch for file/folder changes and fires back any detected read/write event.

sudo apt-get update
sudo apt-get install inotify-tools
sudo nano /home/pi/dbctdeploy.sh

We create a file “dbctdeploy.sh”, responsible for change detection and service restarts. To avoid “spaming” service restarts, we only wan’t to listen for changes when a certain file (in this case the application itself) does exist. Plus, a service restart without an existing application doesn’t make much sense either.

while :
do

        # inotifywait will exit when the file doesn't exist.
        # thus, wait till there is a file available.

        while :
        do

                if [ -f "/home/pi/dbct/DBCT.WebApp.dll" ]
                then
                        break;
                else
                        sleep 10
                fi
        done

        sudo systemctl stop webapp.service
        sleep 2
        sudo systemctl start webapp.service

        echo 'Webapp.service has been restarted'

        sudo inotifywait -q -e delete -r /home/pi/dbct/*
done

To finish our ridiculous setup, we register the shell script to our system startup sequence.

sudo nano /etc/systemd/system/webappftp.service

[Service]
WorkingDirectory=/home/pi/
ExecStart=/bin/sh /home/pi/dbctdeploy.sh
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable webappftp.service
sudo systemctl start webappftp.service

Again, we are able to validate whether the shell script has been started successfully, by executing the command

sudo systemctl status webappftp.service

  Loaded: loaded (/etc/systemd/system/webappftp.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-03-27 14:31:44 GMT; 5h 39min ago
 Main PID: 362 (sh)
    Tasks: 3 (limit: 4915)
   Memory: 4.7M
   CGroup: /system.slice/webappftp.service
           ├─ 362 /bin/sh /home/pi/dbctdeploy.sh
           ├─1576 sudo inotifywait -q -e delete -r /home/pi/dbct/DBCT.Persistence.dll /home/pi/dbct/DBCT.Persistence.pdb
           └─1581 inotifywait -q -e delete -r /home/pi/dbct/DBCT.Persistence.dll /home/pi/dbct/DBCT.Persistence.pdb /hom

Mar 27 14:36:14 bernd sudo[1566]:     root : TTY=unknown ; PWD=/home/pi ; USER=root ; COMMAND=/bin/systemctl start webap
Mar 27 14:36:14 bernd sudo[1566]: pam_unix(sudo:session): session opened for user root by (uid=0)
Mar 27 14:36:14 bernd sudo[1566]: pam_unix(sudo:session): session closed for user root
Mar 27 14:36:14 bernd sh[362]: Webapp.service has been restarted
Mar 27 14:36:14 bernd sudo[1576]:     root : TTY=unknown ; PWD=/home/pi ; USER=root ; COMMAND=/usr/bin/inotifywait -q -e
Mar 27 14:36:14 bernd sudo[1576]:     root : (command continued) /home/pi/dbct/Microsoft.CodeAnalysis.CSharp.Workspaces.
Mar 27 14:36:14 bernd sudo[1576]:     root : (command continued) /home/pi/dbct/Microsoft.Extensions.Configuration.dll /h
Mar 27 14:36:14 bernd sudo[1576]:     root : (command continued) /home/pi/dbct/Microsoft.VisualStudio.Web.CodeGeneration
Mar 27 14:36:14 bernd sudo[1576]:     root : (command continued) /home/pi/dbct/appsettings.Development.json /home/pi/dbc
Mar 27 14:36:14 bernd sudo[1576]: pam_unix(sudo:session): session opened for user root by (uid=0)

That’s it. Our self-made, hacky CD with FTP deployment is ready for “production”. Ensure that everything is working by a system restart (sudo shutdown -r 0)

Hinterlasse einen Kommentar

Please Login to comment
  Subscribe  
Notify of