diff --git a/samples/Demo/Beef.Demo.Api/Controllers/PersonController.cs b/samples/Demo/Beef.Demo.Api/Controllers/PersonController.cs
new file mode 100644
index 00000000..62e50ef9
--- /dev/null
+++ b/samples/Demo/Beef.Demo.Api/Controllers/PersonController.cs
@@ -0,0 +1,38 @@
+#nullable enable
+
+using CoreEx.Results;
+
+namespace Beef.Demo.Api.Controllers
+{
+ public partial class PersonController
+ {
+ ///
+ /// Extend Response.
+ ///
+ /// A resultant string.
+ [HttpPost("api/v1/persons/extend-response", Name = "Person_ExtendResponse")]
+ [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
+ [ProducesResponseType((int)HttpStatusCode.NoContent)]
+ public Task ExtendResponse(string? name)
+ => _webApi.PostWithResultAsync(Request, p =>
+ {
+ return Result.GoAsync(() => _manager.ExtendResponseAsync(name)) // Execute the business logic.
+ .ThenAs(r => // Then handle response where Result.IsSuccess; otherwise, allow to bubble out.
+ {
+ var ia = ValueContentResult.CreateResult(r, HttpStatusCode.OK, null, _webApi.JsonSerializer, p.RequestOptions, false, null); // Use standard CoreEx ValueContentResult to handle the response.
+ if (ia is ValueContentResult vcr) // Ensure is a ValueContentResult, and if so, then manipulate.
+ {
+ vcr.BeforeExtension = hr => // Extend the reponse by adding a new header.
+ {
+ hr.Headers.Add("X-Beef-Test", "123");
+ return Task.CompletedTask;
+ };
+ }
+
+ return ia;
+ });
+ }, alternateStatusCode: HttpStatusCode.NoContent, operationType: CoreEx.OperationType.Unspecified);
+ }
+}
+
+#nullable restore
\ No newline at end of file
diff --git a/samples/Demo/Beef.Demo.Business/Data/Generated/IPersonData.cs b/samples/Demo/Beef.Demo.Business/Data/Generated/IPersonData.cs
index 7e3d05d6..19f37324 100644
--- a/samples/Demo/Beef.Demo.Business/Data/Generated/IPersonData.cs
+++ b/samples/Demo/Beef.Demo.Business/Data/Generated/IPersonData.cs
@@ -202,6 +202,13 @@ public partial interface IPersonData
/// The identifier.
/// A resultant .
Task> SimulateWorkAsync(Guid id);
+
+ ///
+ /// Extend Response.
+ ///
+ /// The Name.
+ /// A resultant .
+ Task> ExtendResponseAsync(string? name);
}
#pragma warning restore
diff --git a/samples/Demo/Beef.Demo.Business/Data/Generated/PersonData.cs b/samples/Demo/Beef.Demo.Business/Data/Generated/PersonData.cs
index 2d02a4e1..4372172c 100644
--- a/samples/Demo/Beef.Demo.Business/Data/Generated/PersonData.cs
+++ b/samples/Demo/Beef.Demo.Business/Data/Generated/PersonData.cs
@@ -230,6 +230,9 @@ public Task DeleteWithEfAsync(Guid id) => DataInvoker.Current.InvokeAsync(this,
///
public Task> SimulateWorkAsync(Guid id) => SimulateWorkOnImplementationAsync(id);
+ ///
+ public Task> ExtendResponseAsync(string? name) => ExtendResponseOnImplementationAsync(name);
+
///
/// Provides the property and database column mapping.
///
diff --git a/samples/Demo/Beef.Demo.Business/Data/PersonData.cs b/samples/Demo/Beef.Demo.Business/Data/PersonData.cs
index aa1eb67b..e85c9ca0 100644
--- a/samples/Demo/Beef.Demo.Business/Data/PersonData.cs
+++ b/samples/Demo/Beef.Demo.Business/Data/PersonData.cs
@@ -166,5 +166,7 @@ private static Task Add3OnImplementationAsync(Person value)
if (value == null) throw new ArgumentNullException(nameof(value));
return Task.CompletedTask;
}
+
+ private Task> ExtendResponseOnImplementationAsync(string? name) => name is null ? Result.Fail("Name is needed dude!").AsTask() : Result.Ok(name).AsTask();
}
}
\ No newline at end of file
diff --git a/samples/Demo/Beef.Demo.Business/DataSvc/Generated/IPersonDataSvc.cs b/samples/Demo/Beef.Demo.Business/DataSvc/Generated/IPersonDataSvc.cs
index 6c55335f..fefd1419 100644
--- a/samples/Demo/Beef.Demo.Business/DataSvc/Generated/IPersonDataSvc.cs
+++ b/samples/Demo/Beef.Demo.Business/DataSvc/Generated/IPersonDataSvc.cs
@@ -221,6 +221,13 @@ public partial interface IPersonDataSvc
/// The identifier.
/// A resultant .
Task> SimulateWorkAsync(Guid id);
+
+ ///
+ /// Extend Response.
+ ///
+ /// The Name.
+ /// A resultant .
+ Task> ExtendResponseAsync(string? name);
}
#pragma warning restore
diff --git a/samples/Demo/Beef.Demo.Business/DataSvc/Generated/PersonDataSvc.cs b/samples/Demo/Beef.Demo.Business/DataSvc/Generated/PersonDataSvc.cs
index 9e23ff32..0d4e5206 100644
--- a/samples/Demo/Beef.Demo.Business/DataSvc/Generated/PersonDataSvc.cs
+++ b/samples/Demo/Beef.Demo.Business/DataSvc/Generated/PersonDataSvc.cs
@@ -45,6 +45,7 @@ public partial class PersonDataSvc : IPersonDataSvc
private Func? _deleteWithEfOnAfterAsync;
private Func? _getDocumentationOnAfterAsync;
private Func>? _simulateWorkOnAfterAsync;
+ private Func>? _extendResponseOnAfterAsync;
#endregion
@@ -309,6 +310,13 @@ public async Task GetDocumentationAsync(Guid id)
.ThenAsync(r => _simulateWorkOnAfterAsync?.Invoke(r, id) ?? Result.SuccessTask)
.Then(r => _events.PublishValueEvent("WorkIt", new Uri($"/person/", UriKind.Relative), $"Work", "Simulated"));
}, new InvokerArgs { IncludeTransactionScope = true, EventPublisher = _events });
+
+ ///
+ public Task> ExtendResponseAsync(string? name)
+ {
+ return Result.GoAsync(_data.ExtendResponseAsync(name))
+ .ThenAsync(r => _extendResponseOnAfterAsync?.Invoke(r, name) ?? Result.SuccessTask);
+ }
}
#pragma warning restore
diff --git a/samples/Demo/Beef.Demo.Business/Generated/IPersonManager.cs b/samples/Demo/Beef.Demo.Business/Generated/IPersonManager.cs
index 0ebf4858..debd2583 100644
--- a/samples/Demo/Beef.Demo.Business/Generated/IPersonManager.cs
+++ b/samples/Demo/Beef.Demo.Business/Generated/IPersonManager.cs
@@ -242,6 +242,13 @@ public partial interface IPersonManager
/// The identifier.
/// A resultant .
Task> SimulateWorkAsync(Guid id);
+
+ ///
+ /// Extend Response.
+ ///
+ /// The Name.
+ /// A resultant .
+ Task> ExtendResponseAsync(string? name);
}
#pragma warning restore
diff --git a/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs b/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs
index 3df39467..99755f71 100644
--- a/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs
+++ b/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs
@@ -167,6 +167,11 @@ public partial class PersonManager : IPersonManager
private Func>? _simulateWorkOnBeforeAsync;
private Func>? _simulateWorkOnAfterAsync;
+ private Func>? _extendResponseOnPreValidateAsync;
+ private Action? _extendResponseOnValidate;
+ private Func>? _extendResponseOnBeforeAsync;
+ private Func>? _extendResponseOnAfterAsync;
+
#endregion
///
@@ -674,6 +679,20 @@ await MultiValidator.Create()
.ThenAsync(r => _simulateWorkOnAfterAsync?.Invoke(r, id) ?? Result.SuccessTask)
.Then(r => Cleaner.Clean(r));
}, InvokerArgs.Unspecified);
+
+ ///
+ public Task> ExtendResponseAsync(string? name) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) =>
+ {
+ return Result.Go()
+ .Then(() => Cleaner.CleanUp(name))
+ .ThenAsync(() => _extendResponseOnPreValidateAsync?.Invoke(name) ?? Result.SuccessTask)
+ .ValidateAsync(() => MultiValidator.Create()
+ .Additional(mv => _extendResponseOnValidate?.Invoke(mv, name)), cancellationToken: ct)
+ .ThenAsync(() => _extendResponseOnBeforeAsync?.Invoke(name) ?? Result.SuccessTask)
+ .ThenAsAsync(() => _dataService.ExtendResponseAsync(name))
+ .ThenAsync(r => _extendResponseOnAfterAsync?.Invoke(r, name) ?? Result.SuccessTask)
+ .Then(r => Cleaner.Clean(r));
+ }, InvokerArgs.Unspecified);
}
#pragma warning restore
diff --git a/samples/Demo/Beef.Demo.CodeGen/entity.beef-5.yaml b/samples/Demo/Beef.Demo.CodeGen/entity.beef-5.yaml
index 9f06318c..667d5399 100644
--- a/samples/Demo/Beef.Demo.CodeGen/entity.beef-5.yaml
+++ b/samples/Demo/Beef.Demo.CodeGen/entity.beef-5.yaml
@@ -105,7 +105,8 @@ entities:
parameters: [
{ name: Id, text: '{{Person}} identifier', type: Guid, isMandatory: true }
]},
- { name: SimulateWork, type: Custom, withResult: true, returnType: string?, webApiRoute: simulate, webApiMethod: HttpGet, webApiStatus: OK, primaryKey: true, eventSubject: Work:Simulated, eventValue: '"WorkIt"' }
+ { name: SimulateWork, type: Custom, withResult: true, returnType: string?, webApiRoute: simulate, webApiMethod: HttpGet, webApiStatus: OK, primaryKey: true, eventSubject: Work:Simulated, eventValue: '"WorkIt"' },
+ { name: ExtendResponse, type: Custom, returnType: string?, excludeWebApi: true, webApiRoute: extend-response, withResult: true, parameters: [ { name: Name } ] }
]
}
diff --git a/samples/Demo/Beef.Demo.Common/Agents/Generated/IPersonAgent.cs b/samples/Demo/Beef.Demo.Common/Agents/Generated/IPersonAgent.cs
index 6795834c..4949159f 100644
--- a/samples/Demo/Beef.Demo.Common/Agents/Generated/IPersonAgent.cs
+++ b/samples/Demo/Beef.Demo.Common/Agents/Generated/IPersonAgent.cs
@@ -349,6 +349,15 @@ public partial interface IPersonAgent
/// The .
/// A .
Task> SimulateWorkAsync(Guid id, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Extend Response.
+ ///
+ /// The Name.
+ /// The optional .
+ /// The .
+ /// A .
+ Task> ExtendResponseAsync(string? name, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default);
}
}
diff --git a/samples/Demo/Beef.Demo.Common/Agents/Generated/PersonAgent.cs b/samples/Demo/Beef.Demo.Common/Agents/Generated/PersonAgent.cs
index a51414fe..79d90e6f 100644
--- a/samples/Demo/Beef.Demo.Common/Agents/Generated/PersonAgent.cs
+++ b/samples/Demo/Beef.Demo.Common/Agents/Generated/PersonAgent.cs
@@ -170,6 +170,10 @@ public Task GetDocumentationAsync(Guid id, HttpRequestOptions? reque
///
public Task> SimulateWorkAsync(Guid id, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)
=> GetAsync("api/v1/persons/simulate", requestOptions: requestOptions, args: HttpArgs.Create(new HttpArg("id", id)), cancellationToken: cancellationToken);
+
+ ///
+ public Task> ExtendResponseAsync(string? name, HttpRequestOptions? requestOptions = null, CancellationToken cancellationToken = default)
+ => PostAsync("api/v1/persons/extend-response", requestOptions: requestOptions, args: HttpArgs.Create(new HttpArg("name", name)), cancellationToken: cancellationToken);
}
}
diff --git a/samples/Demo/Beef.Demo.Test/PersonTest.cs b/samples/Demo/Beef.Demo.Test/PersonTest.cs
index 6c3833f0..18ca2463 100644
--- a/samples/Demo/Beef.Demo.Test/PersonTest.cs
+++ b/samples/Demo/Beef.Demo.Test/PersonTest.cs
@@ -1312,5 +1312,30 @@ public void I420_Simulate_Perf()
}
#endregion
+
+ #region ExtendResponse
+
+ [Test, TestSetUp]
+ public void J110_ExtendResponse_Error()
+ {
+ AgentTester.Test()
+ .ExpectStatusCode(HttpStatusCode.BadRequest)
+ .ExpectError("Name is needed dude!")
+ .Run(a => a.ExtendResponseAsync(null));
+ }
+
+ [Test, TestSetUp]
+ public void J120_ExtendResponse_Success()
+ {
+ var resp = AgentTester.Test()
+ .ExpectStatusCode(HttpStatusCode.OK)
+ .ExpectValue("Sweet!")
+ .Run(a => a.ExtendResponseAsync("Sweet!"));
+
+ if (resp.Response.Headers.TryGetValues("X-Beef-Test", out var values))
+ Assert.That(values, Is.EquivalentTo(new string[] { "123" }));
+ }
+
+ #endregion
}
}
\ No newline at end of file