Building Cross platform Applications with .NET Core - p-patel/software-engineer-knowledge-base GitHub Wiki

https://app.pluralsight.com/library/courses/dotnet-core-building-cross-platform-applications/

Course Overview

  • Build console apps, services and web apps

Building Console Apps

Overview

  • Build/run on a variety of platforms
  • Switch from project.json (.NET Core RC versions) to MSBuild (.NET Core 1.0 onwards) tooling
  • .NET Core is open-source

The State of .NET Core

  • Runtime vs SDK/Tools
  • SDK refers to just the dotnet CLI
  • .NET Core 1.2/2.0 - netstandard 2.0 (runtime)
  • project.json -> MSBuild VS2017 (SDK)
  • Note: Additions to .NET Core 2.0 e.g. .NET Standard 2.0 support, ASP.NET Core Razor pages, MSBuild support

Choosing Development Tools

  • tools available for cross-platform .NET Core application dev
  • single platform: VS Studio 2017 and later, VS Studio for Mac
  • cross platform: VS Code, Jet Brains Rider, dotnet cli
  • no issue in developers using different platforms to contribute to a project, MSBuild tooling is consistent cross-platform

How To Get The Latest SDK Builds

  • See Microsoft .NET Core website

Creating a Console App with dotnet new

  • creating an app that checks links are working on a webpage
  • dotnet new -h and dotnet new console

The New .NET Core MSBuild Project System

  • cf. project.json (old .NET Core config file) with new MSBuild .csproj file
  • project.json no longer exists but global.json can still be used to override config (e.g. specify .net core version to use)
  • dotnet --version displays the version of .NET Core project is using

The Goal Is A Clean MSBuild Project File

  • The cleaner .csproj file aims to match the simplicity of the previous project.json file
  • This is achieved by development of MSBuild which can handle the simpler, cleaner .csproj files

Build and Run the Console App on a Mac

  • dotnet restore to restore package dependencies
  • dotnet build (optional) to build app
  • dotnet run builds and runs app
  • tree to view current directory hierarchy
  • obj\project.assets.json replaces previous project.lock.json file

Build and Run on Windows

  • use the same commands as above for Mac (predictably!)

Build and Run On Linux via Docker and Custom Docker Images

  • docker run -it microsoft/dotnet:latest runs a docker container with image containing .NET Core toolchain
  • docker run -it microsoft/dotnet:1.0.3-sdk-msbuild run specified .NET Core version
  • docker run -it -v $(pwd):/console microsoft/dotnet:1.0.3-sdk-msbuild mount host machine's volume within the docker container (e.g. to access source code)
  • can download and customise an existing docker file as required
  • docker build -t dotnet-sdk-preview4 -f Dockerfile.preview4 . builds a docker image from a docker file in the current dir
  • docker images | grep dotnet list available docker images
  • docker run --rm -it -v $(pwd)/CheckLinksConsole:/console dotnet-sdk/preview4 - runs container with the specified image, removing the container after execution completes, map the volume (as previous)
  • run the same commands to restore, build and run console app
  • Windows containers see Nano Server and Server Core which can be used with a Windows container

You Can Work With Both An IDE and the dotnet CLI

  • dotnet CLI was originally built to work with project.json, but since being replaced with the new .csproj file it mostly now just 'shells' out to MSBuild
  • SDKs used by VS.NET/VS Code work directly with MSBuild, dotnet CLI can be used by other editors/IDEs or can be used directly
  • The SDK provides core functionality needed by .NET core projects - MSBuild tasks and project templates - used by VisualStudio and CLI

Creating a Solution File with Visual Studio

  • You can open the project created above in VS.NET and save the solution file which can then be opened by e.g. VS.NET for Mac

You Can Create Projects with an IDE Too

  • You can use the editor to create .NET Core projects, although there appear to be more options available when using the CLI (which has been been developed more in the open with it being open source)

Finding an API to Make a Web Request

Using an API Bundled with .NET Core to Make Web Requests

  • Can check Dependencies in VS.NET to ensure required package is already included or add it if required
  • VS.NET will use SDK to build and then run app

Is This NuGet Package Compatible with .NET Core?

  • Search for NuGet packages on https://www.nuget.org
  • Best Case - package supports .NET Standard
  • Can also use PackageTargetFallback to use .NET Framework packages if it is known to work with .NET Core (test!)
  • Use a fork that supports .NET Standard (or .NET Core)
  • Create own fork if one doesn't exist
  • .NET Standard 2.0 - compatible with .NET Framework packages! (provides support for full BCL) - see https://devblogs.microsoft.com/dotnet/introducing-net-standard/. .NET Standard 2 provides a compatiblity shim for .NET Framework binaries
  • use dotnet-apiport (command line tool) to scan a DLL to analyse whether it is compatible

Extracting Links With HtmlAgilityPack

  • use HtmlAgilityPack to return links from specified webpage as IEnumerable and write to screen

Adding Packages in the Project File or with the dotnet CLI

  • Use package manager in VS.NET
  • Manually add to .csproj file
  • Use dotnet [add|remove] to add packages from CLI (similar to npm install)

Running the Latest Code on Other Platforms

  • on Windows using CLI dotnet run
  • on Mac using CLI dotnet run
  • this approach is distributing source code and building on each platform

Publishing to Multiple Platforms

Introduction

  • Distributing compiled apps to run and test across target platforms
  • Setting up CI to automate testing
  • Writing unit tests to gain confidence

Deployment Options

  • Framework-dependent deployment, Self contained deployment, Image deployment
  • Use dotnet publish
  • Framework dependent deployment - publish once, run anywhere
  • Self contained deployment - different self contained deployment for each platform that contains platform-specific run-time
  • Image deployment - different image for each platform (requires no pre-requisites on target machine except container)

dotnet publish to Create a Framework Dependent Deployment

  • dotnet restore, dotnet build, dotnet run - build is for use to build app for testing purposes on the same machine, e.g. *.runtimeconfig.dev.json contains a machine-specific path to the local package cache
  • dotnet publish to deploy to a different computer and cross-platform, which creates a '\publish` folder and contains all dependencies rather than configuration containing a path to the local package cache

Diff dotnet build vs. dotnet publish Output

  • use a diff tool to compare build output dir with publish output dir (publish dir contains additional dependencies rather than relying on them being cached and available locally)

FDD to Windows

  • dotnet <filename> in a copy of the publish directory on Windows will run the app. Note this requires the .NET Core runtime to be available on the target machine

FDD to Linux via Docker

...

Automated Testing Across Platforms

Creating a Test Project

  • dotnet new -t xunittest create a test project

Adding a dotnet new Project to a Solution

  • add project to solution from within VS.NET

Where I See An Opportunity to Benefit from Automated Testing

  • add tests around the links retrieval code in LinkChecker

Project References Are Much More Concise

  • no longer contain GUID in the .csproject file

dotnet add - To Add a Project Reference

  • dotnet add reference <.csproj file> add a project reference to a project using the CLI
  • also use to add nuget packages

Running Tests in Your IDE and Platform of Choice

  • run tests using VS.NET

dotnet test to Execute Tests on Multiple Platforms

  • run test using CLI dotnet test from within test project dir

How Much Testing Making Sense Per Platform

  • decide platforms to be supported
  • Platform Agnostic
  • creating .NET Standard libraries means it should be platform agnostic
  • Your Code: develop on preferred runtime, CI on production runtime
  • Not Your Code: smoke test production runtime
  • Platform Specific (e.g. reading files)
  • Your Code: develop & CI on targeted runtime
  • Not Your Code: if not well tested - treat as your code; otherwise smoke test production runtimes

Working With Files

Introduction

  • Working with files with cross-platform .NET Core apps

The System.IO namespace

Getting a Temporary Filename

Writing to Databases

There are plenty of third party ORMs too

Cross-platform SQL Based Migrations with Flyway

  • Flyway - see Wes Higbee's Flyway courses on PluralSight

Configuring the Connection String

You Do Not Need an IRepository

  • Unit test, integration test (with in-memory db) and smoke tests
  • You are not going to swap out your ORM or DB overnight!

Building and Deploying Services

Introduction

  • Building a service that runs in the background

Adding Hangfire for Background Jobs

Injecting Dependencies

Sharing a Single LoggerFactory

  • The existing application logging and Hangfire logging currently use different LoggerFactory instances which is why Hangfire logs are not currently being logged. They need to be configured to use the same LoggerFactory

Telling ASP.NET Core to Use Your LoggerFactory

  • use WebHostBuilder().UseLoggerFactory(loggerFactory) to specify an existing ILoggerFactory for the web host to use. This LoggerFactory will then be used by all services for logging.

How to Explicitly Access Services Like ILoggerFactory

  • How does ASP.NET Core/Hangfire get access to ILoggerFactory instance?
  • .AddSingleton(), .AddTransient(), .AddScoped() - register services in the ServiceCollection
  • var loggerFactory = host.Services.GetService<ILoggerFactory>(); - get a registered service

Looking at Registered Services

  • in Startup class, ConfigureServices(IServiceCollection services) method - view registered services
  • see Hangfire's AddHangfire() method to see the services it registers

Resolving Other Services like Logger of T

  • host.Services.GetService<JobActivator>(), host.Services.GetService<ILogger<Program>>() - resolve a service by type
  • when a framework integrates with dependency injection there will be a XYZServiceCollectionExtensions class as a naming convention

...

Injecting Dependencies

Introduction

  • A framework (like previous logging and configuration)

Sharing a Single LoggerFactory

  • Use DI to share a single LoggerFactory across an application
  • Asp.NET Core builder class will use LoggerFactory passed to it in WebHostBuilder().UseLoggerFactory() or otherwise create a LoggerFactory

How to Explicitly Access Services like ILoggerFactory

  • services is just a collection of services registered in the DI container
  • host.Services.GetService<ILoggerFactory>(); gets ILoggerFactory instance

Looking at Registered Services

  • step over configuration in ConfigureServices() method of ASP.NET Core app in Startup.cs to see services being registered
  • e.g. LoggingServiceCollectionExtensions.AddLogging() registers for ILoggerFactory and typeof(ILogger<>) dependencies

Fulfiling Dependencies of Dependencies

  • DI framework will fulfil dependencies of dependencies as required during construction

The Three Components of Service Registration

  • 3 components of service registration: service type, implementation (instance, type or factory) and lifetime (singleton, scoped (scope can be defined but is commonly a web request in an ASP.NET Core web app) and transient)
⚠️ **GitHub.com Fallback** ⚠️