Skip to content

Commit 10e7aba

Browse files
author
Matthew Thornton
committed
Create skeleton solution and add domain exception handler.
1 parent 45d2776 commit 10e7aba

11 files changed

Lines changed: 593 additions & 0 deletions

.gitignore

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
*.swp
2+
*~
3+
4+
.vs/
5+
6+
.idea/
7+
8+
## Ignore Visual Studio temporary files, build results, and
9+
## files generated by popular Visual Studio add-ons.
10+
11+
# User-specific files
12+
*.suo
13+
*.user
14+
*.sln.docstates
15+
16+
# Build results
17+
[Dd]ebug/
18+
[Dd]ebugPublic/
19+
[Rr]elease/
20+
x64/
21+
build/
22+
bld/
23+
[Bb]in/
24+
[Oo]bj/
25+
26+
# MSTest test Results
27+
[Tt]est[Rr]esult*/
28+
[Bb]uild[Ll]og.*
29+
30+
#NUNIT
31+
*.VisualState.xml
32+
TestResult.xml
33+
34+
# Visual C++ cache files
35+
ipch/
36+
*.aps
37+
*.ncb
38+
*.opensdf
39+
*.sdf
40+
*.cachefile
41+
42+
# Visual Studio profiler
43+
*.psess
44+
*.vsp
45+
*.vspx
46+
47+
# ReSharper is a .NET coding add-in
48+
_ReSharper*/
49+
*.[Rr]e[Ss]harper
50+
*.DotSettings.user
51+
52+
# TeamCity is a build add-in
53+
_TeamCity*
54+
55+
# DotCover is a Code Coverage Tool
56+
*.dotCover
57+
58+
# Click-Once directory
59+
publish/
60+
61+
# Publish Web Output
62+
*.[Pp]ublish.xml
63+
*.azurePubxml
64+
*.pubxml
65+
66+
# NuGet Packages Directory
67+
packages/*
68+
## TODO: If the tool you use requires repositories.config
69+
## uncomment the next line
70+
#!packages/repositories.config
71+
72+
# Enable "build/" folder in the NuGet Packages folder since
73+
# NuGet packages use it for MSBuild targets.
74+
# This line needs to be after the ignore of the build folder
75+
# (and the packages folder if the line above has been uncommented)
76+
!packages/build/
77+
78+
# Others
79+
*.Cache
80+
ClientBin/
81+
~$*
82+
*~
83+
*.dbmdl
84+
*.dbproj.schemaview
85+
*.pfx
86+
*.publishsettings
87+
node_modules/
88+
89+
# Backup & report files from converting an old project file
90+
# to a newer Visual Studio version. Backup files are not needed,
91+
# because we have git ;-)
92+
_UpgradeReport_Files/
93+
Backup*/
94+
UpgradeLog*.XML
95+
UpgradeLog*.htm
96+
97+
# SQL Server files
98+
*.mdf
99+
*.ldf
100+
101+
## Certificates
102+
*.pem
103+
104+
logs/
105+
*.log
106+
*.sln.DotSettings

GitVersionConfig.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
assembly-versioning-scheme: MajorMinorPatch
2+
mode: ContinuousDeployment
3+
4+
# It would be better to use smarter regexes instead of duplicating everything for local and remote cases.
5+
# However, GitVersion has some built-in patterns which cannot be removed and these would cause clashes.
6+
branches:
7+
8+
# These branch patterns cover all local cases
9+
master:
10+
regex: master
11+
tag: master
12+
increment: Minor
13+
prevent-increment-of-merged-branch-version: true
14+
feature:
15+
regex: feature[/-]
16+
tag: a{BranchName}
17+
increment: Minor
18+
prevent-increment-of-merged-branch-version: false
19+
patch:
20+
regex: patch[/-]
21+
tag: useBranchName
22+
increment: Patch
23+
prevent-increment-of-merged-branch-version: false
24+
release:
25+
regex: release[/-]
26+
tag: rc
27+
increment: None
28+
prevent-increment-of-merged-branch-version: false
29+
30+
# These branch patterns cover all remote cases
31+
origin/master:
32+
regex: origin/master
33+
tag: master
34+
increment: Minor
35+
prevent-increment-of-merged-branch-version: true
36+
origin/feature:
37+
regex: origin/feature[/-]
38+
tag: a{BranchName}
39+
increment: Minor
40+
prevent-increment-of-merged-branch-version: false
41+
origin/patch:
42+
regex: origin/patch[/-]
43+
tag: useBranchName
44+
increment: Patch
45+
prevent-increment-of-merged-branch-version: false
46+
origin/release:
47+
regex: origin/release[/-]
48+
tag: rc
49+
increment: None
50+
prevent-increment-of-merged-branch-version: false

Jenkinsfile

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!groovy
2+
3+
node {
4+
step([$class: 'StashNotifier'])
5+
try {
6+
stage("Clone") {
7+
checkout scm
8+
}
9+
10+
stage("Restore") {
11+
bat "dotnet restore --source https://packages/repository/nuget-group-libs/"
12+
}
13+
14+
stage("Build") {
15+
bat("\"${tool 'MSBuild15'}\" /p:Configuration=Release /p:GetVersion=True /p:WriteVersionInfoToBuildLog=True")
16+
}
17+
18+
stage("Test") {
19+
def tests = [
20+
"unit-tests": { test("Winton.DomainModelling.AspNetCore.Tests") }
21+
]
22+
parallel tests
23+
}
24+
25+
stage("Publish") {
26+
dir("src\\Winton.DomainModelling.Abstractions\\bin") {
27+
bat("dotnet nuget push **\\*.nupkg --source https://packages/repository/nuget-hosted-libs/")
28+
}
29+
}
30+
31+
stage("Archive") {
32+
archive "**\\*.nupkg"
33+
}
34+
35+
currentBuild.result = "SUCCESS"
36+
}
37+
catch (err) {
38+
currentBuild.result = "FAILURE"
39+
throw err
40+
}
41+
finally{
42+
step([$class: 'StashNotifier'])
43+
}
44+
}
45+
46+
def test(testProjectName) {
47+
dir("test") {
48+
dir("${testProjectName}") {
49+
bat("dotnet test --configuration Release --no-restore --no-build")
50+
}
51+
}
52+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.27703.2026
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E61DDF24-3DEB-49A2-8D27-E6D04105B28B}"
7+
ProjectSection(SolutionItems) = preProject
8+
.gitignore = .gitignore
9+
GitVersionConfig.yaml = GitVersionConfig.yaml
10+
Jenkinsfile = Jenkinsfile
11+
README.md = README.md
12+
stylecop.json = stylecop.json
13+
EndProjectSection
14+
EndProject
15+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6BF06986-D228-4BDA-87B6-015792391C04}"
16+
EndProject
17+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C4EF1CA3-45F0-47C6-B217-8418788BB088}"
18+
EndProject
19+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Winton.DomainModelling.AspNetCore", "src\Winton.DomainModelling.AspNetCore\Winton.DomainModelling.AspNetCore.csproj", "{083025CE-85A8-4FED-BE30-9756B3947EE4}"
20+
EndProject
21+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Winton.DomainModelling.AspNetCore.Tests", "test\Winton.DomainModelling.AspNetCore.Tests\Winton.DomainModelling.AspNetCore.Tests.csproj", "{BF23E05F-9E4C-4C45-85D8-46D31C15D372}"
22+
EndProject
23+
Global
24+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
25+
Debug|Any CPU = Debug|Any CPU
26+
Release|Any CPU = Release|Any CPU
27+
EndGlobalSection
28+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
29+
{083025CE-85A8-4FED-BE30-9756B3947EE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30+
{083025CE-85A8-4FED-BE30-9756B3947EE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
31+
{083025CE-85A8-4FED-BE30-9756B3947EE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
32+
{083025CE-85A8-4FED-BE30-9756B3947EE4}.Release|Any CPU.Build.0 = Release|Any CPU
33+
{BF23E05F-9E4C-4C45-85D8-46D31C15D372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34+
{BF23E05F-9E4C-4C45-85D8-46D31C15D372}.Debug|Any CPU.Build.0 = Debug|Any CPU
35+
{BF23E05F-9E4C-4C45-85D8-46D31C15D372}.Release|Any CPU.ActiveCfg = Release|Any CPU
36+
{BF23E05F-9E4C-4C45-85D8-46D31C15D372}.Release|Any CPU.Build.0 = Release|Any CPU
37+
EndGlobalSection
38+
GlobalSection(SolutionProperties) = preSolution
39+
HideSolutionNode = FALSE
40+
EndGlobalSection
41+
GlobalSection(NestedProjects) = preSolution
42+
{083025CE-85A8-4FED-BE30-9756B3947EE4} = {6BF06986-D228-4BDA-87B6-015792391C04}
43+
{BF23E05F-9E4C-4C45-85D8-46D31C15D372} = {C4EF1CA3-45F0-47C6-B217-8418788BB088}
44+
EndGlobalSection
45+
GlobalSection(ExtensibilityGlobals) = postSolution
46+
SolutionGuid = {82CC0AE5-734C-4261-B265-C8D93762962F}
47+
EndGlobalSection
48+
EndGlobal
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.AspNetCore.Mvc.Filters;
4+
5+
namespace Winton.DomainModelling.AspNetCore
6+
{
7+
/// <inheritdoc />
8+
/// <summary>
9+
/// An exception filter for converting <see cref="DomainException" />s to <see cref="IActionResult" />s.
10+
/// </summary>
11+
public sealed class DomainExceptionFilter : IExceptionFilter
12+
{
13+
private readonly Func<DomainException, ErrorResponse, IActionResult> _exceptionMapper;
14+
15+
/// <summary>
16+
/// Initializes a new instance of the <see cref="DomainExceptionFilter" /> class.
17+
/// </summary>
18+
public DomainExceptionFilter()
19+
: this(null)
20+
{
21+
}
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="DomainExceptionFilter" /> class.
25+
/// </summary>
26+
/// <param name="exceptionMapper">
27+
/// A function to map custom domain exceptions, that are not handled by this class, to action
28+
/// results.
29+
/// </param>
30+
public DomainExceptionFilter(Func<DomainException, ErrorResponse, IActionResult> exceptionMapper)
31+
{
32+
_exceptionMapper = exceptionMapper;
33+
}
34+
35+
/// <inheritdoc />
36+
public void OnException(ExceptionContext context)
37+
{
38+
if (context.Exception is DomainException exception)
39+
{
40+
context.ExceptionHandled = true;
41+
context.Result = CreateResult(exception);
42+
}
43+
}
44+
45+
/// <summary>
46+
/// Maps a <see cref="DomainException" /> to an <see cref="IActionResult" />.
47+
/// This method can be overriden by classes that extend this one to extend or redefine this mapping.
48+
/// </summary>
49+
/// <param name="domainException">The <see cref="DomainException" />.</param>
50+
/// <returns>The <see cref="IActionResult" />.</returns>
51+
private IActionResult CreateResult(DomainException domainException)
52+
{
53+
var errorResponse = new ErrorResponse(domainException);
54+
switch (domainException)
55+
{
56+
case EntityNotFoundException _:
57+
return new NotFoundObjectResult(errorResponse);
58+
case UnauthorizedException _:
59+
return new UnauthorizedResult();
60+
default:
61+
return _exceptionMapper?.Invoke(domainException, errorResponse) ??
62+
new BadRequestObjectResult(errorResponse);
63+
}
64+
}
65+
}
66+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace Winton.DomainModelling.AspNetCore
2+
{
3+
/// <summary>
4+
/// A response that represents an error.
5+
/// </summary>
6+
public struct ErrorResponse
7+
{
8+
/// <summary>
9+
/// Initializes a new instance of the <see cref="ErrorResponse" /> struct.
10+
/// </summary>
11+
/// <param name="exception">The <see cref="DomainException" /> that resulted from the error.</param>
12+
internal ErrorResponse(DomainException exception)
13+
{
14+
Reason = exception.Message;
15+
}
16+
17+
/// <summary>
18+
/// Gets a description of the error that occured.
19+
/// </summary>
20+
public string Reason { get; }
21+
}
22+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) Winton. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
[assembly: InternalsVisibleTo("Winton.DomainModelling.AspNetCore.Tests")]
7+
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Authors>Winton</Authors>
5+
<Company>Winton</Company>
6+
<Copyright>Copyright 2018 Winton</Copyright>
7+
<Description>Provides conventions for creating an ASP.NET Core based REST API on top of a domain model.</Description>
8+
<GenerateDocumentationFile>True</GenerateDocumentationFile>
9+
<GetVersion>False</GetVersion>
10+
<NoWarn>$(NoWarn);SA0001;SA1101;SA1309;SA1413;SA1633;SA1652</NoWarn>
11+
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
12+
<PackageTags>Winton, AspNetCore, ASP, .NET, Core, App</PackageTags>
13+
<PackageVersion>$(NuGetVersion)</PackageVersion>
14+
<TargetFramework>netcoreapp2.0</TargetFramework>
15+
<Title>Winton Domain Modelling ASP.NET Core</Title>
16+
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
17+
<WriteVersionInfoToBuildLog>False</WriteVersionInfoToBuildLog>
18+
</PropertyGroup>
19+
20+
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
21+
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
22+
</PropertyGroup>
23+
24+
<ItemGroup>
25+
<AdditionalFiles Include="..\..\stylecop.json" />
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<PackageReference Include="Bt.Tooling.ReSharper" Version="1.3.0" PrivateAssets="All" />
30+
<PackageReference Include="GitVersionTask" Version="4.0.0-beta0012" PrivateAssets="All" />
31+
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.0" />
32+
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" PrivateAssets="All" />
33+
<PackageReference Include="Winton.DomainModelling.Abstractions" Version="0.1.0-*" />
34+
</ItemGroup>
35+
36+
</Project>

0 commit comments

Comments
 (0)