Skip to content

Commit

Permalink
MarkdownSnippets documentation changes
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Oct 9, 2021
1 parent 3dab626 commit 3c20568
Show file tree
Hide file tree
Showing 12 changed files with 401 additions and 31 deletions.
72 changes: 68 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ ServiceComposer is a ViewModel Composition Gateway.

Designing a UI when the back-end system consists of dozens (or more) of (micro)services is challenging. We have separation and autonomy on the back end, but this all needs to come back together on the front-end. ViewModel Composition stops it from turning into a mess of spaghetti code and prevents simple actions from causing an inefficient torrent of web requests.

toc
<!-- toc -->
## Contents

* [Technical introduction](#technical-introduction)
* [Getting Started](#getting-started)
* [Documentation and supported platforms](#documentation-and-supported-platforms)
* [Philosophy](#philosophy)
* [Service boundaries](#service-boundaries)<!-- endToc -->

## Technical introduction

Expand All @@ -21,7 +28,26 @@ To start using ServiceComposer, follow the outlined steps:
- Create, in an empty or existing solution, a .NET Core 3.x or later empty web application project named `CompositionGateway`.
- Add a package reference to the `ServiceComposer.AspNetCore` NuGet package and configure the `Startup` class as follows:

snippet: net-core-3x-sample-startup
<!-- snippet: net-core-3x-sample-startup -->
<a id='snippet-net-core-3x-sample-startup'></a>
```cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
services.AddViewModelComposition();
}

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseRouting();
app.UseEndpoints(builder => builder.MapCompositionHandlers());
}
}
```
<sup><a href='/src/Snippets.NetCore3x/BasicUsage/Startup.cs#L8-L23' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-sample-startup' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

> NOTE: To use a `Startup` class, Generic Host support is required.
Expand All @@ -30,11 +56,49 @@ snippet: net-core-3x-sample-startup
- Add a new class to create a composition request handler.
- Define the class similar to the following:

snippet: net-core-3x-basic-usage-sales-handler
<!-- snippet: net-core-3x-basic-usage-sales-handler -->
<a id='snippet-net-core-3x-basic-usage-sales-handler'></a>
```cs
public class SalesProductInfo : ICompositionRequestsHandler
{
[HttpGet("/product/{id}")]
public Task Handle(HttpRequest request)
{
var vm = request.GetComposedResponseModel();

//retrieve product details from the sales database or service
vm.ProductId = request.HttpContext.GetRouteValue("id").ToString();
vm.ProductPrice = 100;

return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore3x/BasicUsage/SalesProductInfo.cs#L9-L24' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-basic-usage-sales-handler' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

- Add another class library project, named `Marketing.ViewModelComposition`, and define a composition request handler like the following:

snippet: net-core-3x-basic-usage-marketing-handler
<!-- snippet: net-core-3x-basic-usage-marketing-handler -->
<a id='snippet-net-core-3x-basic-usage-marketing-handler'></a>
```cs
public class MarketingProductInfo: ICompositionRequestsHandler
{
[HttpGet("/product/{id}")]
public Task Handle(HttpRequest request)
{
var vm = request.GetComposedResponseModel();

//retrieve product details from the marketing database or service
vm.ProductName = "Sample product";
vm.ProductDescription = "This is a sample product";

return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore3x/BasicUsage/MarketingProductInfo.cs#L8-L23' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-basic-usage-marketing-handler' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

- Make so that the web application project created at the beginning can load both class library assemblies, e.g., by adding a reference to the class library projects
- Build and run the web application project
Expand Down
10 changes: 5 additions & 5 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ ServiceComposer can be added to existing or new ASP.NET Core projects, or it can

## ASP.Net Model Binding

When handling composition requests it possible to leverage the power of ASP.Net Model Binding to bind incoming forms, bodies, query string parameters, or route data to strongly typed C# models. For more information on model binding refer to the [Model Binding](model-binding.source.md) section.
When handling composition requests it possible to leverage the power of ASP.Net Model Binding to bind incoming forms, bodies, query string parameters, or route data to strongly typed C# models. For more information on model binding refer to the [Model Binding](model-binding.md) section.

### ASP.Net MVC Action results

MVC Action results support allow composition handlers to set custom response results for specific scenarios, like for example, handling bad requests or validation error thoat would nornmally require throwing an exception. For more information on action results refer to the [MVC Action results](action-results.source.md) section.
MVC Action results support allow composition handlers to set custom response results for specific scenarios, like for example, handling bad requests or validation error thoat would nornmally require throwing an exception. For more information on action results refer to the [MVC Action results](action-results.md) section.

## Authentication and Authorization

By virtue of leveraging ASP.NET Core 3.x Endpoints ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements on routes. For more information refer to the [Authentication and Authorization](authentication-authorization.source.md) section
By virtue of leveraging ASP.NET Core 3.x Endpoints ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements on routes. For more information refer to the [Authentication and Authorization](authentication-authorization.md) section

## Serialization

By default ServiceComposer serializes responses using the Newtonsoft JSON serializer. The built-in serialization support can be configured to seriazlie responses using a camel case or pascal case approach on a per request basis by adding to the request an `Accept-Casing` custom HTTP header. For more information refer to the [response serialization casing](response-serialization-casing.source.md) section. Or it's possible to take full control over the [response serialization settings on a case-by-case](custom-json-response-serialization-settings.source.md) by suppliying at configuration time a customization function.
By default ServiceComposer serializes responses using the Newtonsoft JSON serializer. The built-in serialization support can be configured to seriazlie responses using a camel case or pascal case approach on a per request basis by adding to the request an `Accept-Casing` custom HTTP header. For more information refer to the [response serialization casing](response-serialization-casing.md) section. Or it's possible to take full control over the [response serialization settings on a case-by-case](custom-json-response-serialization-settings.md) by suppliying at configuration time a customization function.

Starting with version 1.9.0, regular MVC Output Formatters can be used to serialize the response model, and honor the `Accept` HTTP header set by clients. When using output formatters the serialization casing is controlled by the formatter configuration and not by ServiceComposer. For more information on using output formatters refers to the [output formatters serialization section](output-formatters-serialization.source.md).
Starting with version 1.9.0, regular MVC Output Formatters can be used to serialize the response model, and honor the `Accept` HTTP header set by clients. When using output formatters the serialization casing is controlled by the formatter configuration and not by ServiceComposer. For more information on using output formatters refers to the [output formatters serialization section](output-formatters-serialization.md).
38 changes: 36 additions & 2 deletions docs/action-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,44 @@

MVC Action results support allow composition handlers to set custom response results for specific scenarios, like for example, handling bad requests or validation error thoat would nornmally require throwing an exception. Setting a custom action result is done by using the `SetActionResult()` `HttpRequest` extension method:

snippet: net-core-3x-action-results
<!-- snippet: net-core-3x-action-results -->
<a id='snippet-net-core-3x-action-results'></a>
```cs
public class UseSetActionResultHandler : ICompositionRequestsHandler
{
[HttpGet("/product/{id}")]
public Task Handle(HttpRequest request)
{
var id = request.RouteValues["id"];

//validate the id format
var problems = new ValidationProblemDetails(new Dictionary<string, string[]>()
{
{ "Id", new []{ "The supplied id does not respect the identifier format." } }
});
var result = new BadRequestObjectResult(problems);

request.SetActionResult(result);

return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore3x/ActionResult/UseSetActionResultHandler.cs#L10-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-action-results' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Using MVC action results require enabling output formatters support:

snippet: net-core-3x-action-results-required-config
<!-- snippet: net-core-3x-action-results-required-config -->
<a id='snippet-net-core-3x-action-results-required-config'></a>
```cs
services.AddViewModelComposition(options =>
{
options.ResponseSerialization.UseOutputFormatters = true;
});
```
<sup><a href='/src/Snippets.NetCore3x/ActionResult/UseSetActionResultHandler.cs#L37-L42' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-action-results-required-config' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Note: ServiceComposer supports only one action result per request. If two or more composition handlers try to set action results, only the frst one will succeed and subsequent requests will be ignored.
45 changes: 43 additions & 2 deletions docs/asp-net-core-2x/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,28 @@ Create a new .NET Core console project and add a reference to the following NuGe

Configure the `Startup` class like follows:

snippet: net-core-2x-sample-startup
<!-- snippet: net-core-2x-sample-startup -->
<a id='snippet-net-core-2x-sample-startup'></a>
```cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
services.AddViewModelComposition();
}

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.RunCompositionGateway(routeBuilder =>
{
routeBuilder.MapComposableGet("{controller}/{id:int}");
});
}
}
```
<sup><a href='/src/Snippets.NetCore2x/Startup.cs#L9-L26' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-2x-sample-startup' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

> Note: define routes so to match your project needs. `ServiceComposer` adds provides all the required `MapComposable*` `IRouteBuilder` extension methods to map routes for every HTTP supported Verb.
Expand All @@ -27,7 +48,27 @@ More details on how to implement `IHandleRequests` and `ISubscribeToCompositionE

The response status code can be set in requests handlers and it'll be honored by the composition pipeline. To set a custom response status code the following snippet can be used:

snippet: net-core-2x-sample-handler-with-custom-status-code
<!-- snippet: net-core-2x-sample-handler-with-custom-status-code -->
<a id='snippet-net-core-2x-sample-handler-with-custom-status-code'></a>
```cs
public class SampleHandlerWithCustomStatusCode : IHandleRequests
{
public bool Matches(RouteData routeData, string httpVerb, HttpRequest request)
{
return true;
}

public Task Handle(string requestId, dynamic vm, RouteData routeData, HttpRequest request)
{
var response = request.HttpContext.Response;
response.StatusCode = (int)HttpStatusCode.Forbidden;

return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore2x/SampleHandler/SampleHandler.cs#L9-L25' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-2x-sample-handler-with-custom-status-code' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

NOTE: Requests handlers are executed in parallel in a non-deterministic way, setting the response code in more than one handler can have unpredictable effects.

Expand Down
16 changes: 15 additions & 1 deletion docs/authentication-authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,18 @@

By virtue of leveraging ASP.NET Core 3.x Endpoints ServiceComposer automatically supports authentication and authorization metadata attributes to express authentication and authorization requirements on routes. For example, it's possible to use the `Authorize` attribute to specify that a handler requires authorization. The authorization process is the regular ASP.NET Core 3.x process and no special configuration is needed to plugin ServiceComposer:

snippet: net-core-3x-sample-handler-with-authorization
<!-- snippet: net-core-3x-sample-handler-with-authorization -->
<a id='snippet-net-core-3x-sample-handler-with-authorization'></a>
```cs
public class SampleHandlerWithAuthorization : ICompositionRequestsHandler
{
[Authorize]
[HttpGet("/sample/{id}")]
public Task Handle(HttpRequest request)
{
return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore3x/SampleHandler/SampleHandler.cs#L10-L20' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-sample-handler-with-authorization' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
11 changes: 10 additions & 1 deletion docs/composition-over-controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

ServiceComposer can be used to enhance a MVC web application by adding compostion support to Controllers. ServiceComposer can be configured to use a technique called "Composition over controllers":

snippet: net-core-3x-enable-composition-over-controllers
<!-- snippet: net-core-3x-enable-composition-over-controllers -->
<a id='snippet-net-core-3x-enable-composition-over-controllers'></a>
```cs
services.AddViewModelComposition(options =>
{
options.EnableCompositionOverControllers();
});
```
<sup><a href='/src/Snippets.NetCore3x/CompositionOverController.cs#L10-L15' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-enable-composition-over-controllers' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Once composition over controllers is enabled, ServiceComposer will inject a MVC filter to intercept all controllers invocations. If a route matches a regular controller and a set of composition handlers ServiceComposer will invoke the matching handlers after the controller and before the view is rendered.

Expand Down
18 changes: 17 additions & 1 deletion docs/custom-http-status-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

The response status code can be set in requests handlers and it'll be honored by the composition pipeline. To set a custom response status code the following snippet can be used:

snippet: net-core-3x-sample-handler-with-custom-status-code
<!-- snippet: net-core-3x-sample-handler-with-custom-status-code -->
<a id='snippet-net-core-3x-sample-handler-with-custom-status-code'></a>
```cs
public class SampleHandlerWithCustomStatusCode : ICompositionRequestsHandler
{
[HttpGet("/sample/{id}")]
public Task Handle(HttpRequest request)
{
var response = request.HttpContext.Response;
response.StatusCode = (int)HttpStatusCode.Forbidden;

return Task.CompletedTask;
}
}
```
<sup><a href='/src/Snippets.NetCore3x/SampleHandler/SampleHandler.cs#L22-L34' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-sample-handler-with-custom-status-code' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

NOTE: Requests handlers are executed in parallel in a non-deterministic way, setting the response code in more than one handler can have unpredictable effects.
37 changes: 34 additions & 3 deletions docs/custom-json-response-serialization-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,46 @@ _Available starting with v1.8.0_

By default each response is serialized using [Json.Net](https://www.newtonsoft.com/json/help/html/Introduction.htm) and serialization settings (`JsonSerializerSettings`) are determined by the [requested response casing](response-serialization-casing.source.md). If the requested casing is camel casing, the default, the folowing serialization settings are applied to the response:

snippet: net-core-3x-camel-serialization-settings
<!-- snippet: net-core-3x-camel-serialization-settings -->
<a id='snippet-net-core-3x-camel-serialization-settings'></a>
```cs
var settings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
```
<sup><a href='/src/Snippets.NetCore3x/Serialization/ResponseSettingsBasedOnCasing.cs#L10-L15' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-camel-serialization-settings' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

If the requested case is pascal, the following settings are applied:

snippet: net-core-3x-pascal-serialization-settings
<!-- snippet: net-core-3x-pascal-serialization-settings -->
<a id='snippet-net-core-3x-pascal-serialization-settings'></a>
```cs
var settings = new JsonSerializerSettings();
```
<sup><a href='/src/Snippets.NetCore3x/Serialization/ResponseSettingsBasedOnCasing.cs#L20-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-pascal-serialization-settings' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

It's possible to customize the response serialization settings on a case-by-case using the following configuration:

snippet: net-core-3x-custom-serialization-settings
<!-- snippet: net-core-3x-custom-serialization-settings -->
<a id='snippet-net-core-3x-custom-serialization-settings'></a>
```cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
services.AddViewModelComposition(options =>
{
options.ResponseSerialization.UseCustomJsonSerializerSettings(request =>
{
return new JsonSerializerSettings();
});
});
}
```
<sup><a href='/src/Snippets.NetCore3x/Serialization/Startup.cs#L9-L21' title='Snippet source file'>snippet source</a> | <a href='#snippet-net-core-3x-custom-serialization-settings' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Each time ServiceComposer needs to serialize a response it'll invoke the supplied function.

Expand Down
Loading

0 comments on commit 3c20568

Please sign in to comment.