This library provides a straightforward implementation of the Result Pattern for .NET applications, enabling developers to encapsulate operation outcomes with clarity and consistency. With this pattern, you can gracefully handle success and failure cases, reducing the need for exceptions and enhancing the maintainability of your code.
$ dotnet add package DeepCode.Returnor nuget using Nuget package manager GUI by searching DeepCode.Return
dotnet add package DeepCode.Return --version 1.0.1
TResult is type of the return
namespace Invoicing.Application.Orders.Commands.CreateOrderCommand;
internal class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, Return<Order>>
{
public async Task<Return<Order>> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
Order order;
//order creation logic
return order;
}
}
for non async methods
public Return<Order> CreateOrder(CreateOrder request, CancellationToken cancellationToken)
{
Order order;
//order creation logic
return order;
}
public Return SendEmail()
{
return Return.Success();
}
public void Main()
{
Return<Order> orderCreateResult = CreateOrder(request, cancellationToken);
if(orderCreateResult.IsFailure)
{
// Failure code goes here
}
Order order = orderCreateResult.Value;
// success path here
}
Handle Conflicts,
public Return<Order> 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<Order>.Failure(Conflict.Create("Not enough stockes in inventory."));
}
}
// all these take one string message arg and optinal description arg
return Fault.NotFound();
return Fault.InternalError();
return Fault.ReturnError();
Return<Order> result = GetOrder(id);
if(result.IsFailure)
{
if(result.IsErrorTypeOf<NotFound>())
{
// Not found logic goes here.
}
if(result.ErrorsContain<NotFound>())
{
// if error list contains Not found logic goes here.
}
if(result.Error.Is<Unauthorized>())
{
// Unauthorize logic goes here.
}
if(result.Errors.ContainsErrorType<NotFound>())
{
// Not found logic goes here.
}
}
public Return Main()
{
Return<Order> orderCreateResult = CreateOrder(100);
if (orderCreateResult.IsFailure)
{
// First error or only error of the list.
Fault error = orderCreateResult.Error;
// Read all errors returned.
IReadOnlyList<Fault> errors = orderCreateResult.Errors;
// Error logic goes here
}
if (orderCreateResult.IsFailure)
{
// Pass errors to call stack
return orderCreateResult.Errors.ToList();
}
}
Need to be inherited from Fault record
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.");
}
Match method can be used to trigger actions when some return is success or failure.
Trigger actions with no return type.
Return<Order> 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
Return<Order> orderCreateResult = Return<Order>.Success(new Order());
Response<Order> response = orderCreateResult.Match<Response<Order>>(
onSuccess:(order) => new Response<Order>() { Data = order },
onFailure:(errors) => new Response<Order>() { Error = new { Error = errors.ToList() } });
//gets first error of the list as the arg when failure.
Response<Order> response = orderCreateResult.MatchFirst<Response<Order>>(
onSuccess:(order) => new Response<Order>() { Data = order },
onFailure:(error) => new Response<Order>() { Error = new { Error = errors.ToList() } });
Response<Order> response = orderCreateResult.MatchAsync<Response<Order>>(
onSuccess: async (order) => {},
onFailure: async (errors) => {});
//gets first error of the list as the arg when failure.
Response<Order> response = orderCreateResult.MatchFirstAsync<Response<Order>>(
onSuccess: async (order) => {},
onFailure: async (error) => {});