Cayd.AspNetCore.ExecutionResult 1.0.0

dotnet add package Cayd.AspNetCore.ExecutionResult --version 1.0.0
                    
NuGet\Install-Package Cayd.AspNetCore.ExecutionResult -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cayd.AspNetCore.ExecutionResult" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cayd.AspNetCore.ExecutionResult" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Cayd.AspNetCore.ExecutionResult" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cayd.AspNetCore.ExecutionResult --version 1.0.0
                    
#r "nuget: Cayd.AspNetCore.ExecutionResult, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cayd.AspNetCore.ExecutionResult@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cayd.AspNetCore.ExecutionResult&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Cayd.AspNetCore.ExecutionResult&version=1.0.0
                    
Install as a Cake Tool

About

This is a result pattern library for ASP.NET Core that handles success and error flows in services and CQRS-based architectures. It abstracts HTTP status codes into result and error classes such as ExecOk<TValue>, ExecNoContent<TValue>, ExecBadRequest, ExecInternalServerError etc. and supports implicit default success (200 OK) and default error (400 Bad Request) handling.

How to Use

After installing the package, you can use ExecResult<TValue> for returning types of your services or CQRS handlers.

  • Implicit Success and Implicit Error Handling in Services:
using Cayd.AspNetCore.ExecutionResult;

public class MyService : IMyService
{
    // ...

    public ExecResult<User> GetUser(Guid id)
    {
        var user = _dbContext.Users.Find(id);
        if (user == null)
            return ExecErrorDetail("Message here if needed", "Message code here if needed (can be used for translation keys for instance)"); // -> This implicit usage utilizes ExecBadRequest, which returns 'error' with the HTTP status code of 400.

        return user; // -> This implicit usage utilizes ExecOk, which returns 'success' with the HTTP status code of 200.
    }
}
  • Explicit Success and Explicit Error Handling in Services:
using Cayd.AspNetCore.ExecutionResult;
using Cayd.AspNetCore.ExecutionResult.ClientError;
using Cayd.AspNetCore.ExecutionResult.Success;

public class MyService : IMyService
{
    // ...

    public ExecResult<MyClass> GetData(string? search)
    {
        if (CheckIfAuthorized())
            return ExecUnauthorized("Message here if needed", "Message code here if needed (can be used for translation keys for instance)");

        // Explicit usage of Bad Request. 'ExecErrorDetail' could be used directly as well.
        if (search == null)
            return ExecBadRequest("Message here if needed", "Message code here if needed (can be used for translation keys for instance)");

        var data = _dbContext.Data.Where(x => x.Property1 == search).ToList();
        if (data.Count == 0)
            return ExecNoContent();

        return data; // -> This implicit usage utilizes ExecOk, which returns 'success' with the HTTP status code of 200.
    }
}
  • Handling The Result:
// By using the Match method's overloads, you can handle success, redirection or error of the execution.

var result = _myService.GetData();
result.Match(
    (code, value, metadata) => { /* Success */ },
    (code, errors, metadata) => { /* Error */ }
);

var result = _myService.GetData();
result.Match(
    (code, metadata) => { /* Redirection */ },
    (code, errors, metadata) => { /* Error */ }
);

var result = _myService.GetData();
result.Match(
    (code, value, metadata) => { /* Success */ },
    (code, metadata) => { /* Redirection */ },
    (code, errors, metadata) => { /* Error */ }
);

// Since the returned result also includes the HTTP code, the response can be returned in action methods by using the 'ObjectResult' class.

For CQRS handlers utilizing the MediatR library:

  • Request:
public class GetDataRequest : IRequest<ExecResult<GetDataResponse>>
{
    // ...
}
  • Handler:
public class GetDataHandler : IRequestHandler<GetDataRequest, ExecResult<GetDataResponse>>
{
    // ...
}
  • Response:
public class GetDataResponse
{
    // ...
}

Result Classes

The library includes all result classes representing 2xx, 3xx, 4xx and 5xx HTTP status codes. These classes start with the Exec prefix. For instance, the class representing 204 No Content is called ExecNoContent and is under the Cayd.AspNetCore.ExecutionResult.Success namespace.

Type Namespace
Success (2xx) Cayd.AspNetCore.ExecutionResult.Success
Redirection (3xx) Cayd.AspNetCore.ExecutionResult.Redirection
Client error (4xx) Cayd.AspNetCore.ExecutionResult.ClientError
Server error (5xx) Cayd.AspNetCore.ExecutionResult.ServerError

Extras

For CQRS handlers utilizing the MediatR library as well as FluentValidation, the validation pipeline can be set up as follows to use ExecBadRequest automatically when validations fail:

  • Validation Behavior:
using Cayd.AspNetCore.ExecutionResult;
using Cayd.AspNetCore.ExecutionResult.ClientError;
using FluentValidation;
using MediatR;

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        if (_validators.Any())
        {
            foreach (var validator in _validators)
            {
                if (validator != null)
                {
                    var validationResult = await validator.ValidateAsync(request, cancellationToken);
                    if (validationResult.Errors.Count > 0)
                    {
                        var errorDetails = validationResult.Errors
                            .Select(e => new ExecErrorDetail(e.ErrorMessage, e.ErrorCode))
                            .ToList();

                        return (dynamic)new ExecBadRequest(errorDetails);
                    }
                }
            }
        }

        return await next();
    }
}
  • Example Validation in CQRS:
public class GetDataValidation : AbstractValidator<GetDataRequest>
{
    public LoginValidation()
    {
        RuleFor(r => r.Property1)
            .NotEmpty()
                .WithMessage("Error message here")
                .WithErrorCode("Error message code here (can be used for translation keys for instance)");
    }
}
  • Registering The Pipeline:
builder.Services.AddMediatR(config =>
{
    // ...
    config.AddOpenBehavior(typeof(ValidationBehavior<,>));
});
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net5.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 144 6/2/2025

First release