The aim of this pattern is to get away from the bloated god controllers that have a million action methods and so many dependencies. By following the SimpleEndpoints pattern we keep the endpoint scoped to a small feature and lightweight which makes it easier to understand and manage. The aim is not to blur the line between the controllers and the domain layer. You can choose to dispatch the request to the domain from the endpoint or handle it in the endpoint itself. Make an informed choice based to the context.
More about it in the blog post here.
- Install and reference the Nuget
SimpleEndpoints
In the NuGet Package Manager Console, type:
Install-Package SimpleEndpoints
- Define your request and response models
publicclassSimpleMessage{publicstringMessage{get;set;}}publicclassSimpleResponse{publicstringMessage{get;set;}}- Create your endpoint and implement your business logic (You can choose to handle in place or dispatch to a domain layer)
publicclassSimpleMessageEndpoint:AsyncGetEndpoint<SimpleMessage,SimpleResponse>{publicoverrideasyncTask<ActionResult<SimpleResponse>>HandleAsync(SimpleMessagerequestModel,CancellationTokencancellationToken=default){// Handle in place or dispatch to the domain i.e. return await _someDomainService.HandleAsync(requestModel)returnnewSimpleResponse(){Message="Hello "+requestModel.Message};}}- In the
ConfigureServices()method in yourStartup.csadd the following
publicvoidConfigureServices(IServiceCollectionservices){// Other services go hereservices.AddControllers();services.AddSimpleEndpointsRouting();// This is required to translate endpoint names}- Navigate to the URL
https://localhost:port_number/simplemessage?message=worldand see the result.
Checkout the Examples folder for more. Await more examples in the coming weeks.
The Endpoints are automatically inherited from a ControllerBase and decorated with ApiController attribute. You can decorate the endpoint class/action method with the usual (Route, HttpGet, FromQuery etc) attributes to customise and extend the functionality. Endpoints fully support AspNetCore routing conventions.
If you really need an endpoint with a custom route, a mix of parameters coming from the Route/Query/Body or need full control over of any aspect then you can do something like this. Each of these class/method attributes works independently of each other and you can pick and choose them as required.
[SimpleEndpoint(HttpVerb.Get)]// define the HTTP method being used[Route("custom/[endpoint]")]// use your own route template (i.e this results in "custom/mysimple")publicclassMySimpleEndpoint:SimpleEndpointBase// Extend the SimpleEndpointBase class{// definew your custom signature binding attributes[Route("custom-method")]publicActionResult<GreetingResponse>MyMethodName([FromQuery]intid,[FromBody]GreetingRequestrequestModel)// Mix of binding attributes{returnnewGreetingResponse(){Greeting=$"Hello {requestModel.name} with id {id}"};}}I've had good success with creating a folder structure like below.
You can take this one step further and create a folder per feature group, then put each endpoint specific folder inside that if you want as well. I recommend keeping the view models in the same folder as it's easier to find related code when they sit next to each other.
Feel free to contribute and raise issues as you see fit :)
- Creator: Dasith Wijesiriwardena (https://dasith.me)

