Skip to content

Commit 871571f

Browse files
Matthew ThorntonMatthew Thornton
authored andcommitted
Merge pull request #1 in TECHBUS/winton.domainmodelling.aspnetcore from feature/BT-6529 to master
* commit '2bb5012726c4b8201209855a54f9f5dbc780deed': Clean up comments in DomainExceptionFilter and remove Moq visibility in AssemblyInfo file. Fix publish step in Jenkinfile. Add test for domain exception filter for case when custom mapper returns null. Create skeleton solution and add domain exception handler.
2 parents 45d2776 + 2bb5012 commit 871571f

11 files changed

Lines changed: 604 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: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
bat("dotnet nuget push **\\*.nupkg --source https://packages/repository/nuget-hosted-libs/")
27+
}
28+
29+
stage("Archive") {
30+
archive "**\\*.nupkg"
31+
}
32+
33+
currentBuild.result = "SUCCESS"
34+
}
35+
catch (err) {
36+
currentBuild.result = "FAILURE"
37+
throw err
38+
}
39+
finally{
40+
step([$class: 'StashNotifier'])
41+
}
42+
}
43+
44+
def test(testProjectName) {
45+
dir("test") {
46+
dir("${testProjectName}") {
47+
bat("dotnet test --configuration Release --no-restore --no-build")
48+
}
49+
}
50+
}
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: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
/// This parameter can be used to extend the capabilities of this exception filter to meet an application's specific
30+
/// requirements.
31+
/// </param>
32+
public DomainExceptionFilter(Func<DomainException, ErrorResponse, IActionResult> exceptionMapper)
33+
{
34+
_exceptionMapper = exceptionMapper;
35+
}
36+
37+
/// <inheritdoc />
38+
public void OnException(ExceptionContext context)
39+
{
40+
if (context.Exception is DomainException exception)
41+
{
42+
context.ExceptionHandled = true;
43+
context.Result = CreateResult(exception);
44+
}
45+
}
46+
47+
private IActionResult CreateResult(DomainException domainException)
48+
{
49+
var errorResponse = new ErrorResponse(domainException);
50+
switch (domainException)
51+
{
52+
case EntityNotFoundException _:
53+
return new NotFoundObjectResult(errorResponse);
54+
case UnauthorizedException _:
55+
return new UnauthorizedResult();
56+
default:
57+
return _exceptionMapper?.Invoke(domainException, errorResponse) ??
58+
new BadRequestObjectResult(errorResponse);
59+
}
60+
}
61+
}
62+
}
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
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")]
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, Domain, Modelling</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)