-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDirectServiceExample.cs
More file actions
104 lines (85 loc) · 4.29 KB
/
DirectServiceExample.cs
File metadata and controls
104 lines (85 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using Trellis;
using Trellis.Authorization;
namespace AuthorizationExample;
/// <summary>
/// Part 1 — Without CQRS.
/// Authorization is checked manually in each service method.
/// Uses only Trellis.Authorization — no Mediator dependency.
/// </summary>
public static class DirectServiceExample
{
public static void Run()
{
Console.WriteLine("══════════════════════════════════════════════════════════════");
Console.WriteLine(" Part 1: Direct Service (No CQRS)");
Console.WriteLine(" Authorization is checked manually in each service method.");
Console.WriteLine(" Uses only Trellis.Authorization — no Mediator dependency.");
Console.WriteLine("══════════════════════════════════════════════════════════════");
Console.WriteLine();
Actors.PrintActors();
var service = new DocumentService();
// 1. Alice creates a document
var createResult = service.CreateDocument(Actors.Alice, "Design Doc", "Initial draft");
Print("Alice creates 'Design Doc'", createResult);
var docId = createResult.Value.Id;
// 2. Alice edits her own document (owner)
Print("Alice edits her document",
service.EditDocument(Actors.Alice, docId, "Updated by Alice"));
// 3. Bob tries to edit Alice's document (not owner, no EditAny)
Print("Bob tries to edit Alice's document",
service.EditDocument(Actors.Bob, docId, "Updated by Bob"));
// 4. Charlie edits Alice's document (has Documents.EditAny)
Print("Charlie edits Alice's document",
service.EditDocument(Actors.Charlie, docId, "Updated by Charlie"));
// 5. Bob tries to publish (no Documents.Publish permission)
Print("Bob tries to publish",
service.PublishDocument(Actors.Bob, docId));
// 6. Alice publishes her document (has Documents.Publish)
Print("Alice publishes her document",
service.PublishDocument(Actors.Alice, docId));
}
private static void Print(string action, Result<Document> result) =>
Console.WriteLine(result.Match(
doc => $" {action,-45} → ✅ {(doc.IsPublished ? "Published" : "Success")}",
error => $" {action,-45} → ❌ {error.Detail}"));
}
/// <summary>
/// A service that manually checks authorization in each method.
/// Authorization, validation, and business logic are mixed together.
/// Compare this with the CQRS handlers in MediatorExample.cs —
/// those handlers contain ZERO authorization code.
/// </summary>
public sealed class DocumentService
{
private readonly DocumentStore _store = new();
public Result<Document> CreateDocument(Actor actor, string title, string content)
{
var doc = new Document(Guid.NewGuid().ToString(), actor.Id, title, content);
_store.Add(doc);
return Result.Success(doc);
}
public Result<Document> EditDocument(Actor actor, string documentId, string newContent)
{
var doc = _store.Get(documentId);
if (doc is null)
return Result.Failure<Document>(Error.NotFound("Document not found"));
// ⚠️ Auth logic mixed with business logic
if (actor.Id != doc.OwnerId && !actor.HasPermission("Documents.EditAny"))
return Result.Failure<Document>(Error.Forbidden("Only the owner can edit this document"));
var updated = doc with { Content = newContent };
_store.Update(updated);
return Result.Success(updated);
}
public Result<Document> PublishDocument(Actor actor, string documentId)
{
var doc = _store.Get(documentId);
if (doc is null)
return Result.Failure<Document>(Error.NotFound("Document not found"));
// ⚠️ Auth logic mixed with business logic
if (!actor.HasPermission("Documents.Publish"))
return Result.Failure<Document>(Error.Forbidden("Missing required permission: Documents.Publish"));
var published = doc with { IsPublished = true };
_store.Update(published);
return Result.Success(published);
}
}