.Net core
.NET Core to develop console or Web applications. .NET Core is a set of runtime, library and compiler components that allow you to create apps that run on Windows, macOS and Linux.
.NET Core has the following characteristics:
- Cross-platform: Runs on Windows, macOS, and Linux operating systems.
- Consistent across architectures: Runs your code with the same behavior on multiple architectures, including x64, x86, and ARM.
- Command-line tools: Includes easy-to-use command-line tools that can be used for local development and in continuous-integration scenarios.
- Flexible deployment: Can be included in your app or installed side-by-side (user-wide or system-wide installations). Can be used with Docker containers.
- Compatible: .NET Core is compatible with .NET Framework, Xamarin, and Mono, via .NET Standard.
Open source: The .NET Core platform is open source, using MIT and Apache 2 licenses. .NET Core is a .NET Foundation project.
- Supported by Microsoft: .NET Core is supported by Microsoft, per .NET Core Support.
- Supported languages: C#, Visual Basic, and F# languages can be used to write applications and libraries for .NET Core.
These components are distributed in the following ways:
- .NET Core Runtime -- includes the .NET Core runtime and framework libraries.
- ASP.NET Core Runtime -- includes ASP.NET Core and .NET Core runtime and framework libraries.
- .NET Core SDK -- includes the .NET Core CLI, ASP.NET Core runtime, and .NET Core runtime and framework.
The major differences between .NET Core and the .NET Framework:
- App-models -- .NET Core doesn't support all the .NET Framework app-models. In particular, it doesn't support ASP.NET Web Forms and ASP.NET MVC, but it supports ASP.NET Core MVC. And starting with .NET Core 3.0, .NET Core also supports WPF and Windows Forms on Windows only.
- APIs -- .NET Core contains a large subset of .NET Framework Base Class Library, with a different factoring (assembly names are different; members exposed on types differ in key cases). In some cases, these differences require changes to port source to .NET Core. For more information, see The .NET Portability Analyzer. .NET Core implements the .NET Standard API specification.
- Subsystems -- .NET Core implements a subset of the subsystems in the .NET Framework, with the goal of a simpler implementation and programming model. For example, Code Access Security (CAS) isn't supported, while reflection is supported.
- Platforms -- The .NET Framework supports Windows and Windows Server while .NET Core also supports macOS and Linux.
- Open Source -- .NET Core is open source, while a read-only subset of the .NET Framework is open source.
https://docs.microsoft.com/pt-pt/dotnet/core/docker/building-net-docker-images
https://msdn.microsoft.com/en-us/library/ff361664(v=vs.110).aspx
.NET Core is an open-source, general-purpose development platform maintained by Microsoft and the .NET community on GitHub. It's cross-platform (supporting Windows, macOS, and Linux) and can be used to build device, cloud, and IoT applications.
Dependency Injection is used similar to Spring.
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.
A dependency is any object that another object requires.
https://dotnet.microsoft.com/download/dotnet-core/3.0
SDK 3.0.102
- Visual Studio support: Visual Studio 2019 (v16.3 or later)
- Included runtimes
- .NET Core Runtime 3.0.2 (The .NET Core Runtime contains just the components needed to run a console app.)
- ASP.NET Core Runtime 3.0.2 (ASP.NET Core Runtime enables you to run existing web/server applications.)
- Desktop Runtime 3.0.2 (run existing Windows desktop applications.)
- Language support C# 8.0 F# 4.7
- OS: Linux macOS Windows
Dotnet core commands (dotnet core cli - command line interface) (scafolding, prepare projects).
dotnet new console dotnet run
https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-1
In browser tutorial
Sample hello world
. ├── appSolution.sln ├── Dockerfile ├── myApp │ ├── myApp.csproj │ └── Program.cs ├── myLib │ ├── Class1.cs │ └── myLib.csproj ├── myLibTests │ ├── myLibTests.csproj │ └── UniTest1.cs
Dockerfile
FROM microsoft/dotnet:2.0-sdk WORKDIR /app RUN apt-get update RUN apt-get install net-tools procps vim nano -y RUN mkdir -p /app/myApp RUN mkdir -p /app/myLib RUN mkdir -p /app/myLibTests ADD myApp/* /app/myApp/ ADD myLib/* /app/myLib/ ADD myLibTests/* /app/myLibTests/ ADD appSolution.sln /app/ RUN cd /app && dotnet clean && dotnet build RUN cd /app/myLibTests && dotnet clean && dotnet test CMD cd /app/myApp/ && dotnet bin/Debug/netcoreapp2.0/myApp.dll && tail -f /var/log/lastlog #CMD tail -f /var/log/lastlog
appSolution.sln
Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myApp", "myApp\myApp.csproj", "{5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myLib", "myLib\myLib.csproj", "{00D6703F-2D64-4D9A-95AA-430DC38E4EC3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|x64.ActiveCfg = Debug|x64 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|x64.Build.0 = Debug|x64 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|x86.ActiveCfg = Debug|x86 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Debug|x86.Build.0 = Debug|x86 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|Any CPU.Build.0 = Release|Any CPU {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|x64.ActiveCfg = Release|x64 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|x64.Build.0 = Release|x64 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|x86.ActiveCfg = Release|x86 {5E009AC4-9BF5-4E1B-9C22-377AC9ECC4EB}.Release|x86.Build.0 = Release|x86 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|x64.ActiveCfg = Debug|x64 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|x64.Build.0 = Debug|x64 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|x86.ActiveCfg = Debug|x86 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Debug|x86.Build.0 = Debug|x86 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|Any CPU.Build.0 = Release|Any CPU {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|x64.ActiveCfg = Release|x64 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|x64.Build.0 = Release|x64 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|x86.ActiveCfg = Release|x86 {00D6703F-2D64-4D9A-95AA-430DC38E4EC3}.Release|x86.Build.0 = Release|x86 EndGlobalSection EndGlobal
myApp/Program.cs
myApp/myApp.csproj
myLib/Class1.cs
myLib/myLib.csproj
myLibTests/UniTest1.cs
myLibTests/myLibTests.csproj
1 <Project Sdk="Microsoft.NET.Sdk">
2
3 <PropertyGroup>
4 <TargetFramework>netcoreapp2.0</TargetFramework>
5
6 <IsPackable>false</IsPackable>
7 </PropertyGroup>
8
9 <ItemGroup>
10 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
11 <PackageReference Include="xunit" Version="2.3.1" />
12 <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
13 <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
14 </ItemGroup>
15
16 <ItemGroup>
17 <ProjectReference Include="..\myLib\myLib.csproj" />
18 </ItemGroup>
19
20 </Project>
Docker commands
1 #build image
2 docker build -t dotnetcorehello .
3 # execute bash in running container
4 docker exec -it $1 bash
5 # delete all containers
6 docker ps -a | awk '//{print $1}' | grep -v "CONTAINER" | xargs -i sh -c 'docker stop {};docker rm {}'
7 # execute container using inage dotnetcorehello
8 docker run -d dotnetcorehello
9 # list all containers
10 docker ps -a
dotnet core commands
test Task
1 // buiild and run with mono
2 // mcs testTask.cs
3 // mono testTask.exe
4
5 using System;
6 using System.Threading.Tasks;
7 using System.Threading;
8 // string interpolation with $ might not be supported in mono
9
10 namespace testTask
11 {
12 class Program
13 {
14 static void Main()
15 {
16 var x=1;
17 // String interpolation $"{varxyz}"
18 //Console.WriteLine($"ThreadId {Thread.CurrentThread.ManagedThreadId}");
19 Console.WriteLine("ThreadId {0}",Thread.CurrentThread.ManagedThreadId);
20 Task t = Task.Run( () => {
21 x++;
22 Console.WriteLine("Stuff");
23 //Console.WriteLine($"ThreadId {Thread.CurrentThread.ManagedThreadId}");
24 Console.WriteLine("ThreadId {0}",Thread.CurrentThread.ManagedThreadId);
25 } );
26 t.ContinueWith((Task task)=>{
27 x++;
28 Console.WriteLine("This the end !");
29 //Console.WriteLine($"ThreadId {Thread.CurrentThread.ManagedThreadId}");
30 Console.WriteLine("ThreadId {0}",Thread.CurrentThread.ManagedThreadId);
31 task.ContinueWith((Task t2)=>{
32 x++;
33 Console.WriteLine("t2 {0}",x);
34 Console.WriteLine("ThreadId {0}",Thread.CurrentThread.ManagedThreadId);
35 });
36 });
37 //t.Wait();
38 var tx = Task<long>.Run( ()=>{ return 11L; } );
39
40 tx.ContinueWith((Task<long> txy)=>{
41 //Console.WriteLine($"Res: {txy.Result}");
42 Console.WriteLine("Res: {0}",txy.Result);
43 });
44 }
45 }
46 }
test foreach
1 //build and run using mono
2 //mcs testForeach.cs
3 //mono testForeach.exe
4 using System;
5 using System.Collections.Generic;
6
7 namespace loopNrs
8 {
9 class Program
10 {
11 static void Main()
12 {
13 var numbers = new List<long> { 1,2,3,4 };
14 foreach (var nr in numbers)
15 {
16 //string interpolation is not supported in mono !?
17 // Console.WriteLine($"Hello {nr}!");
18 Console.WriteLine("Hello {0}!",nr);
19 }
20 }
21 }
22 }
Sample DI (in debian buster)
Commands:
testDI.csproj
Program.cs
1 using System;
2 using Microsoft.Extensions.DependencyInjection;
3
4 namespace testDI
5 {
6 interface IDummy : IDisposable
7 {
8 string GetPong();
9 }
10
11 interface ISnafu : IDisposable
12 {
13 string GetSnafu();
14 }
15
16 interface ITransx : IDisposable
17 {
18 string GetTransx();
19 }
20
21 class Transx : ITransx
22 {
23 private string guid;
24
25 public Transx()
26 {
27 guid = Guid.NewGuid().ToString();
28 Console.WriteLine($"Constructed transx {guid} !");
29 }
30
31 public string GetTransx()
32 {
33 return $"Transx {guid} !";
34 }
35
36 public void Dispose()
37 {
38 Console.WriteLine($"Disposing transx {guid} !");
39 }
40 }
41
42 class Dummy : IDummy
43 {
44 private string guid;
45
46 public Dummy()
47 {
48 guid = Guid.NewGuid().ToString();
49 Console.WriteLine($"Constructed dummy {guid} !");
50 }
51
52 public string GetPong()
53 {
54 return $"Pong {guid} !";
55 }
56
57 public void Dispose()
58 {
59 Console.WriteLine($"Disposing dummy {guid} !");
60 }
61 }
62
63 class Snafu:ISnafu
64 {
65 private IDummy dummy;
66 private string guid;
67
68 public Snafu(IDummy dummy)
69 {
70 this.dummy = dummy;
71 guid = Guid.NewGuid().ToString();
72 Console.WriteLine($"Constructed snafu {guid} !");
73 }
74
75 public string GetSnafu()
76 {
77 return $"Snafu {guid} related with {dummy.GetPong() }!";
78 }
79
80 public void Dispose()
81 {
82 Console.WriteLine($"Disposing snafu {guid} !");
83 }
84 }
85
86 class Program
87 {
88 private static IServiceProvider ioc; //Default implementation ServiceProvider
89
90 private static void PrepareContainer()
91 {
92 var serviceCollection = new ServiceCollection();
93 serviceCollection.AddSingleton<IDummy, Dummy>();
94 serviceCollection.AddSingleton<ISnafu, Snafu>();
95 serviceCollection.AddTransient<ITransx, Transx>();
96 ioc = serviceCollection.BuildServiceProvider();
97 }
98
99 static void Main(string[] args)
100 {
101 Console.WriteLine("Hello World DI!");
102 TestOne();
103 TestTwo();
104 }
105
106 private static void TestOne()
107 {
108 Console.WriteLine("\nTestOne");
109 PrepareContainer();
110 var d1 = ioc.GetService<IDummy>();
111 Console.WriteLine( $"{d1.GetPong()}" );
112 var d2 = ioc.GetService<IDummy>();
113 Console.WriteLine( $"{d2.GetPong()}" );
114 var s1 = ioc.GetService<ISnafu>();
115 Console.WriteLine($"{s1.GetSnafu()}" );
116 var s2 = ioc.GetService<ISnafu>();
117 Console.WriteLine($"{s2.GetSnafu()}" );
118 var t1 = ioc.GetService<ITransx>();
119 Console.WriteLine($"{t1.GetTransx()}" );
120 var t2 = ioc.GetService<ITransx>();
121 Console.WriteLine($"{t2.GetTransx()}" );
122 var t3 = ioc.GetService<ITransx>();
123 Console.WriteLine($"{t3.GetTransx()}" );
124 ReleaseContainer();
125 }
126
127 private static void TestTwo()
128 {
129 Console.WriteLine("\nTestTwo");
130 PrepareContainer();
131 var sx1 = ioc.GetService<ISnafu>();
132 Console.WriteLine($"{sx1.GetSnafu()}" );
133 var dx1 = ioc.GetService<IDummy>();
134 Console.WriteLine( $"{dx1.GetPong()}" );
135 var dx2 = ioc.GetService<IDummy>();
136 Console.WriteLine( $"{dx2.GetPong()}" );
137 ReleaseContainer();
138 }
139
140 private static void ReleaseContainer()
141 {
142 // dispose container and services in it
143 if(ioc is IDisposable)
144 {
145 Console.WriteLine("Can dispose stuff !");
146 ( (IDisposable)ioc).Dispose();
147 }
148 }
149 }
150 }
Example output
Hello World DI! TestOne Constructed dummy 37a7cced-15c3-4b33-9eec-55f0fb58ce8c ! Pong 37a7cced-15c3-4b33-9eec-55f0fb58ce8c ! Pong 37a7cced-15c3-4b33-9eec-55f0fb58ce8c ! Constructed snafu 619160b5-6e67-4396-8555-f453bd1ad06f ! Snafu 619160b5-6e67-4396-8555-f453bd1ad06f related with Pong 37a7cced-15c3-4b33-9eec-55f0fb58ce8c !! Snafu 619160b5-6e67-4396-8555-f453bd1ad06f related with Pong 37a7cced-15c3-4b33-9eec-55f0fb58ce8c !! Constructed transx 6cf6600a-e622-46fd-8d10-3b6015601911 ! Transx 6cf6600a-e622-46fd-8d10-3b6015601911 ! Constructed transx c666091c-efe9-407f-8659-6c1bdc7e2b7f ! Transx c666091c-efe9-407f-8659-6c1bdc7e2b7f ! Constructed transx 421a63ca-0e93-4656-ba5c-c8909774827c ! Transx 421a63ca-0e93-4656-ba5c-c8909774827c ! Can dispose stuff ! Disposing transx 421a63ca-0e93-4656-ba5c-c8909774827c ! Disposing transx c666091c-efe9-407f-8659-6c1bdc7e2b7f ! Disposing transx 6cf6600a-e622-46fd-8d10-3b6015601911 ! Disposing snafu 619160b5-6e67-4396-8555-f453bd1ad06f ! Disposing dummy 37a7cced-15c3-4b33-9eec-55f0fb58ce8c ! TestTwo Constructed dummy 7233afd9-9f2e-43a4-ae1a-bc0abba6abc7 ! Constructed snafu 10298883-4f16-4383-b5b7-ce9e5ad90715 ! Snafu 10298883-4f16-4383-b5b7-ce9e5ad90715 related with Pong 7233afd9-9f2e-43a4-ae1a-bc0abba6abc7 !! Pong 7233afd9-9f2e-43a4-ae1a-bc0abba6abc7 ! Pong 7233afd9-9f2e-43a4-ae1a-bc0abba6abc7 ! Can dispose stuff ! Disposing snafu 10298883-4f16-4383-b5b7-ce9e5ad90715 ! Disposing dummy 7233afd9-9f2e-43a4-ae1a-bc0abba6abc7 !
Eager service bean instantiation
To instantiate a service/bean before being used else where add it as an argument in the Configure method that belongs to the Startup class.
RBAC role based authorization
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-2.0
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.0
https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.0
Identity is enabled for the application by calling UseAuthentication in the Configure method. Startup.cs in dotnet core to init the services/beans.
In ASP.NET Core MVC, views are .cshtml files that use the C# programming language in Razor markup.
- About.cshtml
@{ ViewData["Title"] = "About"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <p>Use this area to provide additional information.</p>
1 // method About related with About.cshtml
2 // ViewData["Message"] defined in the method and accessed inside the view in the About.cshtml
3 public IActionResult About()
4 {
5 ViewData["Message"] = "Your application description page.";
6
7 return View();
8 // return explicit view Orders
9 // return View("Orders");
10 // return both a view and a model
11 // return View("Orders", Orders);
12 }
View discovery searches for a matching view file in this order:
Views/[ControllerName]/[ViewName].cshtml
Views/Shared/[ViewName].cshtml
Pass data to views using several approaches:
- Strongly-typed data: viewmodel
- Weakly-typed data
Strong type sample
// CSHTML @model WebApplication1.ViewModels.Address <h2>Contact</h2> <address> @Model.Street<br> @Model.City, @Model.State @Model.PostalCode<br> <abbr title="Phone">P:</abbr> 425.555.0100 </address> To provide the model to the view, the controller passes it as a parameter: // C# public IActionResult Contact() { ViewData["Message"] = "Your contact page."; var viewModel = new Address() { Name = "Microsoft", Street = "One Microsoft Way", City = "Redmond", State = "WA", PostalCode = "98052-6399" }; return View(viewModel); }
Angular automatically passes an antiforgery token in a request header named X-XSRF-TOKEN. The ASP.NET Core MVC app is configured to refer to this header in its configuration in Startup.cs:
public void ConfigureServices(IServiceCollection services) { // Angular's default header name for sending the XSRF token. services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddMvc(); }
Install dotnetcore in CentOS
1 rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
2 yum install dotnet-sdk-2.2
3 dotnet new console --name hello-console
4 yum install epel-release
5 yum install nodejs
6 dotnet new reactredux --name "react-test"
7 cd react-test/
8 dotnet clean
9 dotnet build
10 dotnet publish
11 dotnet bin/Debug/netcoreapp2.2/publish/react-test.dll
12 vi Program.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Threading.Tasks;
6 using Microsoft.AspNetCore;
7 using Microsoft.AspNetCore.Hosting;
8 using Microsoft.Extensions.Configuration;
9 using Microsoft.Extensions.Logging;
10
11 namespace react_test
12 {
13 public class Program
14 {
15 public static void Main(string[] args)
16 {
17 CreateWebHostBuilder(args).Build().Run();
18 }
19
20 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 WebHost.CreateDefaultBuilder(args)
22 .UseStartup<Startup>().UseUrls("http://0.0.0.0:5000;https://0.0.0.0:5001");
23 }
24 }
Kestrel
Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the web server that's included by default in ASP.NET Core project templates.
Kestrel supports the following scenarios:
- HTTPS
Opaque upgrade used to enable WebSockets
- Unix sockets for high performance behind Nginx
- HTTP/2 (except on macOS†)
Install dotnetcore in Debian buster
1 wget https://packages.microsoft.com/config/ubuntu/19.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
2 sudo dpkg -i packages-microsoft-prod.deb
3 sudo apt-get update
4 sudo apt-get install apt-transport-https
5 sudo apt-get update
6 sudo apt-get install dotnet-sdk-3.1 nodejs npm dotnet-sdk-2.1
7 # https://code.visualstudio.com/
8 cd ~/Downloads
9 wget https://go.microsoft.com/fwlink/?LinkID=760868
10 mv index.html\?LinkID\=760868 vscode.deb
11 sudo dpkg -i vscode.deb # 1.43.2
12 code &
13 # Install extension ms-dotnettools.csharp
14 # Install extension Eclipse Keymap alphabotsec.vscode-eclipse-keybindings
15
Angular project
1 # nodejs --version # v12.16.2
2 # npm --version # 6.14.4
3 # dotnet --version # 3.1.201
4 cd ~
5 dotnet new angular --name test # creates folder test with the project
6 cd test
7 dotnet clean
8 dotnet build
9 dotnet run
10 https://localhost:5001/
11 # There are issues building the project on the sandbox folder shared with windows through a mounted folder.
12
ILspy
https://github.com/icsharpcode/ILSpy open-source .NET assembly browser and decompiler.
Install MSSQL server 2017 express in Debian Linux buster
1 sudo apt-get install apt-transport-https
2 curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
3 curl https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-2017.list | sudo tee /etc/apt/sources.list.d/mssql-server.list
4 sudo apt update
5 # deb http://ftp.debian.org/debian jessie main
6 echo "deb http://ftp.debian.org/debian jessie main" >> /etc/apt/sources.list
7 sudo apt update
8 sudo apt-get install libssl1.0
9 sudo apt-get install mssql-server
10 sudo systemctl restart mssql-server.service
11 sudo /opt/mssql/bin/mssql-conf setup
12 # "Express" edition is free to use with limitations.
13 # Choose 3) Express (free)
14 # Enter the SQL Server system administrator password: **********
15 # The licensing PID was successfully processed. The new edition is [Express Edition].
16 # install sqlcmd
17 sudo apt install mssql-tools
18 nano ~/.bashrc
19 PATH=$PATH:/opt/mssql-tools/bin/
20 . ~/.bashrc # reload .bashrc
21 # tcp6 0 0 :::1433 :::* LISTEN
22
23 sqlcmd -S localhost -U sa -P ********
24 # 1> exec sp_databases
25 # 2> go
26 # https://docs.microsoft.com/en-us/sql/tools/sqlcmd-utility?view=sql-server-ver15
27 # select name from sys.databases
28 # go
29 # exit
30 # example connection string
31 # Data Source=LOCALHOST;Initial Catalog=TestDB;User Id=sa;Password=********;App=TestApp
32
Swagger
1 using Microsoft.OpenApi.Models;
2 /* in Startup.cs ConfigureServices */
3 services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); });
4 /* in Startup,cs Configure */
5 app.UseSwagger();
6 app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
Multiple file upload controller example
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using Microsoft.AspNetCore.Http;
8 using Microsoft.AspNetCore.Mvc;
9 using Microsoft.Extensions.Logging;
10
11 namespace test_webapi.Controllers
12 {
13 [ApiController]
14 [Route("[controller]")]
15 public class UploadController : ControllerBase
16 {
17 private readonly ILogger<UploadController> _logger;
18
19 public UploadController(ILogger<UploadController> logger)
20 {
21 _logger = logger;
22 }
23
24 //---
25 private void ShowHeadersConsole()
26 {
27 Console.WriteLine($"Headers");
28 foreach (var h in Request.Headers)
29 {
30 Console.WriteLine($"{h.Key}:{h.Value}");
31 }
32 }
33
34 private async void ShowFormDataConsole()
35 {
36 Task<IFormCollection> task = Request.ReadFormAsync(CancellationToken.None);
37
38 await task;
39
40 Console.WriteLine($"Form stuff ...");
41 // an uploaded file will not be shown !
42 foreach (var formItem in task.Result)
43 {
44 Console.WriteLine($"{formItem.Key}:{formItem.Value}");
45 }
46 }
47
48 private void ShowBodyConsole()
49 {
50 Console.WriteLine("Body");
51 using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
52 {
53 Task<string> t = reader.ReadToEndAsync();
54 // await t;
55 t.Wait();
56 Console.WriteLine(t.Result);
57 }
58 }
59
60 public class FormPayload1
61 {
62 public IFormFile UploadedFile1 { get; set; }
63 public IFormFile UploadedFile2 { get; set; }
64 public IFormFile UploadedFile3 { get; set; }
65 public IFormFile UploadedFile4 { get; set; }
66 public IFormFile UploadedFile5 { get; set; }
67 public IFormFile UploadedFile6 { get; set; }
68 public IFormFile UploadedFile7 { get; set; }
69 public IFormFile UploadedFile8 { get; set; }
70 public IFormFile UploadedFile9 { get; set; }
71
72 public string TestName { get; set; }
73 }
74
75 public class FormPayload2
76 {
77 public IFormFileCollection UploadedFiles { get; set; }
78 public string TestName { get; set; }
79 }
80
81 [HttpPost]
82 [Route("[controller]/[action]")]
83 public async Task<IActionResult> FilesApproach1([FromForm] FormPayload1 payload)
84 {
85 var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
86
87 ShowHeadersConsole();
88 ShowFormDataConsole();
89 ShowBodyConsole();
90 List<string> paths = new List<string>();
91
92 Console.WriteLine($"Test name: {payload.TestName} ");
93
94 // identify uploaded files properties that have data and create asynch tasks to get that data
95 List<Task<string>> tasks = new List<Task<string>>();
96 foreach (var pi in payload.GetType().GetProperties())
97 {
98 if (pi.GetValue(payload) != null && pi.Name.StartsWith("UploadedFile"))
99 {
100 Task<string> task = this.HandleFile((IFormFile)pi.GetValue(payload));
101 tasks.Add(task);
102 }
103 }
104
105 await Task.WhenAll(tasks);
106 foreach (var task in tasks)
107 {
108 paths.Add(task.Result);
109 }
110
111 return Ok(new { storePaths = paths });
112 }
113
114 [HttpPost]
115 [Route("[controller]/[action]")]
116 public async Task<IActionResult> FilesApproach2([FromForm] FormPayload2 payload)
117 {
118 /*
119 Repeat the field uploadedFiles per file to upload
120 curl -v -X POST -F 'UploadedFiles=@/home/vitor/test.png' -F 'UploadedFiles=@/home/vitor/Vitor.png' -F 'TestName=namex' -k https://localhost:5001/Upload/Upload/FilesApproach2
121 */
122 var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
123
124 ShowHeadersConsole();
125 ShowFormDataConsole();
126 ShowBodyConsole();
127 List<string> paths = new List<string>();
128 List<Task<string>> tasks = new List<Task<string>>();
129
130 Console.WriteLine($"Test name: {payload.TestName} ");
131 Console.WriteLine($"Amount files: {payload.UploadedFiles.Count} ");
132
133 foreach (var f in payload.UploadedFiles)
134 {
135 Task<string> task = this.HandleFile(f);
136 tasks.Add(task);
137 }
138
139 await Task.WhenAll(tasks);
140 foreach (var t in tasks)
141 {
142 paths.Add(t.Result);
143 }
144
145 return Ok(new { storePaths = paths });
146 }
147
148 private async Task<string> HandleFile(IFormFile filename)
149 {
150 var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
151 var filePath = String.Empty;
152 if (filename != null)
153 {
154 if (filename.Length > 0)
155 {
156 filePath = $"{Path.GetTempPath()}{millisSinceDawnTime}_{filename.FileName}";
157 Console.WriteLine($"Name: {filename.Name} ");
158 Console.WriteLine($"Filename: {filename.FileName} ");
159 Console.WriteLine($"Length: {filename.Length} ");
160 Console.WriteLine($"Type: {filename.ContentType} ");
161 Console.WriteLine($"Disposition: {filename.ContentDisposition} ");
162 Console.WriteLine($"File will be stored in: {filePath} ");
163 using (var stream = new FileStream(filePath, FileMode.Create))
164 {
165 await filename.CopyToAsync(stream, CancellationToken.None);
166 }
167 }
168 }
169
170 return filePath;
171
172 }
173 }
174 }
Setup test project
1 dotnet new mstest --name test-proj
2 cd test-proj/
3 //UnitTest1.cs
4 using FluentAssertions;
5 using Microsoft.VisualStudio.TestTools.UnitTesting; // MSTest
6 using Moq;
7
8 dotnet add package Moq --version 4.14.1
9 dotnet add package Microsoft.Extensions.Logging --version 3.1.4
10 dotnet add package FluentAssertions --version 5.10.3
11 dotnet add reference ../other-proj.csproj
12 dotnet add package Microsoft.EntityFrameworkCore.Sqlite
EF core test - sqlite
1 // dotnet add package Microsoft.EntityFrameworkCore.Sqlite
2 var context = new MyDbContext(new DbContextOptionsBuilder<MyDbContext>().UseSqlite(CreateInMemoryDatabase()).Options);
3
4 private static DbConnection CreateInMemoryDatabase()
5 {
6 var connection = new SqliteConnection("Filename=:memory:");
7 connection.Open();
8 return connection;
9 }
10
11
12
13 using System;
14 using System.Data.Common;
15 using FluentAssertions;
16 using Microsoft.Data.Sqlite;
17 using Microsoft.EntityFrameworkCore;
18 using Microsoft.Extensions.Logging;
19 using Microsoft.VisualStudio.TestTools.UnitTesting;
20 using Moq;
21 using test_webapi_efcore.Controllers;
22 using test_webapi_efcore.Domain;
23 using test_webapi_efcore.Persistence;
24
25 namespace test_webapi_efcore.UnitTests
26 {
27 [TestClass]
28 public class ControllerTest
29 {
30 [TestMethod]
31 public void Create_IsOkay()
32 {
33 }
34 }
35 }