question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Issue with base response type

See original GitHub issue

I try to implement validation behavior in asp.net core 2.1 application. My controller:

[HttpPost]
public async Task<CommandResponse<Application>> Post([FromBody] CreateApplicationCommand command)
{
    var response = await _mediator.Send(command);
    return response;
}

ValidationBehavior:

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

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

    public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        var failures = _validators
            .Select(v => v.Validate(request))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        return failures.Any()
            ? Errors(failures)
            : next();
    }

    private static Task<TResponse> Errors(IEnumerable<ValidationFailure> failures)
    {
        var response = new CommandResponse();

        foreach (var failure in failures)
        {
            response.AddError(failure.ErrorMessage);
        }

        return Task.FromResult(response as TResponse);
    }
}

Response:

public class CommandResponse
{
    private readonly IList<string> _errorMessages = new List<string>();

    public void AddError(string errorMessage)
    {
        _errorMessages.Add(errorMessage);
    }

    public bool IsSucceed => !_errorMessages.Any();

    public IReadOnlyCollection<string> Errors => new ReadOnlyCollection<string>(_errorMessages);
}

public class CommandResponse<TModel> : CommandResponse where TModel : class
{
    public CommandResponse(TModel model)
    {
        Result = model;
    }

    public TModel Result { get; }
}

Container registration (Asp.Net Core DI with Scrutor):

public static void AddMediator(this IServiceCollection services)
{
    services.AddScoped<ServiceFactory>(p => p.GetService);
    services.AddScoped<IMediator, Mediator>();

    services.Scan(scan => scan
        .FromAssemblies(Assembly.GetExecutingAssembly())
        .AddClasses(classes => classes.AssignableTo(typeof(IRequestHandler<,>)))
            .AsImplementedInterfaces()
            .WithScopedLifetime()
        .AddClasses(classes => classes.AssignableTo(typeof(IValidator<>)))
            .AsImplementedInterfaces()
            .WithScopedLifetime());

    services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
}

If CreateApplicationCommand is valid everything works fine. When validation failure occures I expect to receive an instance of CommandResponse class with error messages. However response in controller in this case is null. What I am doing wrong?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:11 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
vertonghenbcommented, Jan 16, 2019

@MaciejWierzchowski Fixed using an Activator

        private static Task<TResponse> Errors(IEnumerable<ValidationFailure> failures)
        {
            var response = Activator.CreateInstance<TResponse>();
            foreach (var failure in failures)
            {
                response.AddError(failure.ErrorMessage);
            }

            return Task.FromResult(response);
        }

Caveat : Your TResponse should have a default constructor

1reaction
lilasquaredcommented, Feb 25, 2020

Yep, basically what @joaomatossilva said. A base class of that can be Success or Failure, and the Failure result has properties for validation failure messages or any other metadata needed. All handled by a pipeline behavior that injects IValidators similar to what you have above. All request responses are wrapped in the particular Result response type and we have custom interfaces to help simplify this as well when creating commands, queries and handlers.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Type 'BaseResponse<IavailableParameters[]>' is missing ...
It is an object with properties isSuccessful , error , and results . The property results is an array IavailableParameters[] .
Read more >
responseType setting base on have responsed · Issue #1500
I have the same issue. Example: axios.get('/file', { responseType ...
Read more >
Response: type property - Web APIs - MDN Web Docs
The type read-only property of the Response interface contains the type of the response. It can be one of the following: basic :...
Read more >
Help creating a base response class to use in a Web API
So I recently picked up ASP.NET project for the first time and have been working on a Web API. I am not used...
Read more >
Handle errors in ASP.NET Core web APIs
Learn about error handling with ASP.NET Core web APIs.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found