{"id":22143768,"url":"https://github.com/mrdave1999/simpleresults","last_synced_at":"2025-05-16T14:07:26.899Z","repository":{"id":199840075,"uuid":"703612666","full_name":"MrDave1999/SimpleResults","owner":"MrDave1999","description":"A simple library to implement the Result pattern for returning from services","archived":false,"fork":false,"pushed_at":"2025-04-18T19:47:22.000Z","size":740,"stargazers_count":123,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-19T13:14:09.380Z","etag":null,"topics":["aspnetcore","csharp","dotnet","error-handling","fluent-validation","pattern","result"],"latest_commit_sha":null,"homepage":"https://mrdave1999.github.io/SimpleResults","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/MrDave1999.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-11T15:09:07.000Z","updated_at":"2025-04-18T15:35:29.000Z","dependencies_parsed_at":"2023-10-24T20:31:09.836Z","dependency_job_id":"f5055e19-8680-4e60-b034-b3993c0a31c6","html_url":"https://github.com/MrDave1999/SimpleResults","commit_stats":null,"previous_names":["mrdave1999/simpleresults"],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrDave1999%2FSimpleResults","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrDave1999%2FSimpleResults/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrDave1999%2FSimpleResults/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MrDave1999%2FSimpleResults/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MrDave1999","download_url":"https://codeload.github.com/MrDave1999/SimpleResults/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"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":["aspnetcore","csharp","dotnet","error-handling","fluent-validation","pattern","result"],"created_at":"2024-12-01T22:15:58.893Z","updated_at":"2025-05-16T14:07:26.880Z","avatar_url":"https://github.com/MrDave1999.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SimpleResults\n\n[![SimpleResults](https://img.shields.io/nuget/vpre/SimpleResults?label=SimpleResults%20-%20nuget\u0026color=red)](https://www.nuget.org/packages/SimpleResults)\n[![downloads](https://img.shields.io/nuget/dt/SimpleResults?color=yellow)](https://www.nuget.org/packages/SimpleResults)\n\n[![SimpleResults-AspNetCore](https://img.shields.io/nuget/vpre/SimpleResults.AspNetCore?label=SimpleResults.AspNetCore%20-%20nuget\u0026color=red)](https://www.nuget.org/packages/SimpleResults.AspNetCore)\n[![downloads](https://img.shields.io/nuget/dt/SimpleResults.AspNetCore?color=yellow)](https://www.nuget.org/packages/SimpleResults.AspNetCore)\n\n[![SimpleResults-FluentValidation](https://img.shields.io/nuget/vpre/SimpleResults.FluentValidation?label=SimpleResults.FluentValidation%20-%20nuget\u0026color=red)](https://www.nuget.org/packages/SimpleResults.FluentValidation)\n[![downloads](https://img.shields.io/nuget/dt/SimpleResults.FluentValidation?color=yellow)](https://www.nuget.org/packages/SimpleResults.FluentValidation)\n\n[![SimpleResults-logo](https://raw.githubusercontent.com/MrDave1999/SimpleResults/master/SimpleResults-logo.png)](https://github.com/MrDave1999/SimpleResults)\n\nA simple library to implement the Result pattern for returning from services. It also provides a mechanism for translating the Result object to an [ActionResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult?view=aspnetcore-7.0) or [IResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iresult?view=aspnetcore-7.0).\n\n\u003e This library was inspired by [Ardalis.Result](https://github.com/ardalis/Result).\n\nSee the [API documentation](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.html) for more information on this project.\n\n## Index\n\n- [Operation Result Pattern](#operation-result-pattern)\n- [Why did I make this library?](#why-did-i-make-this-library)\n- [Why don't I use exceptions?](#why-dont-i-use-exceptions)\n  - [Differences between an expected and unexpected error](#differences-between-an-expected-and-unexpected-error)\n  - [Anecdote](#anecdote)\n  - [What happens if exceptions are used for all situations?](#what-happens-if-exceptions-are-used-for-all-situations)\n  - [Interesting resource about exceptions](#interesting-resource-about-exceptions)\n- [Installation](#installation)\n- [Overview](#overview)\n  - [Using the Result type](#using-the-result-type)\n  - [Using the ListedResult type](#using-the-listedresult-type)\n  - [Using the PagedResult type](#using-the-pagedresult-type)\n  - [Creating a resource with Result type](#creating-a-resource-with-resultt-type)\n  - [Designing errors and success messages](#designing-errors-and-success-messages)\n  - [Integration with ASP.NET Core](#integration-with-aspnet-core)\n    - [Using TranslateResultToActionResult as an action filter](#using-translateresulttoactionresult-as-an-action-filter)\n    - [Add action filter as global](#add-action-filter-as-global)\n    - [Support for Minimal APIs](#support-for-minimal-apis)\n    - [Validating with the ModelState property](#validating-with-the-modelstate-property)\n  - [Translate Result object to HTTP status code](#translate-result-object-to-http-status-code)\n  - [Integration with Fluent Validation](#integration-with-fluent-validation)\n- [Samples](#samples)\n- [Language settings](#language-settings)\n- [Contribution](#contribution)\n\n## Operation Result Pattern\n\nThe purpose of the Result design pattern is to give an operation (a method) the possibility to return a complex result (an object), allowing the consumer to:\n- Access the result of an operation; in case there is one.\n- Access the success indicator of an operation.\n- Access the failure indicator of an operation.\n- Access the value (data) of the result if it exists.\n- Access the cause of the failure in case the operation was not successful.\n- Access an error or success message.\n- Access to a collection of error messages.\n\n## Why did I make this library?\n\n- I designed this library for use it in the [DentallApp](https://github.com/DentallApp/back-end) project and for other projects according to my needs.\n\n- I wanted to share my knowledge with the community. I love open source.\n\n- I do not want to throw [exceptions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/using-exceptions) for all situations.\n\n## Why don't I use exceptions?\n\nI usually throw exceptions when developing open source libraries to alert the developer immediately that an unexpected error has occurred and must be corrected. In this case, it makes sense to me to throw an exception because the developer can know exactly where the error originated (by looking at the stack trace). However, when I develop applications, I very rarely find a case for using exceptions.\n\nFor example, I could throw an exception when a normal user enters empty fields but this does not make sense to me, because it is an error caused by the end user (who manages the system from the user interface). So in this case throwing an exception is useless because:\n- Stack trace included in the exception object is of no use to anyone, neither the end user nor the developer. \n  This is not a bug that a developer should be concerned about.\n\n- Nobody cares where the error originated, whether it was in method X or Y, it doesn't matter.\n\n- It is not an unexpected error. An exception is thrown to indicate an unexpected error. Unexpected errors are those that are not expected to occur, and they are not recoverable.\n  - For example, if the database server is not online, it will produce an unexpected error in the application, so there is no way for the application to recover.\n\nAnd there are many more examples of errors caused by the end user: the email is duplicated or a password that does not comply with security policies, among others.\n\nI only throw exceptions for unexpected errors; otherwise I create **result objects** and use return statements in my methods to terminate execution immediately when an expected error occurs.\n\n### Differences between an expected and unexpected error\n\nIt is necessary to understand the differences between an expected and unexpected error in order to know when to throw exceptions. In fact, in practice, third-party dependencies are responsible for reporting unexpected errors, so the developer only has to worry about identifying the expected errors of his business application.\n\n- **Expected errors** are those that are expected to occur, and we tend to recover them. They are also known as recoverable errors.\n  - For example, empty fields or a duplicate email. These are errors that are expected to occur and are normal for them to happen.\n  - To handle these errors, it is useful to use the Result pattern.\n\n- **Unexpected errors** are those that are not expected to occur, and they are not recoverable. They are also known as non-recoverable errors.\n  - For example, a database that does not exist or an incorrectly typed connection string. These are errors that are not expected to occur and it is not normal for them to happen. They should never happen and should be corrected immediately. It is fatal.\n  - Exceptions were designed to represent unexpected errors.\n\n### Anecdote\n\u003e At work I had to implement a module to generate a report that performs a monthly comparison of income and expenses for a company, so it was necessary to create a function that is responsible for calculating the percentage of a balance per month:\n```cs\nPercentage.Calculate(double amount, double total);\n```\n\u003e The `total` parameter if it is zero, will cause a division by zero (undefined operation), however, this value was not provided by an **end user**, but by the **income and expense reporting module**, but since I did not implement this module correctly, I created a bug, so the algorithm was passing a zero value for a strange reason (I call this a logic error, caused by the developer). \n\n\u003e Since I didn't throw an exception in the `Percentage.Calculate` function, it took me a couple of minutes to find out where the error originated (I didn't know that the problem was a division by zero).\n\n\u003e Dividing a floating-point value by zero doesn't throw an exception; it result is not a number (NaN). \nThis was a surprise to me! I didn't know! I was expecting an exception but it was not the case.\n\n\u003e If I had thrown an exception, I would have found the error very quickly, just by looking at the stack trace. In this case, it is very useful the exception object, for me and other developers and yes, divide by zero is an **unexpected error**, an exception should be thrown.\n\n### What happens if exceptions are used for all situations?\n\n**There are some details to consider:**\n\n- New maintainers of your application will learn that it is okay to throw exceptions in all situations. This is bad for their learning, as they don't really understand what [exceptions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions) were designed for in C#.\n\n- You make your code confusing, since you don't follow the official definition of what an [exception](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions) is in C#.\n  - Yes, exceptions represent unexpected errors. This is the definition, changing it, only causes confusion.\n\n- You need to create custom classes that inherit from the Exception type, otherwise you end up using the Exception type in many places. This type does not express any information to the consumer (who calls the public API).\n\n- You need to document those methods that throw exceptions, otherwise the consumer will not know which exceptions to handle, and will end up reviewing the source code of the method (this is not good).\n\n- Performance. Yes, throwing exceptions is very expensive. Although in many applications there may not be any impact, it is not a justification for wasting resources unnecessarily. For more information, see these links: \n  - [Exceptions and Exception Handling](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions)\n  - [Thread contention while throwing and catching exceptions](https://github.com/dotnet/runtime/issues/97181)\n  - [Exceptions are extremely expensive](https://github.com/dotnet/aspnetcore/issues/46280?fbclid=IwAR25e2CFNrI0VhS_H8V4WzgmR_JkXrXTqVn0vpNUFnyCMa9LC9GtnfzMvRU#issuecomment-1527898867)\n\n- If your project is a web application, you will have to find a mechanism to translate the exception object to HTTP status code, so you will have to create base classes like InvalidDataException to catch it from a global exception handler. \n  - For example: `WrongEmailException` inherits from `InvalidDataException` and in turn, it inherits from `Exception`. \n    It is necessary to think of a hierarchy of types that use inheritance (this adds another complexity).\n\n### Interesting resource about exceptions\n\n- [Exceptions for flow control in C# by Vladimir Khorikov](https://enterprisecraftsmanship.com/posts/exceptions-for-flow-control)\n- [Exceptions and Result pattern by Ben Witt](https://medium.com/@wgyxxbf/result-pattern-a01729f42f8c)\n\n## Installation\n\nYou can run any of these commands from the terminal:\n```sh\ndotnet add package SimpleResults\ndotnet add package SimpleResults.AspNetCore\ndotnet add package SimpleResults.FluentValidation\n```\n[SimpleResults](https://www.nuget.org/packages/SimpleResults) package is the main library (the core). The other two packages complement the main library (they are like add-ons).\n\n## Overview\n\nYou must import the namespace types at the beginning of your class file:\n```cs\nusing SimpleResults;\n```\n\nThis library provides four main types:\n- `Result`\n- `Result\u003cTValue\u003e`\n- `ListedResult\u003cTValue\u003e`\n- `PagedResult\u003cTValue\u003e` and `PagedInfo`\n\nWith any of these types you can handle errors and at the same time generate errors with the `return` statement.\n\nThis approach provides a new way to generate an error using return statements without the need to throw exceptions.\n\nSee the [API documentation](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.html) for more information on these types.\n\n### Using the `Result` type\n\nYou can use the `Result` class when you do not want to return any value.\n\n**Example:**\n```cs\npublic class UserService\n{\n    private readonly List\u003cUser\u003e _users;\n    public UserService(List\u003cUser\u003e users) =\u003e _users = users;\n\n    public Result Update(string id, string name)\n    {\n        if (string.IsNullOrWhiteSpace(id))\n            return Result.Invalid(\"ID is required\");\n\n        if (string.IsNullOrWhiteSpace(name))\n            return Result.Invalid(\"Name is required\");\n\n        var user = _users.Find(u =\u003e u.Id == id);\n        if (user is null)\n            return Result.NotFound();\n\n        user.Name = name;\n        return Result.UpdatedResource();\n    }\n}\n```\n\nYou can use the `Result\u003cTValue\u003e` class when you want to return a value (such as a `User` object).\n\n**Example:**\n```cs\npublic class UserService\n{\n    private readonly List\u003cUser\u003e _users;\n    public UserService(List\u003cUser\u003e users) =\u003e _users = users;\n\n    public Result\u003cUser\u003e GetById(string id)\n    {\n        if(string.IsNullOrWhiteSpace(id))\n            return Result.Invalid(\"ID is required\");\n\n        var user = _users.Find(u =\u003e u.Id == id);\n        if(user is null)\n            return Result.NotFound();\n\n        return Result.Success(user, \"User found\");\n    }\n}\n```\n\n### Using the `ListedResult` type\n\nYou can use the `ListedResult\u003cTValue\u003e` class when you want to return a set of values (such as a collection of objects of type `User`).\n\n**Example:**\n```cs\npublic class UserService\n{\n    private readonly List\u003cUser\u003e _users;\n    public UserService(List\u003cUser\u003e users) =\u003e _users = users;\n\n    public ListedResult\u003cUser\u003e GetAll()\n    {\n        if(_users.Count == 0)\n            return Result.Failure(\"No user found\");\n\n        return Result.ObtainedResources(_users);\n    }\n}\n```\n\n### Using the `PagedResult` type\n\nYou can use the `PagedResult\u003cTValue\u003e` class when you want to include paged information and a data collection in the result.\n\n**Example:**\n```cs\npublic class UserService\n{\n    private readonly List\u003cUser\u003e _users;\n    public UserService(List\u003cUser\u003e users) =\u003e _users = users;\n\n    public PagedResult\u003cUser\u003e GetPagedList(int pageNumber, int pageSize)\n    {\n        if(pageNumber \u003c= 0)\n            return Result.Invalid(\"PageNumber must be greater than zero\");\n\n        int itemsToSkip = (pageNumber - 1) * pageSize;\n        var data = _users\n            .Skip(itemsToSkip)\n            .Take(pageSize);\n\n        if (data.Any())\n        {\n            var pagedInfo = new PagedInfo(pageNumber, pageSize, _users.Count);\n            return Result.Success(data, pagedInfo);\n        }\n\n        return Result.Failure(\"No results found\");\n    }\n}\n```\n### Creating a resource with `Result\u003cT\u003e` type\n\nYou can tell the method to return a successfully created resource as a result by using the `Result.CreatedResource` method.\nIn addition, you can use the `CreatedGuid` class to specify the ID assigned to the created resource.\n\n**Example:**\n```cs\npublic class UserService\n{\n    private readonly List\u003cUser\u003e _users;\n    public UserService(List\u003cUser\u003e users) =\u003e _users = users;\n\n    public Result\u003cCreatedGuid\u003e Create(string name)\n    {\n        if(string.IsNullOrWhiteSpace(name))\n            return Result.Invalid(\"Name is required\");\n\n        var guid = Guid.NewGuid();\n        _users.Add(new User { Id = guid.ToString(), Name = name });\n        return Result.CreatedResource(guid);\n    }\n}\n```\nYou can also use the `CreatedId` class when using an **integer** as identifier. \n\nAn example using [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/get-started/overview/first-app?tabs=netcore-cli):\n```cs\npublic class UserModel \n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n}\n\npublic class UserService\n{\n    private readonly DbContext _db;\n    public UserService(DbContext db) =\u003e _db = db;\n\n    public Result\u003cCreatedId\u003e Create(string name)\n    {\n        if(string.IsNullOrWhiteSpace(name))\n            return Result.Invalid(\"Name is required\");\n\n        var user = new UserModel { Name = name };\n        _db.Add(user);\n        _db.SaveChanges();\n        return Result.CreatedResource(user.Id);\n    }\n}\n```\n\n### Designing errors and success messages\n\nYou can create an object that represents an error or success message. The advantage is all the relevant information of an error or success is encapsulated within one object.\n\n**Example:**\n```cs\npublic readonly ref struct StartDateIsAfterEndDateError\n{\n    public string Message { get; }\n    public StartDateIsAfterEndDateError(DateTime startDate, DateTime endDate)\n    { \n        Message = string.Format(\n            \"The start date {0} is after the end date {1}\", \n            startDate.ToString(\"yyyy-MM-dd\"), \n            endDate.ToString(\"yyyy-MM-dd\"));\n    }\n}\n```\nThis approach allows you to change the format of the message without having to make changes elsewhere.\n\nAnd then you can use it in your service:\n```cs\npublic class UserService\n{\n    public Result\u003cList\u003cUser\u003e\u003e GetUsersByDateRange(DateTime startDate, DateTime endDate)\n    {\n        if(startDate \u003e endDate)\n            return Result.Invalid(new StartDateIsAfterEndDateError(startDate, endDate).Message);\n\n        // Do something..\n    }\n}\n```\n\n### Integration with ASP.NET Core\n\nYou can convert the Result object to a [Microsoft.AspNetCore.Mvc.ActionResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult-1?view=aspnetcore-7.0) using the [ToActionResult](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.ResultExtensions.ToActionResult.html) extension method.\n\nYou need to install the [SimpleResults.AspNetCore](https://www.nuget.org/packages/SimpleResults.AspNetCore) package to have access to the extension method. See the [ResultExtensions](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.ResultExtensions.html#methods) class to find all extension methods.\n\n**Example:**\n```cs\npublic class UserRequest \n{ \n    public string Name { get; init; }\n}\n\n[ApiController]\n[Route(\"[controller]\")]\npublic class UserController\n{\n    private readonly UserService _userService;\n    public UserController(UserService userService) =\u003e _userService = userService;\n\n    [HttpPost]\n    public ActionResult\u003cResult\u003cCreatedGuid\u003e\u003e Create([FromBody]UserRequest request)\n        =\u003e _userService.Create(request.Name).ToActionResult();\n\n    [HttpPut(\"{id}\")]\n    public ActionResult\u003cResult\u003e Update(string id, [FromBody]UserRequest request)\n        =\u003e _userService.Update(id, request.Name).ToActionResult();\n\n    [HttpGet(\"{id}\")]\n    public ActionResult\u003cResult\u003cUser\u003e\u003e Get(string id)\n        =\u003e _userService.GetById(id).ToActionResult();\n\n    [HttpGet(\"paged\")]\n    public ActionResult\u003cPagedResult\u003cUser\u003e\u003e GetPagedList([FromQuery]PagedRequest request)\n        =\u003e _userService\n        .GetPagedList(request.PageNumber, request.PageSize)\n        .ToActionResult();\n\n    [HttpGet]\n    public ActionResult\u003cListedResult\u003cUser\u003e\u003e Get()\n        =\u003e _userService.GetAll().ToActionResult();\n}\n```\nSee the [API documentation](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.ResultExtensions.html#methods) for a list of available extension methods.\n\n#### Using TranslateResultToActionResult as an action filter\n\nYou can also use the [TranslateResultToActionResult](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.TranslateResultToActionResultAttribute.html) filter to translate the Result object to [ActionResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult?view=aspnetcore-7.0). \n\n`TranslateResultToActionResultAttribute` class will internally call the `ToActionResult` method and perform the translation.\n\n**Example:**\n```cs\n[TranslateResultToActionResult]\n[ApiController]\n[Route(\"[controller]\")]\npublic class UserController\n{\n    private readonly UserService _userService;\n    public UserController(UserService userService) =\u003e _userService = userService;\n\n    [HttpGet(\"{id}\")]\n    public Result\u003cUser\u003e Get(string id) =\u003e _userService.GetById(id);\n}\n```\nThe return value of `Get` action is a `Result\u003cUser\u003e`. **After the action is executed**, the filter (i.e. `TranslateResultToActionResult`) will run and translate the `Result\u003cUser\u003e` to [ActionResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.actionresult?view=aspnetcore-7.0).\n\n[See the source code](https://github.com/MrDave1999/SimpleResults/blob/e0b4bf02c77c02862f0a95ded268ee05cbc6d033/src/AspNetCore/TranslateResultToActionResultAttribute.cs#L12), it is very simple.\n\n#### Add action filter as global\n\nIf you do not want to use the filter on each controller, you can add it globally for all controllers (see [sample](https://github.com/MrDave1999/SimpleResults/blob/e0b4bf02c77c02862f0a95ded268ee05cbc6d033/samples/SimpleResults.Example.AspNetCore/Program.cs#L10C1-L14C4)).\n```cs\nbuilder.Services.AddControllers(options =\u003e\n{\n    // Add filter for all controllers.\n    options.Filters.Add\u003cTranslateResultToActionResultAttribute\u003e();\n});\n```\nThis way you no longer need to add the `TranslateResultToActionResult` attribute on each controller or individual action.\n\n#### Support for Minimal APIs\n\nAs of version 2.3.0, a feature has been added to convert the Result object to an implementation of [Microsoft.AspNetCore.Http.IResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iresult?view=aspnetcore-7.0).\n\nYou only need to use the extension method called [ToHttpResult](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.ResultExtensions.ToHttpResult.html). See the [ResultExtensions](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.ResultExtensions.html#methods) class to find all extension methods.\n\n**Example:**\n```cs\npublic static class UserEndpoint\n{\n    public static void AddRoutes(this WebApplication app)\n    {\n        var userGroup = app\n            .MapGroup(\"/User\")\n            .WithTags(\"User\");\n\n        userGroup\n            .MapGet(\"/\", (UserService service) =\u003e service.GetAll().ToHttpResult())\n            .Produces\u003cListedResult\u003cUser\u003e\u003e();\n\n        userGroup\n            .MapGet(\"/{id}\", (string id, UserService service) =\u003e service.GetById(id).ToHttpResult())\n            .Produces\u003cResult\u003cUser\u003e\u003e();\n\n        userGroup.MapPost(\"/\", ([FromBody]UserRequest request, UserService service) =\u003e\n        {\n            return service.Create(request.Name).ToHttpResult();\n        })\n        .Produces\u003cResult\u003cCreatedGuid\u003e\u003e();\n    }\n}\n```\nYou can also use the [TranslateResultToHttpResult](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.TranslateResultToHttpResultFilter.html) filter to translate the Result object to an implementation of [IResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iresult?view=aspnetcore-7.0). \n\n`TranslateResultToHttpResultFilter` class will internally call the `ToHttpResult` method and perform the translation.\n\n**Example:**\n```cs\npublic static class UserEndpoint\n{\n    public static void AddRoutes(this WebApplication app)\n    {\n        var userGroup = app\n            .MapGroup(\"/User\")\n            .WithTags(\"User\")\n            .AddEndpointFilter\u003cTranslateResultToHttpResultFilter\u003e();\n\n        userGroup\n            .MapGet(\"/{id}\", (string id, UserService service) =\u003e service.GetById(id))\n            .Produces\u003cResult\u003cUser\u003e\u003e();\n    }\n}\n```\nThe endpoint handler returns a `Result\u003cUser\u003e`. After the handler is executed, the filter (i.e. `TranslateResultToHttpResult`) will run and translate the `Result\u003cUser\u003e` to an implementation of [IResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.iresult?view=aspnetcore-7.0).\n\n[See the source code](https://github.com/MrDave1999/SimpleResults/blob/25387945f57241dadad3baf52886ab59949c98fa/src/AspNetCore/TranslateResultToHttpResultFilter.cs#L26), it is very simple.\n\n#### Validating with the ModelState property\n\n[SimpleResults.AspNetCore](https://www.nuget.org/packages/SimpleResults.AspNetCore) package also adds extension methods for the [ModelStateDictionary](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.modelstatedictionary?view=aspnetcore-7.0) type.\n\nSee the [ModelStateDictionaryExtensions](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.SRModelStateDictionaryExtensions.html) class to find all extension methods.\n\nThe `ModelStateDictionary` type contains the validation errors that are displayed to the client. Somehow these errors must be included in an instance of type [Result](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.Result.html).\n\n##### Manual validation\n\nManual validation is performed directly in the controller action.\n\n**Example:**\n```cs\n[TranslateResultToActionResult]\n[Route(\"[controller]\")]\npublic class OrderController : ControllerBase\n{\n    private readonly OrderService _orderService;\n    public OrderController(OrderService orderService) =\u003e _orderService = orderService;\n\n    [HttpPost]\n    public Result\u003cCreatedGuid\u003e Create([FromBody]CreateOrderRequest request)\n    {\n        if (ModelState.IsFailed())\n            return ModelState.Invalid();\n\n        return _orderService.Create(request);\n    }\n}\n```\nIn this example a manual validation is performed with `ModelState.IsFailed()` (an extension method), so if the model state is failed, an invalid result type is returned. What `ModelState.Invalid()` does is to convert the instance of `ModelStateDictionary` to an instance of type [Result](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.Result.html), so in the result object the validation errors will be added.\n\nAfter the controller action is executed, the `TranslateResultToActionResult` filter will translate the Result object to an instance of type `ActionResult`.\n\nYou can also return the ActionResult directly in the controller action instead of using the action filter.\n\n**Example:**\n```cs\n[Route(\"[controller]\")]\npublic class OrderController : ControllerBase\n{\n    private readonly OrderService _orderService;\n    public OrderController(OrderService orderService) =\u003e _orderService = orderService;\n\n    [HttpPost]\n    public ActionResult\u003cResult\u003cCreatedGuid\u003e\u003e Create([FromBody]CreateOrderRequest request)\n    {\n        if (ModelState.IsFailed())\n            return ModelState.BadRequest();\n\n        return _orderService\n            .Create(request)\n            .ToActionResult();\n    }\n}\n```\n`ModelState.BadRequest()` has a behavior similar to `ModelState.Invalid()`, the difference is that the first one returns an instance of type [BadRequestObjectResult](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.badrequestobjectresult?view=aspnetcore-7.0) in which contains the instance of type [Result](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.Result.html).\n\n##### Automatic validation\n\nYou need to make a setting in the `Program.cs` to convert the instance of type `ModelStateDictionary` to an instance of type [Result](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.Result.html) when the model validation fails.\n\n**Example:**\n```cs\nbuilder.Services.AddControllers()\n.ConfigureApiBehaviorOptions(options =\u003e\n{\n    options.InvalidModelStateResponseFactory = (ActionContext context) =\u003e context.ModelState.BadRequest();\n});\n```\nThis delegate is only invoked on actions annotated with `ApiControllerAttribute` and will execute the `context.ModelState.BadRequest()` call when a model validation failure occurs. If a validation failure occurs in the model, the controller action will never be executed.\n\nYour controller no longer needs to perform manual validation, for example:\n```cs\n[ApiController]\n[TranslateResultToActionResult]\n[Route(\"[controller]\")]\npublic class OrderController : ControllerBase\n{\n    private readonly OrderService _orderService;\n    public OrderController(OrderService orderService) =\u003e _orderService = orderService;\n\n    [HttpPost]\n    public Result\u003cCreatedGuid\u003e Create([FromBody]CreateOrderRequest request)\n        =\u003e _orderService.Create(request);\n}\n```\nThe [ApiController](https://learn.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-7.0#automatic-http-400-responses) is necessary because it allows to activate the [ModelStateInvalid](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.infrastructure.modelstateinvalidfilter?view=aspnetcore-7.0) filter to perform the model validation before executing the controller action.\n\n### Translate Result object to HTTP status code\n\n[SimpleResults.AspNetCore](https://www.nuget.org/packages/SimpleResults.AspNetCore) package is responsible for translating the status of a Result object into an HTTP status code.\n\nThe following table is used as a reference to know which type of result corresponds to an HTTP status code:\n\n| Result type             | HTTP status code            |\n|-------------------------|-----------------------------|\n| Result.Success          | 200 - Ok                    |\n| Result.CreatedResource  | 201 - Created               |\n| Result.UpdatedResource  | 200 - Ok                    |\n| Result.DeletedResource  | 200 - Ok                    |\n| Result.ObtainedResource | 200 - Ok                    |\n| Result.ObtainedResources| 200 - Ok                    |\n| Result.File             | 200 - Ok                    |\n| Result.Invalid          | 400 - Bad Request           |\n| Result.NotFound         | 404 - Not Found             |\n| Result.Unauthorized     | 401 - Unauthorized          |\n| Result.Conflict         | 409 - Conflict              |\n| Result.Failure          | 422 - Unprocessable Entity  |\n| Result.CriticalError    | 500 - Internal Server Error |\n| Result.Forbidden        | 403 - Forbidden             |\n\n### Integration with Fluent Validation\n\nYou need to install the [SimpleResults.FluentValidation](https://www.nuget.org/packages/SimpleResults.FluentValidation) package to have access to the extension methods.\n\n**Example:**\n```cs\npublic class UserService\n{\n    public Result Create(CreateUserRequest request)\n    {\n        ValidationResult result = new CreateUserValidator().Validate(request);\n        if(result.IsFailed())\n            return result.Invalid();\n\n        // Some code..\n    }\n}\n```\nSee the [API documentation](https://mrdave1999.github.io/SimpleResults/api/SimpleResults.SRFluentValidationResultExtensions.html#methods) for a list of available extension methods.\n\n## Samples\n\nYou can find a complete and functional example in these projects:\n- [SimpleResults.Example](https://github.com/MrDave1999/SimpleResults/tree/master/samples/SimpleResults.Example)\n- [SimpleResults.Example.NativeAOT](https://github.com/MrDave1999/SimpleResults/tree/master/samples/SimpleResults.Example.NativeAOT)\n- [SimpleResults.Example.AspNetCore](https://github.com/MrDave1999/SimpleResults/tree/master/samples/SimpleResults.Example.AspNetCore)\n- [SimpleResults.Example.Web.Tests](https://github.com/MrDave1999/SimpleResults/tree/master/samples/SimpleResults.Example.Web.Tests)\n- [SimpleResults.Example.FluentValidation](https://github.com/MrDave1999/SimpleResults/tree/master/samples/SimpleResults.Example/FluentValidation)\n- [Double-V-Partners](https://github.com/MrDave1999/double-v-partners/tree/master/backend/src/Features/Users)\n- [Orders.Sample](https://github.com/MrDave1999/orders-sample/tree/master/src/Application/Features/Orders)\n\n## Language settings\n\n`SimpleResults` has resources that contain response messages. [See the source code](https://github.com/MrDave1999/SimpleResults/tree/23f5fdb4af10195b182ace9ff78fb4fbf4fa9768/src/Core/Resources).\n\nAt the moment there are only two resources:\n- `ResponseMessages.resx`. It contains messages in English.\n- `ResponseMessages.es.resx`. It contains messages in Spanish.\n\nThe loading of these resources depends on your locale settings. \nFor example, if your computer has the language as Spanish, the resource that will be loaded will be `ResponseMessages.es.resx`.\nLikewise, if it is set to English, the default resource will be loaded: `ResponseMessages.resx`.\n\nAnd if the configuration is set to French, the resource that will be loaded will be the default one (i.e. `ResponseMessages.resx`), since there is no resource called `ResponseMessages.fr.resx`.\n\nYou can explicitly specify the culture to ensure that a resource is loaded regardless of your computer's language settings:\n```cs\nThread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(\"es\");\n```\nIn ASP.NET Core applications, the [UseRequestLocalization](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.applicationbuilderextensions.userequestlocalization?view=aspnetcore-7.0#microsoft-aspnetcore-builder-applicationbuilderextensions-userequestlocalization(microsoft-aspnetcore-builder-iapplicationbuilder-system-string())) extension method is used:\n```cs\napp.UseRequestLocalization(\"es\");\n```\n\n## Contribution\n\nAny contribution is welcome! Remember that you can contribute not only in the code, but also in the documentation or even improve the tests.\n\nFollow the steps below:\n\n- Fork it\n- Create your feature branch (git checkout -b my-new-feature)\n- Commit your changes (git commit -am 'Added some feature')\n- Push to the branch (git push origin my-new-feature)\n- Create new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrdave1999%2Fsimpleresults","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrdave1999%2Fsimpleresults","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrdave1999%2Fsimpleresults/lists"}