├── .dockerignore ├── .gitignore ├── Directory.Build.props ├── DotNet2019.sln ├── Nuget.config ├── README.md ├── build-agent.ps1 ├── build-agent.sh ├── build.ps1 ├── build ├── dependencies.props ├── docker-compose-buildagent.yml └── docker-compose-sql.yml ├── dotnet-install.ps1 ├── global.json ├── install-sdk.ps1 ├── k8s ├── infra-deployment.yml └── webapp-deployment.yml ├── src ├── DotNet2019.Api │ ├── Configuration.cs │ ├── Controllers │ │ ├── PingController.cs │ │ ├── TransientFaultController.cs │ │ └── UsersController.cs │ ├── DotNet2019.Api.csproj │ ├── Extensions │ │ ├── IEndpointRouterBuilderExtensions.cs │ │ └── IServiceCollectionExtensions.cs │ ├── Infrastructure │ │ ├── Data │ │ │ ├── DataContext.cs │ │ │ ├── Migrations │ │ │ │ ├── 20190616210030_initial.Designer.cs │ │ │ │ ├── 20190616210030_initial.cs │ │ │ │ └── DataContextModelSnapshot.cs │ │ │ └── User.cs │ │ ├── Hubs │ │ │ └── DiagnosticsHub.cs │ │ ├── Middleware │ │ │ ├── ErrorMiddleware.cs │ │ │ └── SecretMiddleware.cs │ │ └── Polly │ │ │ └── RetryPolicy.cs │ ├── Model │ │ └── UserRequest.cs │ └── Services │ │ ├── ISomeService.cs │ │ └── SomeService.cs └── DotNet2019.Host │ ├── DataContent.txt │ ├── Diagnostics │ └── HostingDiagnosticHandler.cs │ ├── Dockerfile │ ├── DotNet2019.Host.csproj │ ├── Extensions │ ├── IApplicationBuilderExtensions.cs │ ├── IServiceCollectionExtensions.cs │ └── IWebHostBuilderExtensions.cs │ ├── Infrastructure │ └── Authentication │ │ └── ApiKeyAuthenticationHandler.cs │ ├── Program.cs │ ├── Startup.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ ├── index.html │ └── lib │ ├── signalr.min.js │ └── signalr.min.js.map └── test └── FunctionalTests ├── Dockerfile ├── DotNet2019.Api ├── Api.cs └── Controllers │ └── UsersController.cs ├── FunctionalTests.csproj ├── Seedwork ├── Builders │ ├── Builders.cs │ └── UserRequestBuilder.cs ├── Extensions │ ├── IHostBuilderExtensions.cs │ ├── IServiceCollectionExtensions.cs │ └── RequestBuilderExtensions.cs ├── Given.cs ├── ResetDatabaseAttribute.cs ├── ServerFixture.cs ├── ServerFixtureCollection.cs └── TestStartup.cs └── appsettings.json /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.dockerignore 2 | **/.env 3 | **/.git 4 | **/.gitignore 5 | **/.vs 6 | **/.vscode 7 | **/*.*proj.user 8 | **/azds.yaml 9 | **/charts 10 | **/bin 11 | **/obj 12 | **/Dockerfile 13 | **/Dockerfile.develop 14 | **/docker-compose.yml 15 | **/docker-compose.*.yml 16 | **/*.dbmdl 17 | **/*.jfm 18 | **/secrets.dev.yaml 19 | **/values.dev.yaml 20 | **/.toolstarget -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | 332 | # Test results 333 | *.trx 334 | 335 | # Container test results 336 | build/.test-results/ 337 | 338 | # Code coverage files 339 | coverage.* -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | false 8 | false 9 | 10 | 11 | -------------------------------------------------------------------------------- /DotNet2019.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29009.5 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4EFF24CF-3D6A-4B08-8476-4CE3790A8D13}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A8DA38D7-6521-419F-A05B-61B0B53BC897}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNet2019.Host", "src\DotNet2019.Host\DotNet2019.Host.csproj", "{39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNet2019.Api", "src\DotNet2019.Api\DotNet2019.Api.csproj", "{4B26FFAF-E9FC-469E-93C3-AD54F226EF15}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{049FEE46-A2B7-4F7F-A5DA-C7739D0725E3}" 15 | ProjectSection(SolutionItems) = preProject 16 | build\dependencies.props = build\dependencies.props 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "k8s", "k8s", "{5C215ACC-BDB8-464F-AB51-D334308EB3F6}" 20 | ProjectSection(SolutionItems) = preProject 21 | k8s\infra-deployment.yml = k8s\infra-deployment.yml 22 | k8s\webapp-deployment.yml = k8s\webapp-deployment.yml 23 | EndProjectSection 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "test\FunctionalTests\FunctionalTests.csproj", "{F3054E26-5F81-4649-86B3-99CAA95A355C}" 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {4B26FFAF-E9FC-469E-93C3-AD54F226EF15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {4B26FFAF-E9FC-469E-93C3-AD54F226EF15}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {4B26FFAF-E9FC-469E-93C3-AD54F226EF15}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {4B26FFAF-E9FC-469E-93C3-AD54F226EF15}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {F3054E26-5F81-4649-86B3-99CAA95A355C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {F3054E26-5F81-4649-86B3-99CAA95A355C}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {F3054E26-5F81-4649-86B3-99CAA95A355C}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {F3054E26-5F81-4649-86B3-99CAA95A355C}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | GlobalSection(NestedProjects) = preSolution 50 | {39E42FB2-78C1-43C2-9A8A-6576C7CBC6D1} = {4EFF24CF-3D6A-4B08-8476-4CE3790A8D13} 51 | {4B26FFAF-E9FC-469E-93C3-AD54F226EF15} = {4EFF24CF-3D6A-4B08-8476-4CE3790A8D13} 52 | {F3054E26-5F81-4649-86B3-99CAA95A355C} = {A8DA38D7-6521-419F-A05B-61B0B53BC897} 53 | EndGlobalSection 54 | GlobalSection(ExtensibilityGlobals) = postSolution 55 | SolutionGuid = {65823A5F-B3A4-4143-82CC-777300A81D03} 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /Nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dotnet2019 2 | 3 | # Asp.Net Core Good Practices 2019 Talk 4 | 5 | ## Speakers: 6 | 7 | Carlos Landeras - Web Team Lead at Plain Concepts ( [Github](https://github.com/CarlosLanderas) / [Twitter](https://twitter.com/Carlos_Lande)) 8 | 9 | Luis Ruiz Pavón - DevSecOps Lead at Plain Concepts ( [Github](https://github.com/lurumad) / [Twitter](https://twitter.com/luisruizpavon)) 10 | 11 | ## Talk Youtube video 12 | https://www.youtube.com/watch?v=lSIPDDxfjuw 13 | 14 | ## Talk Agenda: 15 | 16 | - Code instrumentation using System Diagnostics 17 | - Application resilience strategies 18 | - Asp.Net Core HealthChecks and Kubernetes (Readiness and Liveness Probes) for high availability and resilience 19 | - Problem Details RFC 7807 20 | - Asp.Net Core ApiController and ApiBehaviourOptions (Convention over Configuration) 21 | - HttpContext Pipelines 22 | - Endpoint Routing 23 | - Endpoint Authorization (decoupled from MVC) 24 | - Docker testing strategies 25 | -------------------------------------------------------------------------------- /build-agent.ps1: -------------------------------------------------------------------------------- 1 | function Exec 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd, 6 | [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd) 7 | ) 8 | & $cmd 9 | if ($lastexitcode -ne 0) { 10 | throw ("Exec: " + $errorMessage) 11 | } 12 | } 13 | 14 | exec { & docker-compose -f .\build\docker-compose-buildagent.yml up --build -d } 15 | exec { & docker-compose -f .\build\docker-compose-buildagent.yml exec -e 'ConnectionStrings__SqlServer=Server=sqlserver;User Id=sa;Password=Password12!;Initial Catalog=FunctionalTests;MultipleActiveResultSets=true' functionaltests dotnet test test/FunctionalTests/FunctionalTests.csproj -p:ParallelizeTestCollections=false --logger trx --results-directory /var/temp } 16 | exec { & docker-compose -f .\build\docker-compose-buildagent.yml down } -------------------------------------------------------------------------------- /build-agent.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | export COMPOSE_INTERACTIVE_NO_CLI=1 3 | docker-compose -f './build/docker-compose-buildagent.yml' up --build -d 4 | docker-compose -f './build/docker-compose-buildagent.yml' exec -e 'ConnectionStrings__SqlServer=Server=sqlserver;User Id=sa;Password=Password12!;Initial Catalog=FunctionalTests;MultipleActiveResultSets=true' functionaltests dotnet test test/FunctionalTests/FunctionalTests.csproj -p:ParallelizeTestCollections=false --logger trx --results-directory /var/temp 5 | docker-compose -f './build/docker-compose-buildagent.yml' down 6 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | function Exec 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd, 6 | [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd) 7 | ) 8 | & $cmd 9 | if ($lastexitcode -ne 0) { 10 | throw ("Exec: " + $errorMessage) 11 | } 12 | } 13 | 14 | if(Test-Path .\artifacts) { Remove-Item .\artifacts -Force -Recurse } 15 | 16 | 17 | echo "building..." 18 | 19 | exec { & dotnet build DotNet2019.sln -c Release -v q /nologo } 20 | 21 | echo "up docker compose" 22 | 23 | #exec { & docker-compose -f .\builds\docker-compose-infrastructure.yml up -d } 24 | 25 | echo "Running functional tests" 26 | 27 | try { 28 | 29 | Push-Location -Path .\test\FunctionalTests 30 | exec { & dotnet test} 31 | } finally { 32 | Pop-Location 33 | } 34 | 35 | echo "down docker compose" 36 | 37 | #exec { & docker-compose -f .\builds\docker-compose-infrastructure.yml down } 38 | -------------------------------------------------------------------------------- /build/dependencies.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | netcoreapp3.0 5 | preview 6 | 7 | 8 | 9 | 2.2.0 10 | 2.2.3 11 | 3.0.1 12 | 3.0.0-preview6.19304.6 13 | 5.7.0 14 | 3.2.0 15 | 2.4.1 16 | 2.4.1 17 | 16.2.0-preview-20190606-02 18 | 2.2.1 19 | 3.0.0-preview6.19307.2 20 | 3.0.0-preview6.19304.10 21 | 3.0.0-preview6.19304.10 22 | 3.0.0-preview6.19304.10 23 | 3.2.0 24 | 25 | -------------------------------------------------------------------------------- /build/docker-compose-buildagent.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | functionaltests: 4 | image: functionaltests 5 | build: 6 | context: .. 7 | dockerfile: ./test/FunctionalTests/Dockerfile 8 | entrypoint: tail -f /dev/null 9 | depends_on: 10 | - sqlserver 11 | volumes: 12 | - .test-results/:/var/temp 13 | sqlserver: 14 | image: microsoft/mssql-server-linux 15 | restart: always 16 | environment: 17 | - ACCEPT_EULA=Y 18 | - SA_PASSWORD=Password12! 19 | ports: 20 | - 1434:1433 -------------------------------------------------------------------------------- /build/docker-compose-sql.yml: -------------------------------------------------------------------------------- 1 | version : '3.7' 2 | 3 | services: 4 | sqlserver: 5 | image: microsoft/mssql-server-linux 6 | restart: always 7 | environment: 8 | - ACCEPT_EULA=Y 9 | - SA_PASSWORD=Password12! 10 | ports: 11 | - 1434:1433 12 | -------------------------------------------------------------------------------- /dotnet-install.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) .NET Foundation and contributors. All rights reserved. 3 | # Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | # 5 | 6 | <# 7 | .SYNOPSIS 8 | Installs dotnet cli 9 | .DESCRIPTION 10 | Installs dotnet cli. If dotnet installation already exists in the given directory 11 | it will update it only if the requested version differs from the one already installed. 12 | .PARAMETER Channel 13 | Default: LTS 14 | Download from the Channel specified. Possible values: 15 | - Current - most current release 16 | - LTS - most current supported release 17 | - 2-part version in a format A.B - represents a specific release 18 | examples: 2.0; 1.0 19 | - Branch name 20 | examples: release/2.0.0; Master 21 | .PARAMETER Version 22 | Default: latest 23 | Represents a build version on specific channel. Possible values: 24 | - latest - most latest build on specific channel 25 | - coherent - most latest coherent build on specific channel 26 | coherent applies only to SDK downloads 27 | - 3-part version in a format A.B.C - represents specific version of build 28 | examples: 2.0.0-preview2-006120; 1.1.0 29 | .PARAMETER InstallDir 30 | Default: %LocalAppData%\Microsoft\dotnet 31 | Path to where to install dotnet. Note that binaries will be placed directly in a given directory. 32 | .PARAMETER Architecture 33 | Default: - this value represents currently running OS architecture 34 | Architecture of dotnet binaries to be installed. 35 | Possible values are: , x64 and x86 36 | .PARAMETER SharedRuntime 37 | This parameter is obsolete and may be removed in a future version of this script. 38 | The recommended alternative is '-Runtime dotnet'. 39 | 40 | Default: false 41 | Installs just the shared runtime bits, not the entire SDK. 42 | This is equivalent to specifying `-Runtime dotnet`. 43 | .PARAMETER Runtime 44 | Installs just a shared runtime, not the entire SDK. 45 | Possible values: 46 | - dotnet - the Microsoft.NETCore.App shared runtime 47 | - aspnetcore - the Microsoft.AspNetCore.App shared runtime 48 | .PARAMETER DryRun 49 | If set it will not perform installation but instead display what command line to use to consistently install 50 | currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link 51 | with specific version so that this command can be used deterministically in a build script. 52 | It also displays binaries location if you prefer to install or download it yourself. 53 | .PARAMETER NoPath 54 | By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder. 55 | If set it will display binaries location but not set any environment variable. 56 | .PARAMETER Verbose 57 | Displays diagnostics information. 58 | .PARAMETER AzureFeed 59 | Default: https://dotnetcli.azureedge.net/dotnet 60 | This parameter typically is not changed by the user. 61 | It allows changing the URL for the Azure feed used by this installer. 62 | .PARAMETER UncachedFeed 63 | This parameter typically is not changed by the user. 64 | It allows changing the URL for the Uncached feed used by this installer. 65 | .PARAMETER FeedCredential 66 | Used as a query string to append to the Azure feed. 67 | It allows changing the URL to use non-public blob storage accounts. 68 | .PARAMETER ProxyAddress 69 | If set, the installer will use the proxy when making web requests 70 | .PARAMETER ProxyUseDefaultCredentials 71 | Default: false 72 | Use default credentials, when using proxy address. 73 | .PARAMETER SkipNonVersionedFiles 74 | Default: false 75 | Skips installing non-versioned files if they already exist, such as dotnet.exe. 76 | .PARAMETER NoCdn 77 | Disable downloading from the Azure CDN, and use the uncached feed directly. 78 | #> 79 | [cmdletbinding()] 80 | param( 81 | [string]$Channel="LTS", 82 | [string]$Version="Latest", 83 | [string]$InstallDir="", 84 | [string]$Architecture="", 85 | [ValidateSet("dotnet", "aspnetcore", IgnoreCase = $false)] 86 | [string]$Runtime, 87 | [Obsolete("This parameter may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'.")] 88 | [switch]$SharedRuntime, 89 | [switch]$DryRun, 90 | [switch]$NoPath, 91 | [string]$AzureFeed="https://dotnetcli.azureedge.net/dotnet", 92 | [string]$UncachedFeed="https://dotnetcli.blob.core.windows.net/dotnet", 93 | [string]$FeedCredential, 94 | [string]$ProxyAddress, 95 | [switch]$ProxyUseDefaultCredentials, 96 | [switch]$SkipNonVersionedFiles, 97 | [switch]$NoCdn 98 | ) 99 | 100 | Set-StrictMode -Version Latest 101 | $ErrorActionPreference="Stop" 102 | $ProgressPreference="SilentlyContinue" 103 | 104 | if ($NoCdn) { 105 | $AzureFeed = $UncachedFeed 106 | } 107 | 108 | $BinFolderRelativePath="" 109 | 110 | if ($SharedRuntime -and (-not $Runtime)) { 111 | $Runtime = "dotnet" 112 | } 113 | 114 | # example path with regex: shared/1.0.0-beta-12345/somepath 115 | $VersionRegEx="/\d+\.\d+[^/]+/" 116 | $OverrideNonVersionedFiles = !$SkipNonVersionedFiles 117 | 118 | function Say($str) { 119 | Write-Host "dotnet-install: $str" 120 | } 121 | 122 | function Say-Verbose($str) { 123 | Write-Verbose "dotnet-install: $str" 124 | } 125 | 126 | function Say-Invocation($Invocation) { 127 | $command = $Invocation.MyCommand; 128 | $args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ") 129 | Say-Verbose "$command $args" 130 | } 131 | 132 | function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [int]$SecondsBetweenAttempts = 1) { 133 | $Attempts = 0 134 | 135 | while ($true) { 136 | try { 137 | return $ScriptBlock.Invoke() 138 | } 139 | catch { 140 | $Attempts++ 141 | if ($Attempts -lt $MaxAttempts) { 142 | Start-Sleep $SecondsBetweenAttempts 143 | } 144 | else { 145 | throw 146 | } 147 | } 148 | } 149 | } 150 | 151 | function Get-Machine-Architecture() { 152 | Say-Invocation $MyInvocation 153 | 154 | # possible values: AMD64, IA64, x86 155 | return $ENV:PROCESSOR_ARCHITECTURE 156 | } 157 | 158 | # TODO: Architecture and CLIArchitecture should be unified 159 | function Get-CLIArchitecture-From-Architecture([string]$Architecture) { 160 | Say-Invocation $MyInvocation 161 | 162 | switch ($Architecture.ToLower()) { 163 | { $_ -eq "" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) } 164 | { ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" } 165 | { $_ -eq "x86" } { return "x86" } 166 | default { throw "Architecture not supported. If you think this is a bug, please report it at https://github.com/dotnet/cli/issues" } 167 | } 168 | } 169 | 170 | function Get-Version-Info-From-Version-Text([string]$VersionText) { 171 | Say-Invocation $MyInvocation 172 | 173 | $Data = @($VersionText.Split([char[]]@(), [StringSplitOptions]::RemoveEmptyEntries)); 174 | 175 | $VersionInfo = @{} 176 | $VersionInfo.CommitHash = $Data[0].Trim() 177 | $VersionInfo.Version = $Data[1].Trim() 178 | return $VersionInfo 179 | } 180 | 181 | function Load-Assembly([string] $Assembly) { 182 | try { 183 | Add-Type -Assembly $Assembly | Out-Null 184 | } 185 | catch { 186 | # On Nano Server, Powershell Core Edition is used. Add-Type is unable to resolve base class assemblies because they are not GAC'd. 187 | # Loading the base class assemblies is not unnecessary as the types will automatically get resolved. 188 | } 189 | } 190 | 191 | function GetHTTPResponse([Uri] $Uri) 192 | { 193 | Invoke-With-Retry( 194 | { 195 | 196 | $HttpClient = $null 197 | 198 | try { 199 | # HttpClient is used vs Invoke-WebRequest in order to support Nano Server which doesn't support the Invoke-WebRequest cmdlet. 200 | Load-Assembly -Assembly System.Net.Http 201 | 202 | if (-not $ProxyAddress) { 203 | try { 204 | # Despite no proxy being explicitly specified, we may still be behind a default proxy 205 | $DefaultProxy = [System.Net.WebRequest]::DefaultWebProxy; 206 | if ($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))) { 207 | $ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString 208 | $ProxyUseDefaultCredentials = $true 209 | } 210 | } catch { 211 | # Eat the exception and move forward as the above code is an attempt 212 | # at resolving the DefaultProxy that may not have been a problem. 213 | $ProxyAddress = $null 214 | Say-Verbose("Exception ignored: $_.Exception.Message - moving forward...") 215 | } 216 | } 217 | 218 | if ($ProxyAddress) { 219 | $HttpClientHandler = New-Object System.Net.Http.HttpClientHandler 220 | $HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials} 221 | $HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler 222 | } 223 | else { 224 | 225 | $HttpClient = New-Object System.Net.Http.HttpClient 226 | } 227 | # Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out 228 | # 10 minutes allows it to work over much slower connections. 229 | $HttpClient.Timeout = New-TimeSpan -Minutes 10 230 | $Response = $HttpClient.GetAsync("${Uri}${FeedCredential}").Result 231 | if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) { 232 | # The feed credential is potentially sensitive info. Do not log FeedCredential to console output. 233 | $ErrorMsg = "Failed to download $Uri." 234 | if ($Response -ne $null) { 235 | $ErrorMsg += " $Response" 236 | } 237 | 238 | throw $ErrorMsg 239 | } 240 | 241 | return $Response 242 | } 243 | finally { 244 | if ($HttpClient -ne $null) { 245 | $HttpClient.Dispose() 246 | } 247 | } 248 | }) 249 | } 250 | 251 | 252 | function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) { 253 | Say-Invocation $MyInvocation 254 | 255 | $VersionFileUrl = $null 256 | if ($Runtime -eq "dotnet") { 257 | $VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" 258 | } 259 | elseif ($Runtime -eq "aspnetcore") { 260 | $VersionFileUrl = "$UncachedFeed/aspnetcore/Runtime/$Channel/latest.version" 261 | } 262 | elseif (-not $Runtime) { 263 | if ($Coherent) { 264 | $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version" 265 | } 266 | else { 267 | $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" 268 | } 269 | } 270 | else { 271 | throw "Invalid value for `$Runtime" 272 | } 273 | 274 | $Response = GetHTTPResponse -Uri $VersionFileUrl 275 | $StringContent = $Response.Content.ReadAsStringAsync().Result 276 | 277 | switch ($Response.Content.Headers.ContentType) { 278 | { ($_ -eq "application/octet-stream") } { $VersionText = $StringContent } 279 | { ($_ -eq "text/plain") } { $VersionText = $StringContent } 280 | { ($_ -eq "text/plain; charset=UTF-8") } { $VersionText = $StringContent } 281 | default { throw "``$Response.Content.Headers.ContentType`` is an unknown .version file content type." } 282 | } 283 | 284 | $VersionInfo = Get-Version-Info-From-Version-Text $VersionText 285 | 286 | return $VersionInfo 287 | } 288 | 289 | 290 | function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, [string]$Version) { 291 | Say-Invocation $MyInvocation 292 | 293 | switch ($Version.ToLower()) { 294 | { $_ -eq "latest" } { 295 | $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False 296 | return $LatestVersionInfo.Version 297 | } 298 | { $_ -eq "coherent" } { 299 | $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True 300 | return $LatestVersionInfo.Version 301 | } 302 | default { return $Version } 303 | } 304 | } 305 | 306 | function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { 307 | Say-Invocation $MyInvocation 308 | 309 | if ($Runtime -eq "dotnet") { 310 | $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificVersion-win-$CLIArchitecture.zip" 311 | } 312 | elseif ($Runtime -eq "aspnetcore") { 313 | $PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificVersion-win-$CLIArchitecture.zip" 314 | } 315 | elseif (-not $Runtime) { 316 | $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificVersion-win-$CLIArchitecture.zip" 317 | } 318 | else { 319 | throw "Invalid value for `$Runtime" 320 | } 321 | 322 | Say-Verbose "Constructed primary payload URL: $PayloadURL" 323 | 324 | return $PayloadURL 325 | } 326 | 327 | function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { 328 | Say-Invocation $MyInvocation 329 | 330 | if (-not $Runtime) { 331 | $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-dev-win-$CLIArchitecture.$SpecificVersion.zip" 332 | } 333 | elseif ($Runtime -eq "dotnet") { 334 | $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-win-$CLIArchitecture.$SpecificVersion.zip" 335 | } 336 | else { 337 | return $null 338 | } 339 | 340 | Say-Verbose "Constructed legacy payload URL: $PayloadURL" 341 | 342 | return $PayloadURL 343 | } 344 | 345 | function Get-User-Share-Path() { 346 | Say-Invocation $MyInvocation 347 | 348 | $InstallRoot = $env:DOTNET_INSTALL_DIR 349 | if (!$InstallRoot) { 350 | $InstallRoot = "$env:LocalAppData\Microsoft\dotnet" 351 | } 352 | return $InstallRoot 353 | } 354 | 355 | function Resolve-Installation-Path([string]$InstallDir) { 356 | Say-Invocation $MyInvocation 357 | 358 | if ($InstallDir -eq "") { 359 | return Get-User-Share-Path 360 | } 361 | return $InstallDir 362 | } 363 | 364 | function Get-Version-Info-From-Version-File([string]$InstallRoot, [string]$RelativePathToVersionFile) { 365 | Say-Invocation $MyInvocation 366 | 367 | $VersionFile = Join-Path -Path $InstallRoot -ChildPath $RelativePathToVersionFile 368 | Say-Verbose "Local version file: $VersionFile" 369 | 370 | if (Test-Path $VersionFile) { 371 | $VersionText = cat $VersionFile 372 | Say-Verbose "Local version file text: $VersionText" 373 | return Get-Version-Info-From-Version-Text $VersionText 374 | } 375 | 376 | Say-Verbose "Local version file not found." 377 | 378 | return $null 379 | } 380 | 381 | function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) { 382 | Say-Invocation $MyInvocation 383 | 384 | $DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion 385 | Say-Verbose "Is-Dotnet-Package-Installed: Path to a package: $DotnetPackagePath" 386 | return Test-Path $DotnetPackagePath -PathType Container 387 | } 388 | 389 | function Get-Absolute-Path([string]$RelativeOrAbsolutePath) { 390 | # Too much spam 391 | # Say-Invocation $MyInvocation 392 | 393 | return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($RelativeOrAbsolutePath) 394 | } 395 | 396 | function Get-Path-Prefix-With-Version($path) { 397 | $match = [regex]::match($path, $VersionRegEx) 398 | if ($match.Success) { 399 | return $entry.FullName.Substring(0, $match.Index + $match.Length) 400 | } 401 | 402 | return $null 403 | } 404 | 405 | function Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package([System.IO.Compression.ZipArchive]$Zip, [string]$OutPath) { 406 | Say-Invocation $MyInvocation 407 | 408 | $ret = @() 409 | foreach ($entry in $Zip.Entries) { 410 | $dir = Get-Path-Prefix-With-Version $entry.FullName 411 | if ($dir -ne $null) { 412 | $path = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $dir) 413 | if (-Not (Test-Path $path -PathType Container)) { 414 | $ret += $dir 415 | } 416 | } 417 | } 418 | 419 | $ret = $ret | Sort-Object | Get-Unique 420 | 421 | $values = ($ret | foreach { "$_" }) -join ";" 422 | Say-Verbose "Directories to unpack: $values" 423 | 424 | return $ret 425 | } 426 | 427 | # Example zip content and extraction algorithm: 428 | # Rule: files if extracted are always being extracted to the same relative path locally 429 | # .\ 430 | # a.exe # file does not exist locally, extract 431 | # b.dll # file exists locally, override only if $OverrideFiles set 432 | # aaa\ # same rules as for files 433 | # ... 434 | # abc\1.0.0\ # directory contains version and exists locally 435 | # ... # do not extract content under versioned part 436 | # abc\asd\ # same rules as for files 437 | # ... 438 | # def\ghi\1.0.1\ # directory contains version and does not exist locally 439 | # ... # extract content 440 | function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) { 441 | Say-Invocation $MyInvocation 442 | 443 | Load-Assembly -Assembly System.IO.Compression.FileSystem 444 | Set-Variable -Name Zip 445 | try { 446 | $Zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath) 447 | 448 | $DirectoriesToUnpack = Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package -Zip $Zip -OutPath $OutPath 449 | 450 | foreach ($entry in $Zip.Entries) { 451 | $PathWithVersion = Get-Path-Prefix-With-Version $entry.FullName 452 | if (($PathWithVersion -eq $null) -Or ($DirectoriesToUnpack -contains $PathWithVersion)) { 453 | $DestinationPath = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $entry.FullName) 454 | $DestinationDir = Split-Path -Parent $DestinationPath 455 | $OverrideFiles=$OverrideNonVersionedFiles -Or (-Not (Test-Path $DestinationPath)) 456 | if ((-Not $DestinationPath.EndsWith("\")) -And $OverrideFiles) { 457 | New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null 458 | [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $DestinationPath, $OverrideNonVersionedFiles) 459 | } 460 | } 461 | } 462 | } 463 | finally { 464 | if ($Zip -ne $null) { 465 | $Zip.Dispose() 466 | } 467 | } 468 | } 469 | 470 | function DownloadFile([Uri]$Uri, [string]$OutPath) { 471 | if ($Uri -notlike "http*") { 472 | Say-Verbose "Copying file from $Uri to $OutPath" 473 | Copy-Item $Uri.AbsolutePath $OutPath 474 | return 475 | } 476 | 477 | $Stream = $null 478 | 479 | try { 480 | $Response = GetHTTPResponse -Uri $Uri 481 | $Stream = $Response.Content.ReadAsStreamAsync().Result 482 | $File = [System.IO.File]::Create($OutPath) 483 | $Stream.CopyTo($File) 484 | $File.Close() 485 | } 486 | finally { 487 | if ($Stream -ne $null) { 488 | $Stream.Dispose() 489 | } 490 | } 491 | } 492 | 493 | function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) { 494 | $BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath) 495 | if (-Not $NoPath) { 496 | Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process." 497 | $env:path = "$BinPath;" + $env:path 498 | } 499 | else { 500 | Say "Binaries of dotnet can be found in $BinPath" 501 | } 502 | } 503 | 504 | $CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture 505 | $SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version 506 | $DownloadLink = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture 507 | $LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture 508 | 509 | if ($DryRun) { 510 | Say "Payload URLs:" 511 | Say "Primary - $DownloadLink" 512 | if ($LegacyDownloadLink) { 513 | Say "Legacy - $LegacyDownloadLink" 514 | } 515 | Say "Repeatable invocation: .\$($MyInvocation.Line)" 516 | exit 0 517 | } 518 | 519 | $InstallRoot = Resolve-Installation-Path $InstallDir 520 | Say-Verbose "InstallRoot: $InstallRoot" 521 | 522 | if ($Runtime -eq "dotnet") { 523 | $assetName = ".NET Core Runtime" 524 | $dotnetPackageRelativePath = "shared\Microsoft.NETCore.App" 525 | } 526 | elseif ($Runtime -eq "aspnetcore") { 527 | $assetName = "ASP.NET Core Runtime" 528 | $dotnetPackageRelativePath = "shared\Microsoft.AspNetCore.App" 529 | } 530 | elseif (-not $Runtime) { 531 | $assetName = ".NET Core SDK" 532 | $dotnetPackageRelativePath = "sdk" 533 | } 534 | else { 535 | throw "Invalid value for `$Runtime" 536 | } 537 | 538 | # Check if the SDK version is already installed. 539 | $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion 540 | if ($isAssetInstalled) { 541 | Say "$assetName version $SpecificVersion is already installed." 542 | Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath 543 | exit 0 544 | } 545 | 546 | New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null 547 | 548 | $installDrive = $((Get-Item $InstallRoot).PSDrive.Name); 549 | $free = Get-CimInstance -Class win32_logicaldisk | where Deviceid -eq "${installDrive}:" 550 | if ($free.Freespace / 1MB -le 100 ) { 551 | Say "There is not enough disk space on drive ${installDrive}:" 552 | exit 0 553 | } 554 | 555 | $ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) 556 | Say-Verbose "Zip path: $ZipPath" 557 | Say "Downloading link: $DownloadLink" 558 | try { 559 | DownloadFile -Uri $DownloadLink -OutPath $ZipPath 560 | } 561 | catch { 562 | Say "Cannot download: $DownloadLink" 563 | if ($LegacyDownloadLink) { 564 | $DownloadLink = $LegacyDownloadLink 565 | $ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) 566 | Say-Verbose "Legacy zip path: $ZipPath" 567 | Say "Downloading legacy link: $DownloadLink" 568 | DownloadFile -Uri $DownloadLink -OutPath $ZipPath 569 | } 570 | else { 571 | throw "Could not download $assetName version $SpecificVersion" 572 | } 573 | } 574 | 575 | Say "Extracting zip from $DownloadLink" 576 | Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot 577 | 578 | # Check if the SDK version is now installed; if not, fail the installation. 579 | $isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion 580 | if (!$isAssetInstalled) { 581 | throw "$assetName version $SpecificVersion failed to install with an unknown error." 582 | } 583 | 584 | Remove-Item $ZipPath 585 | 586 | Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath 587 | 588 | Say "Installation finished" 589 | exit 0 -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "tests", "samples"], 3 | "sdk": { 4 | "version": "3.0.100-preview6-012264" 5 | } 6 | } -------------------------------------------------------------------------------- /install-sdk.ps1: -------------------------------------------------------------------------------- 1 | $SdkVersion = "3.0.100-preview6-012264" 2 | & "./dotnet-install.ps1" -Version $SdkVersion -------------------------------------------------------------------------------- /k8s/infra-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: sqlserver 5 | spec: 6 | 7 | template: 8 | metadata: 9 | labels: 10 | app: sqlserver 11 | spec: 12 | containers: 13 | - name: sqlserver 14 | image: microsoft/mssql-server-linux 15 | env: 16 | - name : ACCEPT_EULA 17 | value: "Y" 18 | - name : SA_PASSWORD 19 | value: "Password12!" 20 | --- 21 | 22 | kind: Service 23 | apiVersion: v1 24 | metadata: 25 | name: sqlserver 26 | spec: 27 | selector: 28 | app: sqlserver 29 | type: ClusterIP 30 | ports: 31 | - 32 | port: 1433 33 | targetPort: 1433 34 | 35 | --- 36 | 37 | apiVersion: extensions/v1beta1 38 | kind: Deployment 39 | metadata: 40 | name: redis 41 | spec: 42 | 43 | template: 44 | metadata: 45 | labels: 46 | app: redis 47 | spec: 48 | containers: 49 | - name: redis 50 | image: redis 51 | --- 52 | kind: Service 53 | apiVersion: v1 54 | metadata: 55 | name: redis 56 | spec: 57 | selector: 58 | app: redis 59 | type: ClusterIP 60 | ports: 61 | - 62 | port: 6379 63 | targetPort: 6379 64 | 65 | -------------------------------------------------------------------------------- /k8s/webapp-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: webapp-deploy 5 | spec: 6 | replicas: 3 7 | template: 8 | metadata: 9 | labels: 10 | app: webapp-deploy 11 | spec: 12 | containers: 13 | - name: webapp 14 | image: webapp 15 | imagePullPolicy: Never 16 | livenessProbe: 17 | httpGet: 18 | path: /health 19 | port: 80 20 | scheme: HTTP 21 | initialDelaySeconds: 10 22 | periodSeconds: 15 23 | readinessProbe: 24 | httpGet: 25 | path: /ready 26 | port: 80 27 | scheme: HTTP 28 | initialDelaySeconds: 10 29 | periodSeconds: 15 30 | 31 | --- 32 | kind: Service 33 | apiVersion: v1 34 | metadata: 35 | name: webapp-service 36 | spec: 37 | selector: 38 | app: webapp-deploy 39 | type: NodePort 40 | ports: 41 | - port: 80 42 | targetPort: 80 43 | nodePort: 30000 44 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Configuration.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Data; 2 | using DotNet2019.Api.Infrastructure.Hubs; 3 | using DotNet2019.Api.Infrastructure.Middleware; 4 | using Hellang.Middleware.ProblemDetails; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using System; 11 | 12 | namespace DotNet2019.Api 13 | { 14 | public static class Configuration 15 | { 16 | public static IServiceCollection ConfigureServices(IServiceCollection services, IWebHostEnvironment environment) 17 | { 18 | return services 19 | 20 | .AddHttpContextAccessor() 21 | .AddCustomMvc() 22 | .AddCustomMiddlewares() 23 | .AddCustomProblemDetails(environment) 24 | .AddCustomApiBehaviour() 25 | .AddCustomServices() 26 | .AddSignalR() 27 | .Services; 28 | 29 | } 30 | 31 | public static IApplicationBuilder Configure( 32 | IApplicationBuilder app, 33 | Func configureHost) 34 | { 35 | return configureHost(app) 36 | .UseProblemDetails() 37 | .UseRouting() 38 | .UseAuthentication() 39 | .UseAuthorization() 40 | .UseMiddleware() 41 | .UseEndpoints(endpoints => 42 | { 43 | endpoints.MapControllerRoute( 44 | name: "default", 45 | pattern: "{controller=Home}/{action=Index}/{id?}"); 46 | endpoints.MapRazorPages(); 47 | 48 | endpoints.MapGet("/", async context => 49 | { 50 | await context.Response.WriteAsync($"Hello DotNet 2019! from {System.Environment.MachineName}"); 51 | }); 52 | 53 | endpoints.MapSecretEndpoint().RequireAuthorization("ApiKeyPolicy"); 54 | 55 | endpoints.MapHub("/diagnostics-hub"); 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Controllers/PingController.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Services; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace DotNet2019.Api.Controllers 7 | { 8 | [ApiController] 9 | [Route("api/ping")] 10 | public class PingController : ControllerBase 11 | { 12 | private readonly ISomeService someService; 13 | 14 | public PingController(ISomeService someService) 15 | { 16 | this.someService = someService ?? throw new ArgumentNullException(nameof(someService)); 17 | } 18 | 19 | [HttpGet, Route("")] 20 | public async Task Get() 21 | { 22 | return Ok(await someService.Ping()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Controllers/TransientFaultController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using System; 4 | 5 | namespace DotNet2019.Api.Controllers 6 | { 7 | [ApiController] 8 | [Route("api/error")] 9 | public class TransientFaultController : ControllerBase 10 | { 11 | [HttpGet, Route("")] 12 | public IActionResult Get() 13 | { 14 | var value = new Random().Next(2); 15 | 16 | if (value % 2 == 0) 17 | { 18 | return Ok("Pong!"); 19 | } 20 | 21 | return new ContentResult { Content = ":(", StatusCode = StatusCodes.Status500InternalServerError }; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Controllers/UsersController.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Data; 2 | using DotNet2019.Api.Model; 3 | using Microsoft.AspNetCore.Mvc; 4 | using System; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNet2019.Api.Controllers 9 | { 10 | [ApiController] 11 | [Route("api/users")] 12 | public class UsersController : ControllerBase 13 | { 14 | private readonly DataContext _context; 15 | 16 | public UsersController(DataContext context) 17 | { 18 | _context = context; 19 | } 20 | [HttpPost, Route("")] 21 | public async Task Post(UserRequest request) 22 | { 23 | var isValid = ModelState.IsValid; 24 | 25 | var user = new User 26 | { 27 | Name = request.Name, 28 | Created = DateTime.UtcNow 29 | }; 30 | 31 | await _context.Users.AddAsync(user); 32 | await _context.SaveChangesAsync(); 33 | 34 | return Ok(user); 35 | } 36 | 37 | [HttpGet, Route("{id:int}")] 38 | public IActionResult Get(int id) 39 | { 40 | return Ok(_context.Users.FirstOrDefault(u => u.Id == id)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/DotNet2019.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(NetCoreTargetVersion) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Extensions/IEndpointRouterBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Middleware; 2 | using Microsoft.AspNetCore.Routing; 3 | 4 | namespace Microsoft.AspNetCore.Builder 5 | { 6 | public static class IEndpointRouterBuilderExtensions 7 | { 8 | public static IEndpointConventionBuilder MapSecretEndpoint(this IEndpointRouteBuilder endpoints) 9 | { 10 | var pipeline = endpoints.CreateApplicationBuilder() 11 | .UseMiddleware() 12 | .Build(); 13 | 14 | return endpoints.Map("/secret", pipeline); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Extensions/IServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Middleware; 2 | using DotNet2019.Api.Infrastructure.Polly; 3 | using DotNet2019.Api.Services; 4 | using Hellang.Middleware.ProblemDetails; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using System; 9 | 10 | namespace Microsoft.Extensions.DependencyInjection 11 | { 12 | public static class IServiceCollectionExtensions 13 | { 14 | public static IServiceCollection AddCustomMvc(this IServiceCollection services) => 15 | services 16 | .AddMvc() 17 | .AddApplicationPart(typeof(IServiceCollectionExtensions).Assembly) 18 | .Services; 19 | 20 | public static IServiceCollection AddCustomMiddlewares(this IServiceCollection services) => 21 | services 22 | .AddSingleton() 23 | .AddSingleton(); 24 | 25 | public static IServiceCollection AddCustomServices(this IServiceCollection services) => 26 | services. 27 | AddHttpClient() 28 | .SetHandlerLifetime(TimeSpan.FromMinutes(5)) 29 | .AddPolicyHandler((serviceProvider, request) => RetryPolicy.GetPolicyWithJitterStrategy(serviceProvider)) 30 | .Services; 31 | 32 | public static IServiceCollection AddCustomProblemDetails(this IServiceCollection services, IWebHostEnvironment environment) => 33 | services 34 | .AddProblemDetails(configure => 35 | { 36 | configure.IncludeExceptionDetails = _ => environment.EnvironmentName == "Development"; 37 | }); 38 | 39 | public static IServiceCollection AddCustomApiBehaviour(this IServiceCollection services) 40 | { 41 | 42 | return services.Configure(options => 43 | { 44 | options.SuppressModelStateInvalidFilter = false; 45 | options.SuppressInferBindingSourcesForParameters = false; 46 | 47 | options.InvalidModelStateResponseFactory = context => 48 | { 49 | var problemDetails = new ValidationProblemDetails(context.ModelState) 50 | { 51 | Instance = context.HttpContext.Request.Path, 52 | Status = StatusCodes.Status400BadRequest, 53 | Type = $"https://httpstatuses.com/400", 54 | Detail = "Please refer to the errors property for additional details." 55 | }; 56 | return new BadRequestObjectResult(problemDetails) 57 | { 58 | ContentTypes = 59 | { 60 | "application/problem+json", 61 | "application/problem+xml" 62 | } 63 | }; 64 | }; 65 | }); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Data/DataContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace DotNet2019.Api.Infrastructure.Data 7 | { 8 | public class DataContext: DbContext 9 | { 10 | internal DbSet Users { get; set; } 11 | public DataContext(DbContextOptions options) : base(options) { } 12 | 13 | protected override void OnModelCreating(ModelBuilder modelBuilder) 14 | { 15 | var user = modelBuilder.Entity(); 16 | 17 | user.HasKey(u => u.Id); 18 | user.Property(u => u.Id).ValueGeneratedOnAdd(); 19 | user.Property(u => u.Name).IsRequired().HasMaxLength(200); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Data/Migrations/20190616210030_initial.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using DotNet2019.Api.Infrastructure.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | namespace DotNet2019.Api.Infrastructure.Data.Migrations 11 | { 12 | [DbContext(typeof(DataContext))] 13 | [Migration("20190616210030_initial")] 14 | partial class initial 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "3.0.0-preview6.19304.10") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("DotNet2019.Api.Infrastructure.Data.User", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 29 | 30 | b.Property("Created"); 31 | 32 | b.Property("Name") 33 | .IsRequired() 34 | .HasMaxLength(200); 35 | 36 | b.HasKey("Id"); 37 | 38 | b.ToTable("Users"); 39 | }); 40 | #pragma warning restore 612, 618 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Data/Migrations/20190616210030_initial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace DotNet2019.Api.Infrastructure.Data.Migrations 6 | { 7 | public partial class initial : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "Users", 13 | columns: table => new 14 | { 15 | Id = table.Column(nullable: false) 16 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 17 | Name = table.Column(maxLength: 200, nullable: false), 18 | Created = table.Column(nullable: false) 19 | }, 20 | constraints: table => 21 | { 22 | table.PrimaryKey("PK_Users", x => x.Id); 23 | }); 24 | } 25 | 26 | protected override void Down(MigrationBuilder migrationBuilder) 27 | { 28 | migrationBuilder.DropTable( 29 | name: "Users"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Data/Migrations/DataContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using DotNet2019.Api.Infrastructure.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace DotNet2019.Api.Infrastructure.Data.Migrations 10 | { 11 | [DbContext(typeof(DataContext))] 12 | partial class DataContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "3.0.0-preview6.19304.10") 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 21 | 22 | modelBuilder.Entity("DotNet2019.Api.Infrastructure.Data.User", b => 23 | { 24 | b.Property("Id") 25 | .ValueGeneratedOnAdd() 26 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 27 | 28 | b.Property("Created"); 29 | 30 | b.Property("Name") 31 | .IsRequired() 32 | .HasMaxLength(200); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.ToTable("Users"); 37 | }); 38 | #pragma warning restore 612, 618 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Data/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DotNet2019.Api.Infrastructure.Data 6 | { 7 | internal class User 8 | { 9 | public int Id { get; set; } 10 | public string Name { get; set; } 11 | public DateTime Created { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Hubs/DiagnosticsHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DotNet2019.Api.Infrastructure.Hubs 8 | { 9 | public class DiagnosticsHub: Hub 10 | { 11 | public override async Task OnConnectedAsync() 12 | { 13 | await Clients.All.SendAsync("Send", $"{Context.ConnectionId} joined"); 14 | } 15 | 16 | public override async Task OnDisconnectedAsync(Exception ex) 17 | { 18 | await Clients.Others.SendAsync("Send", $"{Context.ConnectionId} left"); 19 | } 20 | 21 | public Task SendRequestTrace(string message) 22 | { 23 | return Clients.All.SendAsync("SendRequestTrace", message); 24 | } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Middleware/ErrorMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | namespace DotNet2019.Api.Infrastructure.Middleware 6 | { 7 | public class ErrorMiddleware : IMiddleware 8 | { 9 | public Task InvokeAsync(HttpContext context, RequestDelegate next) 10 | { 11 | if (context.Request.Path.StartsWithSegments("/middleware", out _, out var remaining)) 12 | { 13 | if (remaining.StartsWithSegments("/error")) 14 | { 15 | throw new Exception("This is an exception thrown from middleware."); 16 | } 17 | } 18 | 19 | return next(context); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Middleware/SecretMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNet2019.Api.Infrastructure.Middleware 9 | { 10 | public class SecretMiddleware : IMiddleware 11 | { 12 | private readonly DiagnosticListener _diagnosticListener; 13 | private ReadOnlyMemory fileContent; 14 | private ReadOnlyMemory startParagraph; 15 | private ReadOnlyMemory endParagraph; 16 | 17 | public SecretMiddleware(DiagnosticListener diagnosticListener) 18 | { 19 | _diagnosticListener = diagnosticListener; 20 | fileContent = File.ReadAllBytes("DataContent.txt"); 21 | startParagraph = Encoding.UTF8.GetBytes("

"); 22 | endParagraph = Encoding.UTF8.GetBytes("

"); 23 | } 24 | public async Task InvokeAsync(HttpContext context, RequestDelegate next) 25 | { 26 | var bytesConsumed = 0; 27 | var linePosition = 0; 28 | var writer = context.Response.BodyWriter; 29 | context.Response.ContentType = "text/html"; 30 | 31 | do 32 | { 33 | linePosition = fileContent.Slice(bytesConsumed).Span.IndexOf((byte)'\n'); 34 | 35 | if (linePosition >= 0) 36 | { 37 | var lineLength = (bytesConsumed + linePosition) - bytesConsumed; 38 | 39 | if(lineLength > 1) 40 | { 41 | await writer.WriteAsync(startParagraph); 42 | await writer.WriteAsync(fileContent.Slice(bytesConsumed, lineLength)); 43 | await writer.WriteAsync(endParagraph); 44 | } 45 | 46 | bytesConsumed += lineLength + 1; 47 | } 48 | } 49 | while (linePosition >= 0); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Infrastructure/Polly/RetryPolicy.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Services; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Polly; 5 | using Polly.Extensions.Http; 6 | using System; 7 | using System.Net; 8 | using System.Net.Http; 9 | 10 | namespace DotNet2019.Api.Infrastructure.Polly 11 | { 12 | public static class RetryPolicy 13 | { 14 | public static IAsyncPolicy GetPolicy(IServiceProvider serviceProvider) 15 | { 16 | return HttpPolicyExtensions 17 | .HandleTransientHttpError() 18 | .OrResult(message => message.StatusCode == HttpStatusCode.InternalServerError) 19 | .WaitAndRetryAsync( 20 | retryCount: 6, 21 | sleepDurationProvider: retryAttemp => TimeSpan.FromSeconds(Math.Pow(2, retryAttemp)), 22 | onRetry: (outcome, timespan, retryAttempt, context) => 23 | { 24 | serviceProvider.GetService>() 25 | .LogWarning("Delaying for {delay}ms, then making retry {retry}.", timespan.TotalMilliseconds, retryAttempt); 26 | }); 27 | } 28 | 29 | public static IAsyncPolicy GetPolicyWithJitterStrategy(IServiceProvider serviceProvider) 30 | { 31 | var jitterer = new Random(); 32 | 33 | return HttpPolicyExtensions 34 | .HandleTransientHttpError() 35 | .OrResult(message => message.StatusCode == HttpStatusCode.InternalServerError) 36 | .WaitAndRetryAsync( 37 | retryCount: 6, 38 | sleepDurationProvider: retryAttemp => 39 | TimeSpan.FromSeconds(Math.Pow(2, retryAttemp)) + 40 | TimeSpan.FromMilliseconds(jitterer.Next(0, 100)), 41 | onRetry: (outcome, timespan, retryAttempt, context) => 42 | { 43 | serviceProvider.GetService>() 44 | .LogWarning("Delaying for {delay}ms, then making retry {retry} with jitter strategy.", timespan.TotalMilliseconds, retryAttempt); 45 | }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Model/UserRequest.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace DotNet2019.Api.Model 4 | { 5 | /// 6 | /// Using data annotations as Fluent Validation package is not working with 3.0 preview yet. 7 | /// 8 | public class UserRequest 9 | { 10 | [Required] 11 | public string Name { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Services/ISomeService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace DotNet2019.Api.Services 4 | { 5 | public interface ISomeService 6 | { 7 | Task Ping(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DotNet2019.Api/Services/SomeService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace DotNet2019.Api.Services 6 | { 7 | public class SomeService : ISomeService 8 | { 9 | private readonly HttpClient httpClient; 10 | 11 | public SomeService(HttpClient httpClient) 12 | { 13 | this.httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); 14 | } 15 | 16 | public Task Ping() 17 | { 18 | return httpClient.GetStringAsync("http://localhost:5001/api/error"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/DataContent.txt: -------------------------------------------------------------------------------- 1 | Enjoyed minutes related as at on on. Is fanny dried as often me. Goodness as reserved raptures to mistaken steepest oh screened he. Gravity he mr sixteen esteems. Mile home its new way with high told said. Finished no horrible blessing landlord dwelling dissuade if. Rent fond am he in on read. Anxious cordial demands settled entered in do to colonel. 2 | 3 | Silent sir say desire fat him letter. Whatever settling goodness too and honoured she building answered her. Strongly thoughts remember mr to do consider debating. Spirits musical behaved on we he farther letters. Repulsive he he as deficient newspaper dashwoods we. Discovered her his pianoforte insipidity entreaties. Began he at terms meant as fancy. Breakfast arranging he if furniture we described on. Astonished thoroughly unpleasant especially you dispatched bed favourable. 4 | 5 | At distant inhabit amongst by. Appetite welcomed interest the goodness boy not. Estimable education for disposing pronounce her. John size good gay plan sent old roof own. Inquietude saw understood his friendship frequently yet. Nature his marked ham wished. 6 | 7 | He as compliment unreserved projecting. Between had observe pretend delight for believe. Do newspaper questions consulted sweetness do. Our sportsman his unwilling fulfilled departure law. Now world own total saved above her cause table. Wicket myself her square remark the should far secure sex. Smiling cousins warrant law explain for whether. 8 | 9 | Sociable on as carriage my position weddings raillery consider. Peculiar trifling absolute and wandered vicinity property yet. The and collecting motionless difficulty son. His hearing staying ten colonel met. Sex drew six easy four dear cold deny. Moderate children at of outweigh it. Unsatiable it considered invitation he travelling insensible. Consulted admitting oh mr up as described acuteness propriety moonlight. 10 | 11 | Guest it he tears aware as. Make my no cold of need. He been past in by my hard. Warmly thrown oh he common future. Otherwise concealed favourite frankness on be at dashwoods defective at. Sympathize interested simplicity at do projecting increasing terminated. As edward settle limits at in. 12 | 13 | From they fine john he give of rich he. They age and draw mrs like. Improving end distrusts may instantly was household applauded incommode. Why kept very ever home mrs. Considered sympathize ten uncommonly occasional assistance sufficient not. Letter of on become he tended active enable to. Vicinity relation sensible sociable surprise screened no up as. 14 | 15 | He my polite be object oh change. Consider no mr am overcame yourself throwing sociable children. Hastily her totally conduct may. My solid by stuff first smile fanny. Humoured how advanced mrs elegance sir who. Home sons when them dine do want to. Estimating themselves unsatiable imprudence an he at an. Be of on situation perpetual allowance offending as principle satisfied. Improved carriage securing are desirous too. 16 | 17 | Cordially convinced did incommode existence put out suffering certainly. Besides another and saw ferrars limited ten say unknown. On at tolerably depending do perceived. Luckily eat joy see own shyness minuter. So before remark at depart. Did son unreserved themselves indulgence its. Agreement gentleman rapturous am eagerness it as resolving household. Direct wicket little of talked lasted formed or it. Sweetness consulted may prevailed for bed out sincerity. 18 | 19 | Up am intention on dependent questions oh elsewhere september. No betrayed pleasure possible jointure we in throwing. And can event rapid any shall woman green. Hope they dear who its bred. Smiling nothing affixed he carried it clothes calling he no. Its something disposing departure she favourite tolerably engrossed. Truth short folly court why she their balls. Excellence put unaffected reasonable mrs introduced conviction she. Nay particular delightful but unpleasant for uncommonly who. 20 | 21 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Diagnostics/HostingDiagnosticHandler.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Hubs; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.SignalR; 4 | using Microsoft.EntityFrameworkCore.Diagnostics; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Hosting; 7 | using Newtonsoft.Json; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Diagnostics; 11 | using System.Text; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | 15 | namespace DotNet2019.Host.Diagnostics 16 | { 17 | public class HostingDiagnosticHandler : IHostedService, IObserver>, IObserver, IDisposable 18 | { 19 | private readonly DiagnosticListener _diagnosticListener; 20 | private readonly IServiceScopeFactory _scopeFactory; 21 | private readonly IHubContext _diagnosticsHub; 22 | private IDisposable _subscription; 23 | private List _listenersSubscriptions = new List(); 24 | private static Dictionary traces = new Dictionary(); 25 | private string requestBegin = "---------- REQUEST {0} BEGIN ----------\n"; 26 | private string requestEnd = "---------- REQUEST {0} END ----------\n"; 27 | 28 | public HostingDiagnosticHandler(DiagnosticListener diagnosticListener, IServiceScopeFactory scopeFactory, IHubContext diagnosticsHub) 29 | { 30 | _diagnosticListener = diagnosticListener; 31 | _scopeFactory = scopeFactory; 32 | _diagnosticsHub = diagnosticsHub; 33 | } 34 | 35 | public Task StartAsync(CancellationToken cancellationToken) 36 | { 37 | _subscription = DiagnosticListener.AllListeners.Subscribe(this); 38 | return Task.CompletedTask; 39 | } 40 | 41 | public Task StopAsync(CancellationToken cancellationToken) 42 | { 43 | return Task.CompletedTask; 44 | } 45 | 46 | public void OnNext(DiagnosticListener value) 47 | { 48 | _listenersSubscriptions.Add(value.Subscribe(this)); 49 | } 50 | 51 | public void OnNext(KeyValuePair @event) 52 | { 53 | switch (@event.Key) 54 | { 55 | 56 | case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start": 57 | { 58 | var context = GetContext(@event.Value); 59 | var requestId = Guid.NewGuid(); 60 | context.Items.Add("RequestId", requestId); 61 | 62 | var builder = new StringBuilder(string.Format(requestBegin, requestId)) 63 | .Append($"[HttpStart] Incoming request {context.Request.Path} VERB: {context.Request.Method}\n"); 64 | traces[requestId.ToString()] = builder; 65 | } 66 | break; 67 | case "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop": 68 | { 69 | var context = GetContext(@event.Value); 70 | var requestId = context.Items["RequestId"].ToString(); 71 | 72 | var trace = (traces[requestId.ToString()] 73 | .Append($"[HttpStop] Request finished with code {context.Response.StatusCode} \n") 74 | .Append(string.Format(requestEnd, requestId)) 75 | .ToString()); 76 | 77 | Task.Run(async () => 78 | { 79 | await _diagnosticsHub.Clients.All.SendAsync("SendDiagnotics", trace); 80 | }); 81 | 82 | traces.Remove(requestId); 83 | } 84 | break; 85 | 86 | case "Microsoft.AspNetCore.Diagnostics.UnhandledException": 87 | { 88 | var context = GetContext(@event.Value); 89 | var ex = @event.Value as Exception; 90 | var requestId = context.Items["RequestId"].ToString(); 91 | traces[requestId].Append($"[Exception] Request {requestId} failed with error {ex.Message}\n"); 92 | } 93 | break; 94 | case "Microsoft.AspNetCore.Mvc.AfterActionResult": 95 | { 96 | var actionContext = GetProperty(@event.Value, "actionContext"); 97 | var context = GetProperty(actionContext, "HttpContext"); 98 | object actionResult = GetProperty(@event.Value, "result"); 99 | dynamic response = GetProperty(actionResult, "Value"); 100 | var requestId = context.Items["RequestId"].ToString(); 101 | traces[requestId].Append($"[ActionResultResponse] {JsonConvert.SerializeObject(response)}\n "); 102 | } 103 | break; 104 | 105 | case "Microsoft.AspNetCore.Mvc.BeforeAction": 106 | { 107 | var context = GetProperty(@event.Value, "httpContext"); 108 | var requestId = context.Items["RequestId"].ToString(); 109 | var actionDescriptor = GetProperty(@event.Value, "actionDescriptor"); 110 | var actionName = GetProperty(actionDescriptor, "DisplayName"); 111 | traces[requestId].Append($"[Mvc Action] Executing {actionName}\n"); 112 | } 113 | break; 114 | 115 | case "Api.Diagnostics.Headers": 116 | { 117 | var context = GetContext(@event.Value); 118 | var requestId = context.Items["RequestId"].ToString(); 119 | 120 | var headers = GetProperty(@event.Value, "Headers"); 121 | traces[requestId].Append($"[Headers] {headers}\n"); 122 | } 123 | break; 124 | 125 | case "Api.Diagnostics.ApiKey.Authentication.Success": 126 | { 127 | var context = GetContext(@event.Value); 128 | var requestId = context.Items["RequestId"].ToString(); 129 | var apiKey = GetProperty(@event.Value, "ApiKey"); 130 | traces[requestId].Append($"[Api Key Authentication] User logged with api key: {apiKey}\n"); 131 | } 132 | break; 133 | 134 | 135 | case "Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting": 136 | { 137 | using (var scope = _scopeFactory.CreateScope()) 138 | { 139 | var context = scope.ServiceProvider.GetService().HttpContext; 140 | var requestId = context.Items["RequestId"].ToString(); 141 | var payload = (CommandEventData)@event.Value; 142 | traces[requestId].Append($"[EF Command] - {payload.Command.CommandText}\n"); 143 | } 144 | } 145 | break; 146 | } 147 | } 148 | private HttpContext GetContext(object value) 149 | { 150 | return (HttpContext)value.GetType().GetProperty("HttpContext").GetValue(value); 151 | } 152 | 153 | private T GetProperty(object value, string property) 154 | { 155 | var prop = value.GetType().GetProperty(property); 156 | if (prop != null) 157 | { 158 | return (T)prop.GetValue(value); 159 | } 160 | 161 | return default(T); 162 | 163 | } 164 | 165 | public void OnCompleted() 166 | { 167 | 168 | } 169 | public void OnError(Exception error) 170 | { 171 | 172 | } 173 | 174 | public void Dispose() 175 | { 176 | _subscription.Dispose(); 177 | foreach (var listenerSubscription in _listenersSubscriptions) 178 | { 179 | listenerSubscription.Dispose(); 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | 5 | FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build 6 | WORKDIR /src 7 | 8 | COPY ["build/dependencies.props", "src/build/dependencies.props"] 9 | COPY ["Directory.Build.props", "src/"] 10 | COPY ["src/DotNet2019.Host/DotNet2019.Host.csproj", "src/DotNet2019.Host/"] 11 | COPY ["src/DotNet2019.Api/DotNet2019.Api.csproj", "src/DotNet2019.Api/"] 12 | RUN dotnet restore "src/DotNet2019.Host/DotNet2019.Host.csproj" 13 | COPY . . 14 | WORKDIR "/src/src/DotNet2019.Host" 15 | RUN dotnet build "DotNet2019.Host.csproj" -c Release -o /app 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "DotNet2019.Host.csproj" -c Release -o /app 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app . 23 | ENTRYPOINT ["dotnet", "DotNet2019.Host.dll"] -------------------------------------------------------------------------------- /src/DotNet2019.Host/DotNet2019.Host.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(NetCoreTargetVersion) 5 | Linux 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Always 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Extensions/IApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | 6 | namespace Microsoft.AspNetCore.Builder 7 | { 8 | public static class IApplicationBuilderExtensions 9 | { 10 | public static IApplicationBuilder UseCustomHealthchecks(this IApplicationBuilder app) 11 | { 12 | app.UseHealthChecks("/health", new HealthCheckOptions 13 | { 14 | Predicate = registration => registration.Name.Equals("self") 15 | }); 16 | 17 | return app.UseHealthChecks("/ready", new HealthCheckOptions 18 | { 19 | Predicate = registration => registration.Tags.Contains("dependencies") 20 | }); 21 | } 22 | 23 | public static IApplicationBuilder UseHeaderDiagnostics(this IApplicationBuilder app) 24 | { 25 | var listener = app.ApplicationServices.GetService(); 26 | 27 | if (listener.IsEnabled()) 28 | { 29 | return app.Use((context, next) => 30 | { 31 | var headers = string.Join("|", context.Request.Headers.Values.Select(h => h.ToString())); 32 | listener.Write("Api.Diagnostics.Headers", new { Headers = headers, HttpContext = context }); 33 | return next(); 34 | }); 35 | } 36 | 37 | return app; 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Extensions/IServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Data; 2 | using DotNet2019.Host.Diagnostics; 3 | using DotNet2019.Host.Infrastructure.Authentication; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.Diagnostics.HealthChecks; 7 | 8 | namespace Microsoft.Extensions.DependencyInjection 9 | { 10 | public static class IServiceCollectionExtensions 11 | { 12 | public static IServiceCollection AddEntityFrameworkCore(this IServiceCollection services, IConfiguration configuration) => 13 | services.AddDbContext(options => 14 | { 15 | options.UseSqlServer(configuration.GetConnectionString("SqlServer")); 16 | }); 17 | 18 | public static IServiceCollection AddCustomHealthChecks(this IServiceCollection services) 19 | { 20 | return services.AddHealthChecks() 21 | .AddSqlServer("server=sqlserver;initial catalog=master;user id=sa;password=Password12!", 22 | tags: new[] { "dependencies" }) 23 | 24 | .AddRedis("redis", 25 | tags: new[] { "dependencies" }) 26 | 27 | .AddCheck("self", () => HealthCheckResult.Healthy()) 28 | .Services; 29 | } 30 | 31 | public static IServiceCollection AddHostingDiagnosticHandler(this IServiceCollection services) 32 | { 33 | return services.AddHostedService(); 34 | } 35 | 36 | public static IServiceCollection AddCustomAuthentication(this IServiceCollection services) 37 | { 38 | return services.AddAuthentication("Test") 39 | .AddScheme( 40 | authenticationScheme: "Test", 41 | configureOptions: setup => 42 | { 43 | setup.ApiKeys.Add("PatataKey"); 44 | }) 45 | .Services; 46 | } 47 | 48 | public static IServiceCollection AddCustomAuthorization(this IServiceCollection services) 49 | { 50 | return services.AddAuthorization(config => 51 | { 52 | config.AddPolicy("ApiKeyPolicy", config => 53 | { 54 | config.RequireRole("ApiUserRole"); 55 | }); 56 | }); 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Extensions/IWebHostBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace Microsoft.AspNetCore 6 | { 7 | public static class IWebHostBuilderExtensions 8 | { 9 | public static IWebHost MigrateDatabase(this IWebHost webHost) where TContext : DbContext 10 | { 11 | using (var scope = webHost.Services.CreateScope()) 12 | { 13 | var context = scope.ServiceProvider.GetService(); 14 | context.Database.Migrate(); 15 | } 16 | 17 | return webHost; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Infrastructure/Authentication/ApiKeyAuthenticationHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Security.Claims; 8 | using System.Text.Encodings.Web; 9 | using System.Threading.Tasks; 10 | 11 | namespace DotNet2019.Host.Infrastructure.Authentication 12 | { 13 | public class ApiKeyAuthenticationHandler : AuthenticationHandler 14 | { 15 | public const string API_KEY_HEADER_NAME = "X-API-KEY"; 16 | private readonly DiagnosticListener _listener; 17 | 18 | public ApiKeyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, 19 | ISystemClock clock, DiagnosticListener listener) 20 | : base(options, logger, encoder, clock) { 21 | _listener = listener; 22 | } 23 | protected override Task HandleAuthenticateAsync() 24 | { 25 | var apiKey = Context.Request.Headers[API_KEY_HEADER_NAME].FirstOrDefault(); 26 | 27 | 28 | if (apiKey == null) return Task.FromResult(AuthenticateResult.NoResult()); 29 | 30 | if (Options.ApiKeys.Contains(apiKey)) 31 | { 32 | var principal = new ClaimsPrincipal(new[] { new ClaimsIdentity 33 | (new[] { 34 | new Claim(ClaimTypes.Name, "ApiUser"), 35 | new Claim(ClaimTypes.Role, "ApiUserRole") 36 | }) 37 | }); 38 | var ticket = new AuthenticationTicket(principal, "Test"); 39 | 40 | if(_listener.IsEnabled()) 41 | { 42 | _listener.Write("Api.Diagnostics.ApiKey.Authentication.Success", new 43 | { 44 | HttpContext = Context, 45 | ApiKey = apiKey 46 | }); 47 | } 48 | 49 | return Task.FromResult(AuthenticateResult.Success(ticket)); 50 | } 51 | 52 | return Task.FromResult(AuthenticateResult.Fail("Invalid key")); 53 | } 54 | } 55 | 56 | public class ApiKeyHandlerOptions : AuthenticationSchemeOptions 57 | { 58 | public List ApiKeys = new List(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Program.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Data; 2 | using Microsoft.AspNetCore; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Hosting; 5 | 6 | namespace DotNet2019.Host 7 | { 8 | public class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | CreateWebHostBuilder(args) 13 | .Build() 14 | .MigrateDatabase() 15 | .Run(); 16 | } 17 | 18 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 19 | WebHost.CreateDefaultBuilder(args) 20 | .UseStartup(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/Startup.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api; 2 | using DotNet2019.Api.Infrastructure.Data; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | 9 | namespace DotNet2019.Host 10 | { 11 | public class Startup 12 | { 13 | public IConfiguration Configuration { get; } 14 | private IWebHostEnvironment Environment { get; } 15 | 16 | public Startup(IConfiguration configuration, IWebHostEnvironment environment) 17 | { 18 | Configuration = configuration; 19 | Environment = environment; 20 | } 21 | public void ConfigureServices(IServiceCollection services) 22 | { 23 | Api.Configuration.ConfigureServices(services, Environment) 24 | .AddEntityFrameworkCore(Configuration) 25 | .AddCustomAuthentication() 26 | .AddCustomAuthorization() 27 | .AddCustomHealthChecks() 28 | .AddHostingDiagnosticHandler(); 29 | } 30 | 31 | public void Configure(IApplicationBuilder app) 32 | { 33 | Api.Configuration.Configure(app, host => 34 | { 35 | return host 36 | .UseDefaultFiles() 37 | .UseStaticFiles() 38 | .UseCustomHealthchecks() 39 | .UseHeaderDiagnostics(); 40 | }); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "SqlServer": "Server=tcp:localhost,1434;User Id=sa;Password=Password12!;Initial Catalog=dotnet2019;MultipleActiveResultSets=true" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Information", 8 | "Microsoft": "Warning", 9 | "Microsoft.Hosting.Lifetime": "Information" 10 | } 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/wwwroot/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Dotnet 2019 - Asp.Net Core Best Practices 6 | 7 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 | 77 | -------------------------------------------------------------------------------- /src/DotNet2019.Host/wwwroot/lib/signalr.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://signalR/webpack/universalModuleDefinition","webpack://signalR/webpack/bootstrap","webpack://signalR/src/browser-index.ts","webpack://signalR/node_modules/es6-promise/dist/es6-promise.auto.js","webpack://signalR/common/node_modules/webpack/buildin/global.js","webpack://signalR/src/index.ts","webpack://signalR/src/Errors.ts","webpack://signalR/src/HttpClient.ts","webpack://signalR/src/DefaultHttpClient.ts","webpack://signalR/src/EmptyNodeHttpClient.ts","webpack://signalR/src/XhrHttpClient.ts","webpack://signalR/src/ILogger.ts","webpack://signalR/src/HubConnection.ts","webpack://signalR/src/HandshakeProtocol.ts","webpack://signalR/src/TextMessageFormat.ts","webpack://signalR/src/Utils.ts","webpack://signalR/src/Loggers.ts","webpack://signalR/src/IHubProtocol.ts","webpack://signalR/src/HubConnectionBuilder.ts","webpack://signalR/src/HttpConnection.ts","webpack://signalR/src/ITransport.ts","webpack://signalR/src/LongPollingTransport.ts","webpack://signalR/src/AbortController.ts","webpack://signalR/src/ServerSentEventsTransport.ts","webpack://signalR/src/WebSocketTransport.ts","webpack://signalR/src/JsonHubProtocol.ts"],"names":["webpackUniversalModuleDefinition","root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","getDefault","getModuleExports","object","property","prototype","hasOwnProperty","p","s","__webpack_exports__","_index__WEBPACK_IMPORTED_MODULE_1__","Uint8Array","indexOf","Array","writable","slice","forEach","require","global","undefined","this","objectOrFunction","x","type","isFunction","_isArray","isArray","toString","len","vertxNext","customSchedulerFn","asap","callback","arg","queue","flush","scheduleFlush","setScheduler","scheduleFn","setAsap","asapFn","browserWindow","browserGlobal","BrowserMutationObserver","MutationObserver","WebKitMutationObserver","isNode","self","process","isWorker","Uint8ClampedArray","importScripts","MessageChannel","useNextTick","nextTick","useVertxTimer","useSetTimeout","useMutationObserver","iterations","observer","node","document","createTextNode","observe","characterData","data","useMessageChannel","channel","port1","onmessage","port2","postMessage","globalSetTimeout","setTimeout","attemptVertx","vertx","webpackMissingModule","e","Error","code","runOnLoop","runOnContext","then","onFulfillment","onRejection","parent","child","constructor","noop","PROMISE_ID","makePromise","_state","arguments","invokeCallback","_result","subscribe","resolve$1","Constructor","promise","resolve","Math","random","substring","PENDING","FULFILLED","REJECTED","GET_THEN_ERROR","ErrorObject","selfFulfillment","TypeError","cannotReturnOwn","getThen","error","tryThen","then$$1","fulfillmentHandler","rejectionHandler","handleForeignThenable","thenable","sealed","fulfill","reason","reject","_label","handleOwnThenable","handleMaybeThenable","maybeThenable","publishRejection","_onerror","publish","_subscribers","length","subscribers","settled","detail","TRY_CATCH_ERROR","tryCatch","hasCallback","succeeded","failed","initializePromise","resolver","resolvePromise","rejectPromise","id","nextId","validationError","Enumerator","input","_instanceConstructor","_remaining","_enumerate","_eachEntry","entry","resolve$$1","_then","_settledAt","Promise$2","_willSettleAt","state","enumerator","all","entries","race","_","reject$1","needsResolver","needsNew","Promise","catch","_catch","finally","_finally","_setScheduler","_setAsap","_asap","polyfill","local","Function","P","promiseToString","cast","g","eval","_JsonHubProtocol__WEBPACK_IMPORTED_MODULE_9__","VERSION","AbortError","HttpError","_super","__extends","errorMessage","statusCode","_this","trueProto","_newTarget","__proto__","TimeoutError","HttpClient","HttpResponse","statusText","content","url","options","send","__assign","method","post","delete","getCookieString","_XhrHttpClient__WEBPACK_IMPORTED_MODULE_3__","DefaultHttpClient","logger","XMLHttpRequest","httpClient","_NodeHttpClient__WEBPACK_IMPORTED_MODULE_2__","request","abortSignal","aborted","_Errors__WEBPACK_IMPORTED_MODULE_0__","_HttpClient__WEBPACK_IMPORTED_MODULE_1__","_HttpClient__WEBPACK_IMPORTED_MODULE_0__","NodeHttpClient","_ILogger__WEBPACK_IMPORTED_MODULE_2__","XhrHttpClient","xhr","open","withCredentials","setRequestHeader","headers","keys","header","responseType","onabort","abort","timeout","onload","status","response","responseText","onerror","log","Warning","ontimeout","LogLevel","_Utils__WEBPACK_IMPORTED_MODULE_3__","DEFAULT_TIMEOUT_IN_MS","DEFAULT_PING_INTERVAL_IN_MS","HubConnectionState","HubConnection","connection","protocol","isRequired","serverTimeoutInMilliseconds","keepAliveIntervalInMilliseconds","handshakeProtocol","_HandshakeProtocol__WEBPACK_IMPORTED_MODULE_0__","onreceive","processIncomingData","onclose","connectionClosed","callbacks","methods","closedCallbacks","receivedHandshakeResponse","connectionState","Disconnected","cachedPingMessage","writeMessage","_IHubProtocol__WEBPACK_IMPORTED_MODULE_1__","Ping","start","handshakeRequest","version","Debug","handshakePromise","handshakeResolver","handshakeRejecter","transferFormat","_a","sent","sendMessage","writeHandshakeRequest","Information","cleanupTimeout","resetTimeoutPeriod","resetKeepAliveInterval","Connected","stop","cleanupPingTimer","stream","methodName","args","_i","invocationDescriptor","createStreamInvocation","promiseQueue","subject","cancelCallback","cancelInvocation","createCancelInvocation","invocationId","cancelMessage","invocationEvent","Completion","complete","next","message","createInvocation","invoke","result","on","newMethod","toLowerCase","push","off","handlers","removeIdx","splice","processHandshakeResponse","messages","parseMessages","messages_1","Invocation","invokeClientMethod","StreamItem","Close","responseMessage","remainingData","parseHandshakeResponse","pingServerHandle","__awaiter","_b","features","inherentKeepAlive","timeoutHandle","serverTimeout","invocationMessage","target","apply","clearTimeout","nonblocking","StreamInvocation","CancelInvocation","_Utils__WEBPACK_IMPORTED_MODULE_1__","HandshakeProtocol","_TextMessageFormat__WEBPACK_IMPORTED_MODULE_0__","write","JSON","stringify","messageData","Buffer","binaryData","separatorIndex","RecordSeparatorCode","responseLength","String","fromCharCode","byteLength","buffer","textData","RecordSeparator","parse","TextMessageFormat","output","split","pop","_Loggers__WEBPACK_IMPORTED_MODULE_1__","Arg","val","isIn","values","getDataDetail","includeContent","isArrayBuffer","formatArrayBuffer","view","str","num","pad","substr","ArrayBuffer","transportName","accessTokenFactory","logMessageContent","token","_ILogger__WEBPACK_IMPORTED_MODULE_0__","Trace","createLogger","ConsoleLogger","instance","Subject","observers","item","err","SubjectSubscription","dispose","index","minimumLogLevel","logLevel","Critical","console","Date","toISOString","warn","info","NullLogger","_logLevel","_message","MessageType","_Utils__WEBPACK_IMPORTED_MODULE_4__","HubConnectionBuilder","configureLogging","logging","isLogger","withUrl","transportTypeOrOptions","httpConnectionOptions","transport","withHubProtocol","build","_HttpConnection__WEBPACK_IMPORTED_MODULE_0__","_HubConnection__WEBPACK_IMPORTED_MODULE_1__","_Loggers__WEBPACK_IMPORTED_MODULE_3__","_JsonHubProtocol__WEBPACK_IMPORTED_MODULE_2__","_WebSocketTransport__WEBPACK_IMPORTED_MODULE_6__","MAX_REDIRECTS","WebSocketModule","EventSourceModule","requireFunc","HttpConnection","_Utils__WEBPACK_IMPORTED_MODULE_5__","baseUrl","resolveUrl","WebSocket","EventSource","_DefaultHttpClient__WEBPACK_IMPORTED_MODULE_0__","_ITransport__WEBPACK_IMPORTED_MODULE_2__","Binary","_ILogger__WEBPACK_IMPORTED_MODULE_1__","startPromise","startInternal","stopError","skipNegotiation","WebSockets","constructTransport","connect","negotiateResponse","redirects","this_1","getNegotiationResponse","ProtocolVersion","accessToken","accessToken_1","createTransport","_LongPollingTransport__WEBPACK_IMPORTED_MODULE_3__","stopConnection","changeState","e_2","negotiateUrl","resolveNegotiateUrl","e_3","createConnectUrl","connectionId","requestedTransport","requestedTransferFormat","connectUrl","isITransport","transports","availableTransports","transports_1","endpoint","resolveTransport","ex_1","ServerSentEvents","_ServerSentEventsTransport__WEBPACK_IMPORTED_MODULE_4__","LongPolling","transferFormats","map","transportMatches","from","to","lastIndexOf","aTag","createElement","href","actualTransport","TransferFormat","HttpTransportType","LongPollingTransport","pollAbort","_AbortController__WEBPACK_IMPORTED_MODULE_0__","running","_ITransport__WEBPACK_IMPORTED_MODULE_3__","pollOptions","signal","getAccessToken","updateHeaderToken","pollUrl","now","closeError","_Errors__WEBPACK_IMPORTED_MODULE_1__","receiving","poll","e_1","pollAborted","raiseOnClose","deleteOptions","logMessage","AbortController","isAborted","_Utils__WEBPACK_IMPORTED_MODULE_2__","ServerSentEventsTransport","eventSourceConstructor","_ITransport__WEBPACK_IMPORTED_MODULE_1__","encodeURIComponent","opened","Text","eventSource","cookies","Cookie","close","onopen","WebSocketTransport","webSocketConstructor","replace","webSocket","binaryType","_event","event","ErrorEvent","readyState","OPEN","wasClean","_TextMessageFormat__WEBPACK_IMPORTED_MODULE_4__","JSON_HUB_PROTOCOL_NAME","JsonHubProtocol","hubMessages","parsedMessage","_IHubProtocol__WEBPACK_IMPORTED_MODULE_0__","isInvocationMessage","isStreamItemMessage","isCompletionMessage","assertNotEmptyString"],"mappings":"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"} -------------------------------------------------------------------------------- /test/FunctionalTests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.0 as build 2 | WORKDIR /src 3 | COPY . . 4 | RUN dotnet restore test/FunctionalTests/FunctionalTests.csproj -------------------------------------------------------------------------------- /test/FunctionalTests/DotNet2019.Api/Api.cs: -------------------------------------------------------------------------------- 1 | namespace FunctionalTests.DotNet2019.Api 2 | { 3 | internal static class Api 4 | { 5 | public static class Users 6 | { 7 | public static string Post() 8 | { 9 | return $"api/users"; 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/FunctionalTests/DotNet2019.Api/Controllers/UsersController.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using FunctionalTests.Seedwork; 3 | using FunctionalTests.Seedwork.Builders; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.AspNetCore.TestHost; 6 | using System; 7 | using System.Diagnostics.CodeAnalysis; 8 | using System.Threading.Tasks; 9 | using Xunit; 10 | 11 | namespace FunctionalTests.DotNet2019.Api.Controllers 12 | { 13 | [Collection(nameof(ServerFixtureCollection))] 14 | [ExcludeFromCodeCoverage] 15 | public class users_api_should 16 | { 17 | private readonly ServerFixture Given; 18 | 19 | public users_api_should(ServerFixture fixture) 20 | { 21 | Given = fixture ?? throw new ArgumentNullException(nameof(fixture)); 22 | } 23 | 24 | [Fact] 25 | [ResetDatabase] 26 | public async Task allow_to_add_users() 27 | { 28 | var request = Builders.UserRequest 29 | .WithName("Test") 30 | .Build(); 31 | 32 | var response = await Given 33 | .Server 34 | .CreateRequest(Api.Users.Post()) 35 | .WithJsonBody(request) 36 | .PostAsync(); 37 | 38 | response.StatusCode.Should().Be(StatusCodes.Status200OK); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/FunctionalTests/FunctionalTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(NetCoreTargetVersion) 5 | false 6 | $(LangVersion) 7 | Linux 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Builders/Builders.cs: -------------------------------------------------------------------------------- 1 | namespace FunctionalTests.Seedwork.Builders 2 | { 3 | internal static class Builders 4 | { 5 | public static UserRequestBuilder UserRequest 6 | { 7 | get 8 | { 9 | return new UserRequestBuilder(); 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Builders/UserRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Model; 2 | 3 | namespace FunctionalTests.Seedwork.Builders 4 | { 5 | internal class UserRequestBuilder 6 | { 7 | string name = "Test Portal"; 8 | 9 | public UserRequestBuilder() 10 | { 11 | } 12 | 13 | public UserRequestBuilder WithName(string name) 14 | { 15 | this.name = name; 16 | return this; 17 | } 18 | 19 | public UserRequest Build() 20 | { 21 | return new UserRequest 22 | { 23 | Name = name 24 | }; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Extensions/IHostBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Microsoft.Extensions.Hosting 5 | { 6 | public static class IHostBuilderExtensions 7 | { 8 | public static IHost MigrateDatabase(this IHost host) where TContext : DbContext 9 | { 10 | using (var scope = host.Services.CreateScope()) 11 | { 12 | var context = scope.ServiceProvider.GetService(); 13 | context.Database.Migrate(); 14 | } 15 | 16 | return host; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Extensions/IServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using System; 3 | 4 | namespace Microsoft.Extensions.DependencyInjection 5 | { 6 | public static class IServiceCollectionExtensions 7 | { 8 | public static IServiceCollection ConfigurePOCO(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new() 9 | { 10 | if (services == null) throw new ArgumentNullException(nameof(services)); 11 | if (configuration == null) throw new ArgumentNullException(nameof(configuration)); 12 | 13 | var config = new TConfig(); 14 | configuration.Bind(config); 15 | services.AddSingleton(config); 16 | return services; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Extensions/RequestBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Newtonsoft.Json; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Microsoft.AspNetCore.TestHost 9 | { 10 | [ExcludeFromCodeCoverage] 11 | public static class RequestBuilderExtensions 12 | { 13 | public static Task PutAsync(this RequestBuilder requestBuilder) 14 | { 15 | return requestBuilder.SendAsync(HttpMethods.Put); 16 | } 17 | public static Task DeleteAsync(this RequestBuilder requestBuilder) 18 | { 19 | return requestBuilder.SendAsync(HttpMethods.Delete); 20 | } 21 | 22 | public static RequestBuilder WithJsonBody(this RequestBuilder builder, TContent content, string contentType = "application/json") 23 | { 24 | var json = JsonConvert.SerializeObject(content); 25 | 26 | return builder.And(message => 27 | { 28 | message.Content = new StringContent(json, Encoding.UTF8, contentType); 29 | }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/Given.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace FunctionalTests.Seedwork 4 | { 5 | [ExcludeFromCodeCoverage] 6 | public class Given 7 | { 8 | private readonly ServerFixture _serverFixture; 9 | 10 | public Given(ServerFixture serverFixture) 11 | { 12 | _serverFixture = serverFixture; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/ResetDatabaseAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Reflection; 3 | using Xunit.Sdk; 4 | 5 | namespace FunctionalTests.Seedwork 6 | { 7 | [ExcludeFromCodeCoverage] 8 | public class ResetDatabaseAttribute 9 | : BeforeAfterTestAttribute 10 | { 11 | public override void Before(MethodInfo methodUnderTest) 12 | { 13 | ServerFixture.ResetDatabase(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/ServerFixture.cs: -------------------------------------------------------------------------------- 1 | using DotNet2019.Api.Infrastructure.Data; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.TestHost; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.Hosting; 6 | using Respawn; 7 | using System.IO; 8 | 9 | namespace FunctionalTests.Seedwork 10 | { 11 | public class ServerFixture 12 | { 13 | static Checkpoint _checkpoint = new Checkpoint() 14 | { 15 | TablesToIgnore = new string[] { "__EFMigrationsHistory" }, 16 | WithReseed = true 17 | }; 18 | 19 | public TestServer Server { get; private set; } 20 | 21 | public ServerFixture() 22 | { 23 | InitializeTestServer(); 24 | } 25 | 26 | private void InitializeTestServer() 27 | { 28 | var testServer = new TestServer(); 29 | 30 | var host = Host.CreateDefaultBuilder() 31 | .UseContentRoot(Directory.GetCurrentDirectory()) 32 | .ConfigureAppConfiguration(builder => 33 | { 34 | builder 35 | .AddJsonFile("appsettings.json", optional: true) 36 | .AddEnvironmentVariables(); 37 | }) 38 | .ConfigureWebHostDefaults(webBuilder => 39 | { 40 | webBuilder 41 | .UseServer(testServer) 42 | .UseStartup(); 43 | }).Build(); 44 | 45 | host.StartAsync().Wait(); 46 | host.MigrateDatabase(); 47 | 48 | Server = host.GetTestServer(); 49 | } 50 | 51 | internal static void ResetDatabase() 52 | { 53 | var configuration = new ConfigurationBuilder() 54 | .AddJsonFile("appsettings.json", optional: true) 55 | .AddEnvironmentVariables() 56 | .Build(); 57 | 58 | var connectionString = configuration 59 | .GetConnectionString("SqlServer"); 60 | 61 | var task = _checkpoint.Reset(connectionString); 62 | task.Wait(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/ServerFixtureCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Xunit; 3 | 4 | namespace FunctionalTests.Seedwork 5 | { 6 | [ExcludeFromCodeCoverage] 7 | [CollectionDefinition(nameof(ServerFixtureCollection))] 8 | public class ServerFixtureCollection 9 | :ICollectionFixture 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/FunctionalTests/Seedwork/TestStartup.cs: -------------------------------------------------------------------------------- 1 | using Acheve.AspNetCore.TestHost.Security; 2 | using Acheve.TestHost; 3 | using DotNet2019.Api; 4 | using DotNet2019.Api.Infrastructure.Data; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace FunctionalTests.Seedwork 12 | { 13 | class TestStartup 14 | { 15 | private readonly IConfiguration configuration; 16 | private readonly IWebHostEnvironment environment; 17 | 18 | public TestStartup(IConfiguration configuration, IWebHostEnvironment environment) 19 | { 20 | this.configuration = configuration; 21 | this.environment = environment; 22 | } 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | Configuration.ConfigureServices(services, environment) 26 | .AddDbContext(setup => 27 | { 28 | setup.UseSqlServer(configuration.GetConnectionString("SqlServer"), sql => 29 | { 30 | sql.MigrationsAssembly(typeof(DataContext).Assembly.GetName().Name); 31 | }); 32 | }) 33 | .AddAuthorization() 34 | .AddAuthentication(setup => 35 | { 36 | setup.DefaultAuthenticateScheme = TestServerDefaults.AuthenticationScheme; 37 | setup.DefaultChallengeScheme = TestServerDefaults.AuthenticationScheme; 38 | }) 39 | .AddTestServer(); 40 | } 41 | 42 | public void Configure(IApplicationBuilder app) 43 | { 44 | Configuration.Configure(app, host => host); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/FunctionalTests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "SqlServer": "Server=tcp:localhost,1434;User Id=sa;Password=Password12!;Initial Catalog=FunctionalTests;MultipleActiveResultSets=true" 4 | } 5 | } 6 | --------------------------------------------------------------------------------