https://github.com/deshansl/returns
Simplify error handling and improve code readability with the Result Pattern
https://github.com/deshansl/returns
csharp dotnet dotnet-core dotnetnugetutil nuget nuget-package result result-pattern resultpattern return returns simple
Last synced: 4 months ago
JSON representation
Simplify error handling and improve code readability with the Result Pattern
- Host: GitHub
- URL: https://github.com/deshansl/returns
- Owner: DeshanSL
- Created: 2024-06-19T00:21:59.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2024-10-02T02:31:28.000Z (over 1 year ago)
- Last Synced: 2025-09-30T01:51:29.504Z (5 months ago)
- Topics: csharp, dotnet, dotnet-core, dotnetnugetutil, nuget, nuget-package, result, result-pattern, resultpattern, return, returns, simple
- Language: C#
- Homepage:
- Size: 54.7 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
### Simplify error handling and improve code readability with the Result Pattern
## Get Started
#### Install nuget package using .Net CLI
or nuget using Nuget package manager GUI by searching DeepCode.Return
```bash
dotnet add package DeepCode.Return --version 1.0.1
```
## How To Use
#### Define method return type with Return struct with TResult type parameter
TResult is type of the return
```csharp
namespace Invoicing.Application.Orders.Commands.CreateOrderCommand;
internal class CreateOrderCommandHandler : IRequestHandler>
{
public async Task> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
Order order;
//order creation logic
return order;
}
}
```
for non async methods
```csharp
public Return CreateOrder(CreateOrder request, CancellationToken cancellationToken)
{
Order order;
//order creation logic
return order;
}
```
#### Return struct can be used when there's no return value but to notify if function was success or not
```csharp
public Return SendEmail()
{
return Return.Success();
}
```
### How to extract if state is success
```csharp
Return orderCreateResult = CreateOrder(request, cancellationToken);
if(orderCreateResult.IsFailure)
{
// Failure code goes here
}
Order order = orderCreateResult.Value;
// success path here
```
### Error Handling
#### Notify caller error with in built error types
Handle Conflicts,
```csharp
public Return CreateOrder(double totalAmount)
{
// logic to apply the discount if total amount is > 100
// Inventory says out of stock due to high demand
if (!inventoryManagement.AreEnoughStokesAvailable())
{
return Fault.Conflict("Not enough stockes in inventory.");
//or
return Return.Failure(Conflict.Create("Not enough stockes in inventory."));
}
}
```
#### Other in-built error type available
```csharp
// all these take one string message arg and optinal description arg
return Fault.NotFound();
return Fault.InternalError();
return Fault.ReturnError();
```
#### Type check errors for decision making
```csharp
Return result = GetOrder(id);
if(result.IsFailure)
{
if(result.IsErrorTypeOf())
{
// Not found logic goes here.
}
if(result.ErrorsContain())
{
// if error list contains Not found logic goes here.
}
if(result.Error.Is())
{
// Unauthorize logic goes here.
}
if(result.Errors.ContainsErrorType())
{
// Not found logic goes here.
}
if(result.Errors.ContainsErrorType())
{
// if custom error type
}
}
```
#### Handle Errors from caller method
```csharp
Return orderCreateResult = CreateOrder(100);
if (orderCreateResult.IsFailure)
{
// First error or only error of the list.
Fault error = orderCreateResult.Error;
// Read all errors returned.
IReadOnlyList errors = orderCreateResult.Errors;
// Error logic goes here
}
if (orderCreateResult.IsFailure)
{
// Pass errors to call stack
return orderCreateResult.Errors.ToList();
}
```
#### Define custom error types
Need to be inherited from Fault record
```csharp
public record OrderCreationErrors : Fault
{
public OrderCreationErrors(string message, string? description = null) : base(message, description) { }
public static OrderCreationErrors InvalidCustomerIdForOrderCreation =>
new OrderCreationErrors("Could not find matching customer to the given customerId.");
public static OrderCreationErrors CustomerBlacklisted =>
new OrderCreationErrors("Customer with the given customerId has been blacklisted.");
}
```
#### Using Match
Match method can be used to trigger actions when some return is success or failure.
Trigger actions with no return type.
```csharp
Return orderCreateResult = CreateOrder(100);
orderCreateResult.Match(
onSuccess: (value) => _logger.Info($"{value.Id} Order created successfully."),
onFailure: (errors) => _logger.Error("Failed to create order.")
);
//Match first error of errors if failure.
orderCreateResult.MatchFirst(
onSuccess: (value) => _logger.Info($"{value.Id} Order created successfully."),
onFailure: (error) => _logger.Error("Failed to create order.")
);
orderCreateResult.MatchAsync(
onSuccess: async (value) =>
{
// Simulating async process
await Task.Delay(100);
_logger.Info($"{value.Id} Order created successfully.");
},
onFailure: async (errors) =>
{
// Simulating async process
await Task.Delay(100);
_logger.Error("Failed to create order.");
});
```
Match using TNextValue type, has return after match
```csharp
Return orderCreateResult = Return.Success(new Order());
Response response = orderCreateResult.Match>(
onSuccess:(order) => new Response() { Data = order },
onFailure:(errors) => new Response() { Error = new { Error = errors.ToList() } });
//gets first error of the list as the arg when failure.
Response response = orderCreateResult.MatchFirst>(
onSuccess:(order) => new Response() { Data = order },
onFailure:(error) => new Response() { Error = new { Error = errors.ToList() } });
Response response = orderCreateResult.MatchAsync>(
onSuccess: async (order) => {},
onFailure: async (errors) => {});
//gets first error of the list as the arg when failure.
Response response = orderCreateResult.MatchFirstAsync>(
onSuccess: async (order) => {},
onFailure: async (error) => {});
```