Skip to content

Commit 6a027f6

Browse files
author
Nick Tune
committed
Add compositional delegates example
1 parent 731a11f commit 6a027f6

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
namespace FunctionalProject.Features.CompositionalDelegates
2+
{
3+
using System;
4+
using System.Threading.Tasks;
5+
using Botwin;
6+
using Botwin.ModelBinding;
7+
using Botwin.Response;
8+
using FunctionalProject.Features.NamedDelegatesFilms.Films;
9+
using FunctionalProject.Features.NamedDelegatesFilms.Films.Permissions;
10+
using Microsoft.AspNetCore.Http;
11+
using Models;
12+
13+
public class FilmsModule : BotwinModule
14+
{
15+
private readonly Films.CreateFilm createFilm;
16+
17+
public FilmsModule() : base("/api/delegate-coposition/films")
18+
{
19+
// If the framework lets you, pass the wired-up functions into the constructor instead for testability
20+
this.createFilm = ApplicationServices.Default.createFilm;
21+
22+
this.Post("/", this.CreateFilm);
23+
}
24+
25+
private async Task CreateFilm(HttpContext context)
26+
{
27+
var result = context.Request.BindAndValidate<Film>();
28+
29+
if (!result.ValidationResult.IsValid)
30+
{
31+
context.Response.StatusCode = 422;
32+
await context.Response.Negotiate(result.ValidationResult.GetFormattedErrors());
33+
return;
34+
}
35+
36+
try
37+
{
38+
createFilm(result.Data);
39+
context.Response.StatusCode = 201;
40+
}
41+
catch (Exception)
42+
{
43+
context.Response.StatusCode = 403;
44+
}
45+
}
46+
}
47+
48+
// This class composes all of the functions together with their dependencies. It is the composition root of the app
49+
// You would call this once when the application starts and then thread the functions into the controllers that need them
50+
public class ApplicationServices
51+
{
52+
public Films.CreateFilm createFilm;
53+
54+
public ApplicationServices()
55+
{
56+
ValidUserDelegate vud = () => ValidUserQuery.Execute();
57+
58+
// Use currying to supply 'constructor' dependencies
59+
createFilm = Films.Create(vud);
60+
}
61+
62+
public static ApplicationServices Default => new ApplicationServices();
63+
64+
// As this class grows large, you can chop it up into multiple cohesive classes e.g. FilmService
65+
}
66+
67+
public static class Films
68+
{
69+
public delegate void CreateFilm(Film film);
70+
71+
// This is effectively an object constructor
72+
public static CreateFilm Create(ValidUserDelegate validUserQuery)
73+
{
74+
// C# local method syntax makes it easy to return a function from a function
75+
// This function is basically the wired up object
76+
void func(Film film)
77+
{
78+
if (!validUserQuery())
79+
{
80+
throw new InvalidOperationException();
81+
}
82+
83+
//Do some special MEGA CORP business validation
84+
85+
//Save to database by writing SQL here
86+
}
87+
88+
return func;
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)