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/
- Build console apps, services and web apps
- 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
- 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
- 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
- See Microsoft .NET Core website
- creating an app that checks links are working on a webpage
-
dotnet new -h
anddotnet new console
- cf. project.json (old .NET Core config file) with new MSBuild .csproj file
-
project.json
no longer exists butglobal.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 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
-
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 previousproject.lock.json
file
- use the same commands as above for Mac (predictably!)
-
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
- 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
- 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 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)
- Use https://apisof.net to find APIs and their framework compatibility or use .NET Core API Reference or use https://packagesearch.azurewebsites.net
- 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
- 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
- use HtmlAgilityPack to return links from specified webpage as IEnumerable and write to screen
- Use package manager in VS.NET
- Manually add to .csproj file
- Use
dotnet [add|remove]
to add packages from CLI (similar tonpm install
)
- on Windows using CLI
dotnet run
- on Mac using CLI
dotnet run
- this approach is distributing source code and building on each platform
- Distributing compiled apps to run and test across target platforms
- Setting up CI to automate testing
- Writing unit tests to gain confidence
- 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 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
- 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)
-
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
...
-
dotnet new -t xunittest
create a test project
- add project to solution from within VS.NET
- add tests around the links retrieval code in
LinkChecker
- no longer contain GUID in the .csproject file
-
dotnet add reference <.csproj file>
add a project reference to a project using the CLI - also use to add nuget packages
- run tests using VS.NET
- run test using CLI
dotnet test
from within test project dir
- 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 with cross-platform .NET Core apps
- Flyway - see Wes Higbee's Flyway courses on PluralSight
- See Configuring a DbContext - https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
- Unit test, integration test (with in-memory db) and smoke tests
- You are not going to swap out your ORM or DB overnight!
- Building a service that runs in the background
- 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
- 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 does ASP.NET Core/Hangfire get access to ILoggerFactory instance?
-
.AddSingleton()
,.AddTransient()
,.AddScoped()
- register services in theServiceCollection
-
var loggerFactory = host.Services.GetService<ILoggerFactory>();
- get a registered service
- in
Startup
class,ConfigureServices(IServiceCollection services)
method - view registered services - see Hangfire's
AddHangfire()
method to see the services it registers
-
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
...
- A framework (like previous logging and configuration)
- 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
-
services
is just a collection of services registered in the DI container -
host.Services.GetService<ILoggerFactory>();
getsILoggerFactory
instance
- step over configuration in
ConfigureServices()
method of ASP.NET Core app inStartup.cs
to see services being registered - e.g.
LoggingServiceCollectionExtensions.AddLogging()
registers forILoggerFactory
andtypeof(ILogger<>)
dependencies
- DI framework will fulfil dependencies of dependencies as required during construction
- 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)