();
Console.WriteLine( $"{dx2.GetPong()}" );
ReleaseContainer();
}
private static void ReleaseContainer()
{
// dispose container and services in it
if(ioc is IDisposable)
{
Console.WriteLine("Can dispose stuff !");
( (IDisposable)ioc).Dispose();
}
}
}
}
}}}
=== 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/authentication/identity?view=aspnetcore-2.0&tabs=visual-studio%2Caspnetcore2x
* 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
{{{#!highlight csharp
@{
ViewData["Title"] = "About";
}
@ViewData["Title"].
@ViewData["Message"]
Use this area to provide additional information.
}}}
* HomeController.cs
{{{#!highlight csharp
// method About related with About.cshtml
// ViewData["Message"] defined in the method and accessed inside the view in the About.cshtml
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
// return explicit view Orders
// return View("Orders");
// return both a view and a model
// return View("Orders", Orders);
}
}}}
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
* ViewData (ViewDataAttribute)
* ViewBag
Strong type sample
{{{#!highlight csharp
// CSHTML
@model WebApplication1.ViewModels.Address
Contact
@Model.Street
@Model.City, @Model.State @Model.PostalCode
P: 425.555.0100
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:
{{{#!highlight csharp
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 ==
{{{#!highlight sh
rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
yum install dotnet-sdk-2.2
dotnet new console --name hello-console
yum install epel-release
yum install nodejs
dotnet new reactredux --name "react-test"
cd react-test/
dotnet clean
dotnet build
dotnet publish
dotnet bin/Debug/netcoreapp2.2/publish/react-test.dll
vi Program.cs
}}}
{{{#!highlight csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace react_test
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup().UseUrls("http://0.0.0.0:5000;https://0.0.0.0:5001");
}
}
}}}
== Kestrel ==
* https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1
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 ==
{{{#!highlight sh
wget https://packages.microsoft.com/config/ubuntu/19.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-3.1 nodejs npm dotnet-sdk-2.1
# https://code.visualstudio.com/
cd ~/Downloads
wget https://go.microsoft.com/fwlink/?LinkID=760868
mv index.html\?LinkID\=760868 vscode.deb
sudo dpkg -i vscode.deb # 1.43.2
code &
# Install extension ms-dotnettools.csharp
# Install extension Eclipse Keymap alphabotsec.vscode-eclipse-keybindings
}}}
=== Angular project ===
{{{#!highlight bash
# nodejs --version # v12.16.2
# npm --version # 6.14.4
# dotnet --version # 3.1.201
cd ~
dotnet new angular --name test # creates folder test with the project
cd test
dotnet clean
dotnet build
dotnet run
https://localhost:5001/
# There are issues building the project on the sandbox folder shared with windows through a mounted folder.
}}}
== ILspy ==
* https://github.com/icsharpcode/ILSpy open-source .NET assembly browser and decompiler.
== Install MSSQL server 2017 express in Debian Linux buster ==
* https://dev.to/nabbisen/microsoft-sql-server-2017-on-debian-n77
{{{#!highlight bash
sudo apt-get install apt-transport-https
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-2017.list | sudo tee /etc/apt/sources.list.d/mssql-server.list
sudo apt update
# deb http://ftp.debian.org/debian jessie main
echo "deb http://ftp.debian.org/debian jessie main" >> /etc/apt/sources.list
sudo apt update
sudo apt-get install libssl1.0
sudo apt-get install mssql-server
sudo systemctl restart mssql-server.service
sudo /opt/mssql/bin/mssql-conf setup
# "Express" edition is free to use with limitations.
# Choose 3) Express (free)
# Enter the SQL Server system administrator password: **********
# The licensing PID was successfully processed. The new edition is [Express Edition].
# install sqlcmd
sudo apt install mssql-tools
nano ~/.bashrc
PATH=$PATH:/opt/mssql-tools/bin/
. ~/.bashrc # reload .bashrc
# tcp6 0 0 :::1433 :::* LISTEN
sqlcmd -S localhost -U sa -P ********
# 1> exec sp_databases
# 2> go
# https://docs.microsoft.com/en-us/sql/tools/sqlcmd-utility?view=sql-server-ver15
# select name from sys.databases
# go
# exit
# example connection string
# Data Source=LOCALHOST;Initial Catalog=TestDB;User Id=sa;Password=********;App=TestApp
}}}
== Webapi/Swagger ==
* https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=netcore-cli
{{{#!highlight sh
dotnet new webapi --name test-webapi
dotnet add test.csproj package Swashbuckle.AspNetCore
dotnet build
dotnet run
# https://localhost:5001/swagger/index.html
curl -X GET "https://localhost:5001/WeatherForecast" -H "accept: text/plain" -k
}}}
{{{#!highlight csharp
using Microsoft.OpenApi.Models;
/* in Startup.cs ConfigureServices */
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); });
/* in Startup,cs Configure */
app.UseSwagger();
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
}}}
== Multiple file upload controller example ==
{{{#!highlight csharp
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace test_webapi.Controllers
{
[ApiController]
[Route("[controller]")]
public class UploadController : ControllerBase
{
private readonly ILogger _logger;
public UploadController(ILogger logger)
{
_logger = logger;
}
//---
private void ShowHeadersConsole()
{
Console.WriteLine($"Headers");
foreach (var h in Request.Headers)
{
Console.WriteLine($"{h.Key}:{h.Value}");
}
}
private async void ShowFormDataConsole()
{
Task task = Request.ReadFormAsync(CancellationToken.None);
await task;
Console.WriteLine($"Form stuff ...");
// an uploaded file will not be shown !
foreach (var formItem in task.Result)
{
Console.WriteLine($"{formItem.Key}:{formItem.Value}");
}
}
private void ShowBodyConsole()
{
Console.WriteLine("Body");
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
Task t = reader.ReadToEndAsync();
// await t;
t.Wait();
Console.WriteLine(t.Result);
}
}
public class FormPayload1
{
public IFormFile UploadedFile1 { get; set; }
public IFormFile UploadedFile2 { get; set; }
public IFormFile UploadedFile3 { get; set; }
public IFormFile UploadedFile4 { get; set; }
public IFormFile UploadedFile5 { get; set; }
public IFormFile UploadedFile6 { get; set; }
public IFormFile UploadedFile7 { get; set; }
public IFormFile UploadedFile8 { get; set; }
public IFormFile UploadedFile9 { get; set; }
public string TestName { get; set; }
}
public class FormPayload2
{
public IFormFileCollection UploadedFiles { get; set; }
public string TestName { get; set; }
}
[HttpPost]
[Route("[controller]/[action]")]
public async Task FilesApproach1([FromForm] FormPayload1 payload)
{
var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
ShowHeadersConsole();
ShowFormDataConsole();
ShowBodyConsole();
List paths = new List();
Console.WriteLine($"Test name: {payload.TestName} ");
// identify uploaded files properties that have data and create asynch tasks to get that data
List> tasks = new List>();
foreach (var pi in payload.GetType().GetProperties())
{
if (pi.GetValue(payload) != null && pi.Name.StartsWith("UploadedFile"))
{
Task task = this.HandleFile((IFormFile)pi.GetValue(payload));
tasks.Add(task);
}
}
await Task.WhenAll(tasks);
foreach (var task in tasks)
{
paths.Add(task.Result);
}
return Ok(new { storePaths = paths });
}
[HttpPost]
[Route("[controller]/[action]")]
public async Task FilesApproach2([FromForm] FormPayload2 payload)
{
/*
Repeat the field uploadedFiles per file to upload
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
*/
var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
ShowHeadersConsole();
ShowFormDataConsole();
ShowBodyConsole();
List paths = new List();
List> tasks = new List>();
Console.WriteLine($"Test name: {payload.TestName} ");
Console.WriteLine($"Amount files: {payload.UploadedFiles.Count} ");
foreach (var f in payload.UploadedFiles)
{
Task task = this.HandleFile(f);
tasks.Add(task);
}
await Task.WhenAll(tasks);
foreach (var t in tasks)
{
paths.Add(t.Result);
}
return Ok(new { storePaths = paths });
}
private async Task HandleFile(IFormFile filename)
{
var millisSinceDawnTime = DateTime.Now.Ticks / 10000;
var filePath = String.Empty;
if (filename != null)
{
if (filename.Length > 0)
{
filePath = $"{Path.GetTempPath()}{millisSinceDawnTime}_{filename.FileName}";
Console.WriteLine($"Name: {filename.Name} ");
Console.WriteLine($"Filename: {filename.FileName} ");
Console.WriteLine($"Length: {filename.Length} ");
Console.WriteLine($"Type: {filename.ContentType} ");
Console.WriteLine($"Disposition: {filename.ContentDisposition} ");
Console.WriteLine($"File will be stored in: {filePath} ");
using (var stream = new FileStream(filePath, FileMode.Create))
{
await filename.CopyToAsync(stream, CancellationToken.None);
}
}
}
return filePath;
}
}
}
}}}
== Setup test project ==
{{{#!highlight csharp
dotnet new mstest --name test-proj
cd test-proj/
//UnitTest1.cs
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting; // MSTest
using Moq;
dotnet add package Moq --version 4.14.1
dotnet add package Microsoft.Extensions.Logging --version 3.1.4
dotnet add package FluentAssertions --version 5.10.3
dotnet add reference ../other-proj.csproj
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
}}}
== EF core test - sqlite ==
{{{#!highlight csharp
// dotnet add package Microsoft.EntityFrameworkCore.Sqlite
var context = new MyDbContext(new DbContextOptionsBuilder().UseSqlite(CreateInMemoryDatabase()).Options);
private static DbConnection CreateInMemoryDatabase()
{
var connection = new SqliteConnection("Filename=:memory:");
connection.Open();
return connection;
}
using System;
using System.Data.Common;
using FluentAssertions;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using test_webapi_efcore.Controllers;
using test_webapi_efcore.Domain;
using test_webapi_efcore.Persistence;
namespace test_webapi_efcore.UnitTests
{
[TestClass]
public class ControllerTest
{
[TestMethod]
public void Create_IsOkay()
{
}
}
}
}}}
== Dotnet core 9 podman ==
=== Dockerfile ===
{{{#!highlight sh
FROM mcr.microsoft.com/dotnet/sdk:9.0
WORKDIR /app
RUN apt-get update
RUN apt-get install net-tools procps vim nano -y
CMD tail -f /var/log/lastlog
}}}
=== Steps ===
{{{#!highlight sh
podman build -t dotnet9-image .
podman run -d -P --name dotnet9-image-container dotnet9-image
podman ps -l
podman exec -it dotnet9-image-container bash
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
dotnet --version
# 9.0.200
cd /app
dotnet new console
dotnet run
dotnet bin/Debug/net9.0/app.dll
# Hello, World!
cat Program.cs
#var hello="Hello world!";
#Console.WriteLine(hello);
dotnet build
dotnet bin/Debug/net9.0/app.dll
# Hello world!
}}}
* https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.200/dotnet-sdk-9.0.200-linux-x64.tar.gz
* Included runtimes
* .NET Runtime 9.0.2
* ASP.NET Core Runtime 9.0.2
* .NET Desktop Runtime 9.0.2
* Language support
* C# 13.0
* F# 9.0
* Visual Basic 17.13
== Install on debian 12 - bookworm / debian 11 - bullseye ==
{{{#!highlight sh
cd ~
wget https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.200/dotnet-sdk-9.0.200-linux-x64.tar.gz
mkdir ~/dotnetcore9
mv dotnet-sdk-9.0.200-linux-x64.tar.gz ~/dotnetcore9/
cd ~/dotnetcore9/
tar xvzf dotnet-sdk-9.0.200-linux-x64.tar.gz
echo 'PATH="$HOME/dotnetcore9:$PATH"' >> ~/.bashrc
source ~/.bashrc
dotnet --version
dotnet new list
}}}
== dotnet core 9 hello world ==
=== Program.cs ===
{{{#!highlight csharp
/**
dotnet new console
dotnet build
dotnet run
dotnet bin/Debug/net9.0/dotnet-9-test.dll
*/
var message = new Hello().GetHello();
Console.WriteLine( message );
public class Hello{
public string GetHello(){
return "Hello, world!";
}
}
}}}
=== dotnet-9-test.csproj ===
{{{#!highlight xml
Exe
net9.0
dotnet_9_test
enable
enable
}}}
== dotnetcore 9 - test api ==
=== Setup docker DB with docker ===
{{{#!highlight sh
docker network create mynet
docker run -p 5432:5432 --rm --name postgres-server -e POSTGRES_PASSWORD=postgres --network mynet -d postgres:15.3-alpine
docker exec -it postgres-server sh
psql -U postgres
\l
\q
exit
# Create DB and schema
docker exec -it postgres-server sh
su postgres
psql
create user appuser with login password '12345678';
create database app;
grant all privileges on database app to appuser;
\q
exit
exit
# Create schema, table and sequence
docker exec -it postgres-server sh
psql -U appuser -h localhost -W -d app
create schema if not exists myschema;
SET search_path TO myschema;
GRANT ALL ON SCHEMA myschema TO appuser;
create sequence if not exists device_seq;
CREATE TABLE devices (
id integer PRIMARY KEY DEFAULT nextval('device_seq'),
device varchar(128),
apikey varchar(128)
);
insert into devices(device,apikey) values('device','api');
select * from devices;
\l
\d
\q
exit
}}}
=== Setup postgres DB in Debian ===
{{{#!highlight sh
sudo apt install postgresql-15
ss -a -n | grep 5432
}}}
=== /etc/postgresql/15/main/pg_hba.conf ===
sudo nano /etc/postgresql/15/main/pg_hba.conf
{{{#!highlight sh
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
host all all 0.0.0.0/0 password
}}}
=== /etc/postgresql/15/main/postgresql.conf ===
sudo nano /etc/postgresql/15/main/postgresql.conf
{{{#!highlight sh
data_directory = '/var/lib/postgresql/15/main'
hba_file = '/etc/postgresql/15/main/pg_hba.conf'
ident_file = '/etc/postgresql/15/main/pg_ident.conf'
external_pid_file = '/var/run/postgresql/15-main.pid'
unix_socket_directories = '/var/run/postgresql'
shared_buffers = 128MB
dynamic_shared_memory_type = posix
max_wal_size = 1GB
min_wal_size = 80MB
log_line_prefix = '%m [%p] %q%u@%d '
log_timezone = 'Europe/Lisbon'
cluster_name = '15/main'
datestyle = 'iso, mdy'
timezone = 'Europe/Lisbon'
default_text_search_config = 'pg_catalog.english'
include_dir = 'conf.d'
listen_addresses = '*'
}}}
=== check connections ===
{{{#!highlight sh
sudo service postgresql restart
sudo service postgresql status
pg_isready
# /var/run/postgresql:5432 - accepting connections
}}}
=== Create DB and schema ===
{{{#!highlight sh
sudo bash
su postgres
psql
create user appuser with login password '12345678';
create database app;
grant all privileges on database app to appuser;
create schema if not exists myschema;
\q
}}}
=== Create table and sequence ===
{{{
psql -U appuser -h 127.0.0.1 -W -d app
psql -U appuser -h localhost -W -d app
create schema if not exists myschema;
SET search_path TO myschema;
GRANT ALL ON SCHEMA myschema TO appuser;
create sequence if not exists device_seq;
CREATE TABLE devices (
id integer PRIMARY KEY DEFAULT nextval('device_seq'),
device varchar(128),
apikey varchar(128)
);
insert into devices(device,apikey) values('device','api');
select * from devices;
\q
}}}
=== dotnet steps ===
{{{#!highlight sh
cd ~/
mkdir -p test-api
cd test-api
dotnet new webapi
dotnet add package Microsoft.AspNetCore.OpenApi
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Scalar.AspNetCore
dotnet tool install --global dotnet-ef
dotnet tool update --global dotnet-ef
echo "export DOTNET_ROOT=$HOME/dotnetcore9/" >> ~/.bashrc
echo "export DOTNET_ROOT=$HOME/dotnetcore9/" >> ~/.profile
echo 'PATH="$HOME/.dotnet/tools:$PATH"' >> ~/.bashrc
source ~/.bashrc
dotnet-ef
dotnet ef
dotnet ef migrations add InitialCreate
dotnet ef database update
}}}
=== build.sh ===
{{{#!highlight sh
#!/bin/sh
dotnet build
}}}
=== run.sh ===
{{{#!highlight sh
#!/bin/sh
dotnet bin/Debug/net9.0/test-api.dll
}}}
=== appsettings.json ===
{{{#!highlight json
{
"AppName": "test-api app",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"PostgresDB": "Host=localhost; Database=app; Username=appuser; Password=12345678; SearchPath=myschema;"
},
"https_port": 8443,
"Urls": "http://localhost:8081"
}
}}}
=== Program.cs ===
{{{#!highlight csharp
using Microsoft.EntityFrameworkCore;
using Scalar.AspNetCore;
using Microsoft.Extensions.Configuration;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.AddDbContext();
builder.Services.AddScoped();
WebApplication app = builder.Build();
Console.WriteLine("appsettings.json Urls: {0}", app.Configuration["Urls"] );
Console.WriteLine("appsettings.json App name: {0}", app.Configuration["AppName"] );
Console.WriteLine("OpenAPI Scalar URL {0}/Scalar/v1", app.Configuration["Urls"] );
app.MapScalarApiReference();
app.MapOpenApi();
app.MapGet("/createtask/{description}", (string description, ITaskService service) =>
{
return service.Create(description);
})
.WithName("CreateTask");
app.MapGet("/gettasks", (ITaskService service) =>
{
return service.GetAll();
})
.WithName("GetTasks");
app.Run();
public class DataContext : DbContext
{
protected readonly IConfiguration Configuration;
public DataContext(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
// connect to postgres with connection string from app settings
options.UseNpgsql(Configuration.GetConnectionString("PostgresDB"));
}
public DbSet Tasks { get; set; }
}
public class Task
{
public int Id { get; set; }
public required string Description { get; set; }
}
public interface ITaskService
{
IEnumerable GetAll();
int Create(string description);
}
public class TaskService : ITaskService
{
private DataContext dbcontext;
public TaskService(DataContext context)
{
dbcontext = context;
}
public int Create(string description)
{
var task = new Task() { Description = description };
dbcontext.Tasks.Add(task);
dbcontext.SaveChanges();
return task.Id;
}
public IEnumerable GetAll()
{
return dbcontext.Tasks;
}
}
}}}