Reading HttpContext.Request as object?

旧巷老猫 提交于 2021-02-11 14:30:28

问题


My base Request class looks like this:

public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}

public abstract class QueryBase<T> : UserContext, IRequest<T> // IRequest is MediatR interface
{
}

public abstract class UserContext
{
    public string ApplicationUserId { get; set; } // and other properties
}

I want to write a middleware to my .NET Core 3.1 WebApi that will grab JWT from request header amd read ApplicationUserId from it. I started to code something:

public class UserInformation
{
    private readonly RequestDelegate next;

    public UserInformation(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var jwt = context.Request.Headers["Authorization"];
        // read jwt here
        var userContext = (UserContext)context.Request.Body; // i know it wont work
        userContext.ApplicationUserId = //whats next? Any ideas?

        await this.next(context);
    }
}

But to be honest i have no idea how to start so here are my questions:

As you can see, every request will be packed with my UserContext class and so on. How to cast HttpContext.Request.Body to my request object and attach ApplicationUserId to it? Is it possible? I want to acces to user credentials from my JWT from headers and i want to have that information in every request in my API (pass it to controller, then to command etc).

If getting this information from middleware is not the best practice, what is?

EDIT: Mcontroller that using MediatR:

// base controller:
[ApiController]
[Route("[controller]")]
public abstract class BaseController : ControllerBase
{
    private IMediator mediator;

    protected IMediator Mediator => this.mediator ?? (this.mediator = HttpContext.RequestServices.GetService<IMediator>());
}

// action in ProjectControlle

[HttpGet]
[Authorize]
public async Task<ActionResult<ProjectsListModel>> GetAllProjects()
{
    return Ok(await base.Mediator.Send(new GetAllProjectsQuery()));
}

// query:
public class GetAllProjectsQuery : QueryBase<ProjectsListModel>
{
}

// handler:

public class GetAllProjectsQueryHandler : IRequestHandler<GetAllProjectsQuery, ProjectsListModel>
{
    private readonly IProjectRepository projectRepository;

    public GetAllProjectsQueryHandler(IProjectRepository projectRepository)
    {
        this.projectRepository = projectRepository;
    }

    public async Task<ProjectsListModel> Handle(GetAllProjectsQuery request, CancellationToken cancellationToken)
    {
        var projects = await this.projectRepository.GetAllProjectsWithTasksAsync();

        return new ProjectsListModel
        {
            List = projects
        };
    }
}


回答1:


You might not need a middleware, but need a model binder:

See: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1

Also see: https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1

public class UserContextModelBinder : IModelBinder
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IModelBinder _defaultModelBinder;

    public UserContextModelBinder(
        IHttpContextAccessor httpContextAccessor,
        IOptions<MvcOptions> mvcOptions,
        IHttpRequestStreamReaderFactory streamReaderFactory)
    {
        _httpContextAccessor = httpContextAccessor;
        _defaultModelBinder = new BodyModelBinder(mvcOptions.Value.InputFormatters, streamReaderFactory);
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (!typeof(UserContext).IsAssignableFrom(bindingContext.ModelType))
        {
            return;
        }

        await _defaultModelBinder.BindModelAsync(bindingContext);

        if (bindingContext.Result.IsModelSet && bindingContext.Result.Model is UserContext)
        {
            var model = (UserContext)bindingContext.Result.Model;
            var httpContext = _httpContextAccessor.HttpContext;

            // Read JWT
            var jwt = httpContext.Request.Headers["Authorization"];

            model.ApplicationUserId = jwt;

            bindingContext.Result = ModelBindingResult.Success(model);
        }
    }
}

Then add model binder to UserContext class:

[ModelBinder(typeof(UserContextModelBinder))]
public abstract class UserContext
{
    public string ApplicationUserId { get; set; }
}

Also add IHttpContextAccessor to services in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddHttpContextAccessor();
}


来源:https://stackoverflow.com/questions/60786102/reading-httpcontext-request-as-object

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!