【问题标题】:Reading HttpContext.Request as object?将 HttpContext.Request 作为对象读取?
【发布时间】:2020-03-23 14:19:15
【问题描述】:

我的基础Request 类如下所示:

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
}

我想为我的.NET Core 3.1 WebApi 编写一个中间件,它将从请求头中获取JWT 并从中读取ApplicationUserId。我开始编写代码:

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);
    }
}

但老实说,我不知道如何开始,所以这是我的问题:

如您所见,每个请求都将包含我的UserContext 类等等。如何将HttpContext.Request.Body 转换为我的请求对象并将ApplicationUserId 附加到它?可能吗?我想从我的 JWT 从标头访问用户凭据,并且我希望在我的 API 中的每个请求中都有该信息(将其传递给控制器​​,然后传递给命令等)。

如果从中间件获取这些信息不是最佳做法,那是什么?

编辑:使用MediatR的Mcontroller:

// 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
        };
    }
}

【问题讨论】:

  • 看看this的帖子。

标签: c# asp.net-core


【解决方案1】:

您可能不需要中间件,但需要模型绑定器:

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

另见: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);
        }
    }
}

然后将模型绑定器添加到UserContext 类:

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

还要在 Startup.cs 中的服务中添加 IHttpContextAccessor

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

【讨论】:

  • 看起来不错,您能否通过其他链接提供您的答案?我想更多地了解这个绑定,因为它是我正在寻找的
  • 老实说,您的解决方案不起作用。我复制粘贴它,ModelBinder 从未被击中
  • @michasaucer 这很奇怪。我在答案中的内容是从我测试过的本地项目中复制粘贴的。我有一个控制器动作,它是一个 HTTP Post 并采用 Query 的参数(派生自 UserContext),你的控制器动作是什么样的?这是我的[HttpPost] public IEnumerable&lt;WeatherForecast&gt; Get([FromBody]Query query)
  • 我的查询命中handler,但不是binder
  • @michasaucer 模型绑定器在您拥有类似public async Task&lt;ActionResult&lt;ProjectsListModel&gt;&gt; GetAllProjects([FromQuery] GetAllProjectsQuery query) 的控制器时工作,如果您使用new 创建一个新查询,它不会触发模型绑定器。我认为您需要从正文中读取查询?
猜你喜欢
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 2020-06-02
  • 2017-09-19
  • 2020-12-07
相关资源
最近更新 更多