Skip to content

Commit 236a543

Browse files
committed
Added sample with composite pattern
1 parent ec07b1c commit 236a543

File tree

210 files changed

+11361
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

210 files changed

+11361
-0
lines changed

Modules/CompositePublishTest/CompositePublishTest/.gitignore

Lines changed: 487 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
4+
using System.IO;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Intent.RoslynWeaver.Attributes;
8+
using Microsoft.AspNetCore.Http;
9+
10+
[assembly: DefaultIntentManaged(Mode.Fully)]
11+
[assembly: IntentTemplate("Intent.AzureFunctions.AzureFunctionClassHelper", Version = "1.0")]
12+
13+
namespace CompositePublishTest.Api
14+
{
15+
static class AzureFunctionHelper
16+
{
17+
private static readonly System.Text.Json.JsonSerializerOptions SerializationSettings = new() { PropertyNameCaseInsensitive = true };
18+
19+
public static async Task<T> DeserializeJsonContentAsync<T>(Stream jsonContentStream, CancellationToken cancellationToken)
20+
{
21+
return await System.Text.Json.JsonSerializer.DeserializeAsync<T>(jsonContentStream, SerializationSettings, cancellationToken) ?? throw new FormatException("Unable to deserialize JSON content.");
22+
}
23+
24+
public static T GetQueryParam<T>(string paramName, IQueryCollection query, ParseDelegate<T> parse)
25+
where T : struct
26+
{
27+
var strVal = query[paramName];
28+
if (string.IsNullOrEmpty(strVal) || !parse(strVal, out T parsed))
29+
{
30+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
31+
}
32+
33+
return parsed;
34+
}
35+
36+
public static T? GetQueryParamNullable<T>(string paramName, IQueryCollection query, ParseDelegate<T> parse)
37+
where T : struct
38+
{
39+
var strVal = query[paramName];
40+
if (string.IsNullOrEmpty(strVal))
41+
{
42+
return null;
43+
}
44+
45+
if (!parse(strVal, out T parsed))
46+
{
47+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
48+
}
49+
50+
return parsed;
51+
}
52+
53+
public static IEnumerable<T> GetQueryParamCollection<T>(string paramName, IQueryCollection query, ParseDelegate<T> parse)
54+
where T : struct
55+
{
56+
var result = new List<T>();
57+
var strVal = query[paramName];
58+
var values = strVal.ToString().Split(",");
59+
foreach (var v in values)
60+
{
61+
if (string.IsNullOrEmpty(v) || !parse(v, out T parsed))
62+
{
63+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
64+
}
65+
result.Add(parsed);
66+
}
67+
68+
return result;
69+
}
70+
71+
public static T GetHeadersParam<T>(string paramName, IHeaderDictionary headers, ParseDelegate<T> parse)
72+
where T : struct
73+
{
74+
var strVal = headers[paramName];
75+
if (string.IsNullOrEmpty(strVal) || !parse(strVal, out T parsed))
76+
{
77+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
78+
}
79+
80+
return parsed;
81+
}
82+
83+
public static T? GetHeadersParamNullable<T>(string paramName, IHeaderDictionary headers, ParseDelegate<T> parse)
84+
where T : struct
85+
{
86+
var strVal = headers[paramName];
87+
if (string.IsNullOrEmpty(strVal))
88+
{
89+
return null;
90+
}
91+
92+
if (!parse(strVal, out T parsed))
93+
{
94+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
95+
}
96+
97+
return parsed;
98+
}
99+
100+
public static IEnumerable<T> GetHeadersParamCollection<T>(string paramName, IHeaderDictionary headers, ParseDelegate<T> parse)
101+
where T : struct
102+
{
103+
var result = new List<T>();
104+
var strVal = headers[paramName];
105+
var values = strVal.ToString().Split(",");
106+
foreach (var v in values)
107+
{
108+
if (string.IsNullOrEmpty(v) || !parse(v, out T parsed))
109+
{
110+
throw new FormatException($"Parameter '{paramName}' could not be parsed as a {typeof(T).Name}.");
111+
}
112+
result.Add(parsed);
113+
}
114+
115+
return result;
116+
}
117+
118+
public static TEnum GetEnumParam<TEnum>(string paramName, string enumString)
119+
where TEnum : struct
120+
{
121+
if (!Enum.TryParse<TEnum>(enumString, true, out var enumValue))
122+
{
123+
throw new FormatException($"Parameter {paramName} has value of {enumString} which is not a valid literal value for Enum {typeof(TEnum).Name}");
124+
}
125+
126+
return enumValue;
127+
}
128+
129+
public static TEnum? GetEnumParamNullable<TEnum>(string paramName, string? enumString)
130+
where TEnum : struct
131+
{
132+
if (enumString is null)
133+
{
134+
return null;
135+
}
136+
137+
if (!Enum.TryParse<TEnum>(enumString, true, out var enumValue))
138+
{
139+
throw new FormatException($"Parameter {paramName} has value of {enumString} which is not a valid literal value for Enum {typeof(TEnum).Name}");
140+
}
141+
142+
return enumValue;
143+
}
144+
145+
public delegate bool ParseDelegate<T>(string strVal, out T parsed);
146+
}
147+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Net;
5+
using System.Text.Json;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using CompositePublishTest.Application.Clients.CreateClient;
9+
using CompositePublishTest.Domain.Common.Exceptions;
10+
using CompositePublishTest.Domain.Common.Interfaces;
11+
using FluentValidation;
12+
using Intent.RoslynWeaver.Attributes;
13+
using MediatR;
14+
using Microsoft.AspNetCore.Http;
15+
using Microsoft.AspNetCore.Mvc;
16+
using Microsoft.Azure.Functions.Worker;
17+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
18+
using Microsoft.OpenApi.Models;
19+
20+
[assembly: DefaultIntentManaged(Mode.Fully)]
21+
[assembly: IntentTemplate("Intent.AzureFunctions.AzureFunctionClass", Version = "2.0")]
22+
23+
namespace CompositePublishTest.Api.Clients
24+
{
25+
public class CreateClient
26+
{
27+
private readonly IMediator _mediator;
28+
29+
public CreateClient(IMediator mediator)
30+
{
31+
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
32+
}
33+
34+
[Function("CreateClient")]
35+
[OpenApiOperation("CreateClientCommand", tags: new[] { "Clients" }, Description = "Create client command")]
36+
[OpenApiRequestBody(contentType: "application/json", bodyType: typeof(CreateClientCommand))]
37+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.Created, contentType: "application/json", bodyType: typeof(Guid))]
38+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(object))]
39+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.NotFound, contentType: "application/json", bodyType: typeof(object))]
40+
public async Task<IActionResult> Run(
41+
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "clients")] HttpRequest req,
42+
CancellationToken cancellationToken)
43+
{
44+
try
45+
{
46+
var command = await AzureFunctionHelper.DeserializeJsonContentAsync<CreateClientCommand>(req.Body, cancellationToken);
47+
var result = await _mediator.Send(command, cancellationToken);
48+
return new CreatedResult(string.Empty, result);
49+
}
50+
catch (ValidationException exception)
51+
{
52+
return new BadRequestObjectResult(exception.Errors);
53+
}
54+
catch (NotFoundException exception)
55+
{
56+
return new NotFoundObjectResult(new { exception.Message });
57+
}
58+
catch (JsonException exception)
59+
{
60+
return new BadRequestObjectResult(new { exception.Message });
61+
}
62+
catch (FormatException exception)
63+
{
64+
return new BadRequestObjectResult(new { exception.Message });
65+
}
66+
}
67+
}
68+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Net;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using CompositePublishTest.Application.Clients.DeleteClient;
8+
using CompositePublishTest.Domain.Common.Exceptions;
9+
using CompositePublishTest.Domain.Common.Interfaces;
10+
using FluentValidation;
11+
using Intent.RoslynWeaver.Attributes;
12+
using MediatR;
13+
using Microsoft.AspNetCore.Http;
14+
using Microsoft.AspNetCore.Mvc;
15+
using Microsoft.Azure.Functions.Worker;
16+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
17+
using Microsoft.OpenApi.Models;
18+
19+
[assembly: DefaultIntentManaged(Mode.Fully)]
20+
[assembly: IntentTemplate("Intent.AzureFunctions.AzureFunctionClass", Version = "2.0")]
21+
22+
namespace CompositePublishTest.Api.Clients
23+
{
24+
public class DeleteClient
25+
{
26+
private readonly IMediator _mediator;
27+
28+
public DeleteClient(IMediator mediator)
29+
{
30+
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
31+
}
32+
33+
[Function("DeleteClient")]
34+
[OpenApiOperation("DeleteClientCommand", tags: new[] { "Clients" }, Description = "Delete client command")]
35+
[OpenApiParameter(name: "id", In = ParameterLocation.Path, Required = true, Type = typeof(Guid))]
36+
[OpenApiResponseWithoutBody(statusCode: HttpStatusCode.OK)]
37+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(object))]
38+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.NotFound, contentType: "application/json", bodyType: typeof(object))]
39+
public async Task<IActionResult> Run(
40+
[HttpTrigger(AuthorizationLevel.Function, "delete", Route = "clients/{id}")] HttpRequest req,
41+
Guid id,
42+
CancellationToken cancellationToken)
43+
{
44+
try
45+
{
46+
await _mediator.Send(new DeleteClientCommand(id: id), cancellationToken);
47+
return new OkResult();
48+
}
49+
catch (ValidationException exception)
50+
{
51+
return new BadRequestObjectResult(exception.Errors);
52+
}
53+
catch (NotFoundException exception)
54+
{
55+
return new NotFoundObjectResult(new { exception.Message });
56+
}
57+
catch (FormatException exception)
58+
{
59+
return new BadRequestObjectResult(new { exception.Message });
60+
}
61+
}
62+
}
63+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Net;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using CompositePublishTest.Application.Clients;
8+
using CompositePublishTest.Application.Clients.GetClientById;
9+
using CompositePublishTest.Domain.Common.Exceptions;
10+
using CompositePublishTest.Domain.Common.Interfaces;
11+
using FluentValidation;
12+
using Intent.RoslynWeaver.Attributes;
13+
using MediatR;
14+
using Microsoft.AspNetCore.Http;
15+
using Microsoft.AspNetCore.Mvc;
16+
using Microsoft.Azure.Functions.Worker;
17+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
18+
using Microsoft.OpenApi.Models;
19+
20+
[assembly: DefaultIntentManaged(Mode.Fully)]
21+
[assembly: IntentTemplate("Intent.AzureFunctions.AzureFunctionClass", Version = "2.0")]
22+
23+
namespace CompositePublishTest.Api.Clients
24+
{
25+
public class GetClientById
26+
{
27+
private readonly IMediator _mediator;
28+
29+
public GetClientById(IMediator mediator)
30+
{
31+
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
32+
}
33+
34+
[Function("GetClientById")]
35+
[OpenApiOperation("GetClientByIdQuery", tags: new[] { "Clients" }, Description = "Get client by id query")]
36+
[OpenApiParameter(name: "id", In = ParameterLocation.Path, Required = true, Type = typeof(Guid))]
37+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ClientDto))]
38+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(object))]
39+
[OpenApiResponseWithBody(statusCode: HttpStatusCode.NotFound, contentType: "application/json", bodyType: typeof(object))]
40+
public async Task<IActionResult> Run(
41+
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "clients/{id}")] HttpRequest req,
42+
Guid id,
43+
CancellationToken cancellationToken)
44+
{
45+
try
46+
{
47+
var result = await _mediator.Send(new GetClientByIdQuery(id: id), cancellationToken);
48+
return result != null ? new OkObjectResult(result) : new NotFoundResult();
49+
}
50+
catch (ValidationException exception)
51+
{
52+
return new BadRequestObjectResult(exception.Errors);
53+
}
54+
catch (NotFoundException exception)
55+
{
56+
return new NotFoundObjectResult(new { exception.Message });
57+
}
58+
catch (FormatException exception)
59+
{
60+
return new BadRequestObjectResult(new { exception.Message });
61+
}
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)