{"id":19989990,"url":"https://github.com/burgyn/mmlib.mediatr.generators","last_synced_at":"2025-05-04T09:34:05.433Z","repository":{"id":115374765,"uuid":"382229205","full_name":"Burgyn/MMLib.MediatR.Generators","owner":"Burgyn","description":null,"archived":false,"fork":false,"pushed_at":"2023-05-02T17:46:03.000Z","size":192,"stargazers_count":37,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-01T21:36:30.729Z","etag":null,"topics":["csharp-sourcegenerator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Burgyn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-07-02T04:24:54.000Z","updated_at":"2024-10-13T17:50:13.000Z","dependencies_parsed_at":"2024-01-06T02:09:53.230Z","dependency_job_id":null,"html_url":"https://github.com/Burgyn/MMLib.MediatR.Generators","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Burgyn%2FMMLib.MediatR.Generators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Burgyn%2FMMLib.MediatR.Generators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Burgyn%2FMMLib.MediatR.Generators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Burgyn%2FMMLib.MediatR.Generators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Burgyn","download_url":"https://codeload.github.com/Burgyn/MMLib.MediatR.Generators/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224391390,"owners_count":17303609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp-sourcegenerator"],"created_at":"2024-11-13T04:50:53.190Z","updated_at":"2024-11-13T04:50:59.190Z","avatar_url":"https://github.com/Burgyn.png","language":"C#","funding_links":["https://www.buymeacoffee.com/0dQ7tNG"],"categories":[],"sub_categories":[],"readme":"# MediatR controllers generator\n\nThis generator generates controllers and their methods for you based on your [MediatR](https://github.com/jbogard/MediatR) requests.\n\n---\n\nDid this project help you? [You can now buy me a beer 😎🍺.](https://www.buymeacoffee.com/0dQ7tNG)\n\n[![\"You can now buy me a beer 😎🍺.\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/0dQ7tNG)\n\n## Installation\n\n```bash\n  dotnet add package MMLib.MediatR.Generators\n```\n\n## How to use it\n\n[MediatR](https://github.com/jbogard/MediatR)  is a great project that enables in-process messaging. Many ASP.NET Core projects use it to implement the CQRS pattern. You use MediatR to define yours commands and queries, but you still have to manually write a large amount of similar code to the controllers.\n\nThis generator will generate the necessary controllers and methods for you. Just decorate your request with an attribute according to the appropriate http method and define the name of the controller. In this case, it will be `[HttpPost(Controller = \"People\")]`.\n\n```csharp\n[HttpPost(Controller = \"People\")]\npublic record CreatePersonCommand(string FirstName, string LastName): IRequest\u003cint\u003e\n```\n\nThe generator generates the following controller:\n\n```csharp\n[ApiController]\n[Route(\"[controller]\")]\npublic partial class PeopleController : ControllerBase\n{\n    private IMediator _mediator;\n\n    /// \u003csummary\u003e\n    /// Ctor.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"mediator\"\u003eMediator.\u003c/param\u003e\n    public PeopleController(IMediator mediator)\n    {\n        _mediator = mediator;\n    }\n\n    [HttpPost(\"\")]\n    public async Task\u003cActionResult\u003e CreatePersonCommand([FromBody] CreatePersonCommand command)\n    {\n        return await SendCreateCommand(command, nameof(CreatePersonCommand));\n    }\n\n    private async Task\u003cCreatedResult\u003e SendCreateCommand\u003cTResponse\u003e(IRequest\u003cTResponse\u003e command, string actionName = null)\n    {\n        var ret = new\n        {\n          id = await _mediator.Send(command)\n        };\n        string url = actionName != null ? Url.Link(actionName, ret) ?? string.Empty : string.Empty;\n        return Created(url, ret);\n    }\n}\n```\n\n## Another example\n\nYou have the following commands and queries.\n\n```csharp\n/// \u003csummary\u003e\n/// Testing comment.\n/// \u003c/summary\u003e\n[HttpPost(Controller = \"People\")]\npublic record CreatePersonCommand(string FirstName, string LastName): IRequest\u003cint\u003e\n{\n    [Microsoft.AspNetCore.Authorization.AllowAnonymous]\n    [Microsoft.AspNetCore.Mvc.ValidateAntiForgeryToken]\n    private void RequestMethodDefinition()\n    {\n        throw new NotImplementedException();\n    }\n}\n\n[HttpDelete(\"{id:int}\", Controller = \"People\")]\npublic class DeletePersonCommand : DeleteCommandBase\u003cPerson\u003e{}\n\n/// \u003csummary\u003e\n/// Command for update person.\n/// \u003c/summary\u003e\n[HttpPut(\"{id:int}\", Controller = \"People\")]\n[AdditionalParameters(\"id\")]\npublic record UpdatePersonCommand([property:JsonIgnore]int Id, string FirstName, string LastName) : IRequest\u003cUnit\u003e;\n\n[HttpGet(\"all\", Controller = \"People\", From = From.Ignore)]\npublic record GetAllPeopleQuery() : IRequest\u003cIEnumerable\u003cPerson\u003e\u003e;\n\n[HttpGet(Controller = \"People\", Name = \"GetPeople\", From = From.Query)]\npublic record GetPeopleQuery(int Skip, int Take) : IRequest\u003cIEnumerable\u003cPerson\u003e\u003e;\n\n[HttpGet(\"{id}\", Controller = \"People\", Name = \"GetById\")]\npublic record Query(int Id) : IRequest\u003cResponse\u003e;\n```\n\nThe generated controller looks like this:\n\n```csharp\n[ApiController]\n[Route(\"[controller]\")]\npublic partial class PeopleController : ControllerBase\n{\n    private IMediator _mediator;\n    /// \u003csummary\u003e\n    /// Ctor.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"mediator\"\u003eMediator.\u003c/param\u003e\n    public PeopleController(IMediator mediator)\n    {\n        _mediator = mediator;\n    }\n\n    /// \u003csummary\u003e\n    /// Testing comment.\n    /// \u003c/summary\u003e\n    [HttpPost(\"\")]\n    [Microsoft.AspNetCore.Authorization.AllowAnonymous()]\n    [Microsoft.AspNetCore.Mvc.ValidateAntiForgeryToken()]\n    public async Task\u003cActionResult\u003e CreatePersonCommand([FromBody] CreatePersonCommand command)\n    {\n        return await SendCreateCommand(command, nameof(CreatePersonCommand));\n    }\n\n    [HttpDelete(\"{id:int}\")]\n    public async Task\u003cActionResult\u003e DeletePersonCommand([FromRoute] DeletePersonCommand command)\n    {\n        await _mediator.Send(command);\n        return NoContent();\n    }\n\n    /// \u003csummary\u003e\n    /// Command for update person.\n    /// \u003c/summary\u003e\n    [HttpPut(\"{id:int}\")]\n    public async Task\u003cActionResult\u003e UpdatePersonCommand([FromBody] UpdatePersonCommand command, Int32 id)\n    {\n        command.Id = id;\n        await _mediator.Send(command);\n        return Ok();\n    }\n\n    [HttpGet(\"all\")]\n    public async Task\u003cIEnumerable\u003cPerson\u003e\u003e GetAllPeopleQuery()\n    {\n        return await _mediator.Send(new GetAllPeopleQuery());\n    }\n\n    [HttpGet(\"\")]\n    public async Task\u003cIEnumerable\u003cPerson\u003e\u003e GetPeople([FromQuery] GetPeopleQuery query)\n    {\n        return await _mediator.Send(query);\n    }\n\n    [HttpGet(\"{id}\")]\n    public async Task\u003cResponse\u003e GetById([FromRoute] Query query)\n    {\n        return await _mediator.Send(query);\n    }\n\n    private async Task\u003cCreatedResult\u003e SendCreateCommand\u003cTResponse\u003e(IRequest\u003cTResponse\u003e command, string actionName = null)\n    {\n        var ret = new\n        {\n          id = await _mediator.Send(command)\n        };\n        string url = actionName != null ? Url.Link(actionName, ret) ?? string.Empty : string.Empty;\n        return Created(url, ret);\n    }\n}\n```\n\n## Customizations\n\n### Http method type\n\nUse the inherited attributes from the `HttpMethodAttribute` to specify to which type of http method to translate your command / query.  Supported types are `Get`, `Post`, `Put`, `Delete`.\n\n### Controller name\n\nParameter `Controller` is required. Use this parameter to define the name of the controller and to group the methods to be within one controller.\n\n### Method name\n\nThe method name is generated based on the Command / Query class name *(if it is a nested class, the prefix is the name of the main class)*. However, if you want to change this, you can use the `Name` property. Eg: `[HttpGet(Controller = \"People\", Name = \"GetPeople\")]`\n\n### Parameter source type\n\nThe given command / query is used as a parameter of the generated methods. It is used with the `FromRoute` attribute for the `Get` and `Delete` methods and with the `FromBody` attribute for `Post` and `Put`. If you want to change this default behavior, use the `From` property. Possible values: `Ignore`, `Route`, `Query`, `Body`, `Header`, `Form`, `Services`. Eg.: `[HttpGet(Controller = \"People\", From = From.Query)]`.\n\n\u003e If you do not want the command / query type to be used as a parameter, use `From.Ignore`. Command / query will be created in the method `_mediator.Send(new GetAllPeopleQuery())`.\n\n### Route template\n\nYou can define route template for the method: `[HttpDelete(\"{id:int}\")]`.\n\n### Response type\n\nThe response type is derived based on the generic used to define your command / query. For query definition `record GetPersonQuery() : IRequest\u003cPerson\u003e;` it will be `Task\u003cPerson\u003e`. If you use MediatR type `Unit` it will be `Task\u003cActionResult\u003e`.\n\nUse `ResponseType` property to define your own type. Eg.: `[HttpPost(Controller = \"People\", ResponseType = typeof(long))]`\n\n### Additional parameter\n\nSometimes you need to add another parameter to the path, which you then want to set to the command. Typically, with the `Put` method, you want to have the record `Id` in the path and assign it to the command. You can use the attribute for this `[AdditionalParameters(\"id\")]`.\n\nThe generated method looks like this:\n\n```csharp\n[HttpPut(\"{id:int}\")]\npublic async Task\u003cActionResult\u003e UpdatePersonCommand([FromBody] UpdatePersonCommand command, Int32 id)\n{\n    command.Id = id;\n    await _mediator.Send(command);\n    return Ok();\n}\n```\n\n### New method to generated controller\n\nControllers are generated as a `partial class`es, so if you want to add a new method to this controller,  you can create a new `partial class` for this controller.\n\n### Comments\n\nIf you have enabled the generation of a documentation file (`\u003cGenerateDocumentationFile\u003etrue\u003c/GenerateDocumentationFile\u003e`) in your csproj, your XML comments from the command / query definitions will be used as comments of the generated method.\n\n## Templates\n\nThe generation consists of several templates, some of which can be overwritten in the end application.\n\n### General\n\n[Scriban](https://github.com/scriban/scriban) is used as templating engine. All templates you must define in `csproj` file as additional files. The `TemplateType` property determines what type of template it is. Use the property `ControllerName` to override the template for a specific controller.\n\n### Controllers usings\n\nIn your project you can define your own `.txt` file, which will contain the `usings` part of the controller.\n\nYour file might look like this:\n\n```csharp\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\n```\n\nYour template must be added to `csproj` as an additional file with the `TemplateType` property set to `ControllerUsings`\n\n```xml\n\u003cItemGroup\u003e\n  \u003cAdditionalFiles Include=\"Templates\\Attributes.txt\" MMLib_TemplateType=\"ControllerUsings\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\nThis template is used for all generated controllers. To define a custom usage for a particular controller, you must set the controller name using the `MMLib_ControllerName` property.\n\n```xml\n\u003cItemGroup\u003e\n  \u003cAdditionalFiles Include=\"Templates\\Attributes.txt\" MMLib_TemplateType=\"ControllerUsings\" MMLib_ControllerName=\"ProductsController\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n### Controller attributes\n\n`MMLib_TemplateType` property must be set to `ControllerAttributes`.\n\n### Http method body\n\nYou can override body of http method. Eg.: `HttpGetMethodBody.txt`\n\n```csharp\n{\n\treturn await _mediator.Send({{ parameters | get_parameter request_type }});\n}\n```\n\n```xml\n\u003cItemGroup\u003e\n  \u003cAdditionalFiles Include=\"Templates\\HttpGetMethodBody.txt\" MMLib_TemplateType=\"MethodBody\" MMLib_MethodType=\"Get\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n### Method attributes\n\nIf you want to override the attributes above all generated methods, you can also do so via a template. `MMLib_TemplateType` property must be set to `MethodAttributes`.\n\nBut if you want to define specific attributes for a particular method, you can use a hack to add the `RequestMethodDefinition` method to your command / query. All attributes defined above this method will be used when generating the http method.\n\n```csharp\n[HttpPost(Controller = \"People\")]\npublic record CreatePersonCommand(string FirstName, string LastName): IRequest\u003cint\u003e\n{\n    [Microsoft.AspNetCore.Authorization.AllowAnonymous]\n    [Microsoft.AspNetCore.Mvc.ValidateAntiForgeryToken]\n    private void RequestMethodDefinition()\n    {\n        throw new NotImplementedException();\n    }\n}\n```\n\n### Whole controller template\n\nYou can override whole controller template. `MMLib_TemplateType` property must be set to `Controller`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburgyn%2Fmmlib.mediatr.generators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburgyn%2Fmmlib.mediatr.generators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburgyn%2Fmmlib.mediatr.generators/lists"}