Is it possible to pass data from a filter to its endpoint without tampering the original argument?

Viewed 44

A contrived example:

  • Endpoint "/math/{x:int}" expects a positive integer x and returns 2x.
  • Filter preprocesses argument with Math.Abs() to produce a positive integer for the endpoint.
  • Filter also post processes 2x by adding 1 to it. So the final output is an odd number 2x+1.

First Attempt (Tampering Argument) --> Bad!

app.MapGet("/math/{x:int}", (int x) =>
{
    return ValueTask.FromResult(2 * x);
})
.AddEndpointFilter(async (ctx, next) =>
{
    var arg = ctx.GetArgument<int>(0);
    arg = Math.Abs(arg);

    ctx.Arguments[0] = arg;

    var output = await next(ctx);

    return (int)output! + 1;

})
;

Second Attempt (Without Tampering Argument) --> Good?

I add the sterilized arg to EndpointFilterInvocationContext.Arguments as follows:

arg = Math.Abs(arg);

ctx.Arguments.Add(arg);

But now the problem, is it possible to retrieve it from the endpoint?

app.MapGet("/math/{x:int}", (int x) =>
{
    // I need to retrieve the data from filter here, but how?
    // The data is at the last entry in Arguments.
    // return oddnumber;
})
.AddEndpointFilter(async (ctx, next) =>
{
    var arg = ctx.GetArgument<int>(0);
    arg = Math.Abs(arg);

    ctx.Arguments.Add(arg);

    var output = await next(ctx);

    return (int)output! + 1;

})
;

Real Scenario

In my real scenario, I want to make the endpoint only handle database models and filters do preprocessing (converting view model to models) and post processing (converting models to view models).

app.MapGet("/User", ([FromBody]UserCreateDto dto) =>
{
    // How to retrieve User passed from filter here?
    // return user;
})
.AddEndpointFilter(async (ctx, next) =>
{
    var userCreateDto = ctx.GetArgument<UserCreateDto>(0);

    var user = Mapper.FromCreateToUser(userCreateDto);

    ctx.Arguments.Add(user);

    var result = await next(ctx);

    var userDisplayDto = Mapper.FromUserToDisplay((result as User)!);
    return userCreateDto;
})
;

app.Run();



class User
{
    public int Id { get; set; }
    public string Name { get; set; } = default!;
    public int Age { get; set; }
}

class UserCreateDto
{
    public string Name { get; set; } = default!;
    public int Age { get; set; }
}

class UserDisplayDto
{
    public int Id { get; set; }
    public string Name { get; set; } = default!;
}

static class Mapper
{
    public static User FromCreateToUser(UserCreateDto dto) =>
        new User { Name = dto.Name.ToLower(), Age = dto.Age };

    public static UserDisplayDto FromUserToDisplay(User user) =>
         new UserDisplayDto { Id = user.Id, Name = user.Name };
}
0 Answers
Related