如何从包含 .Net 5 Web API 中的 HttpContext 数据的通用 class 创建响应
How to create a response from a generic class containing HttpContext data in .Net 5 Web API
我已经使用 .Net 5 开始了一个新项目(我之前的项目是 .Net Framework 4.7)。我正在编写一个网络 API 项目,我希望我所有的 controllers/action 响应都属于某种类型。这允许我在每个响应中添加一些我想要包含的信息,例如当前用户信息(以及更多内容)。
我的一般回复如下所示(我只留下了相关代码):
public class MyResponse<T>
{
public T data { get; set; }
public User user { get; set; }
public MyResponse(T inputData)
{
data = inputData;
}
}
我这样设置对控制器操作的响应:
public IActionResult Get()
{
var response = new MyResponse<string>("Hello");
return Ok(response);
}
所以这个想法是响应总是包含一个“数据”属性 和实际数据,以及一堆其他属性和元数据。
问题是如何在 .Net 5 中包含登录用户的信息。在 .Net 4.x 中,您可以从任何地方访问 HttpContext,因此您可以只填充用户 属性。但这在 .Net 5
中是不可能的
我正在疯狂地尝试了解如何在 .Net 5 中实现这一目标。
我尝试的第一件事是 DI(我是新手,所以我可能没有正确理解它)。
我尝试的第一件事是让我的用户 class 依赖于 IHttpContextAccessor,因为大多数文档都指向:
public class User : IIdentity
{
private readonly IHttpContextAccessor _httpContextAccessor;
public User(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
并在 startup.cs 上以这种方式注册:
services.AddHttpContextAccessor();
services.AddTransient<User>();
但这效果不佳,因为当我尝试在 MyResponse class:
中创建我的用户 class
var user = new User(); // This doesn't work, as the constructor requires one argument
所以构造函数需要一个参数,所以我不能那样创建 class。我(相信)我需要从 DI 容器创建用户,但我无法在 MyResponse class 上访问它(或者至少我不能真正理解如何去做,或者如果可能的话)。
我可以将 HttpContext 从控制器传递到 MyResponse,但这似乎完全错误(另外,可能还有其他人在写控制器,所以我认为如果他们不明确需要将其传递给响应会更好,应该透明地处理)
我的具体问题:
关于如何在我的自定义响应中获取 HttpContext 的任何想法 class?
我是否应该寻找替代选项(例如中间件或过滤器)来生成我的响应?
非常感谢。
您可以将工厂与依赖注入一起使用。
创建您的用户class:
using Microsoft.AspNetCore.Http;
using System.Security.Principal;
public class User : IIdentity
{
private IHttpContextAccessor HttpContextAccessor { get; }
public User(IHttpContextAccessor httpContextAccessor)
{
this.HttpContextAccessor = httpContextAccessor;
}
public string AuthenticationType => this.HttpContextAccessor.HttpContext.User.Identity.AuthenticationType;
public bool IsAuthenticated => this.HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated;
public string Name => this.HttpContextAccessor.HttpContext.User.Identity.Name;
}
使用 DI 注入你想要的类型的工厂:
services.AddHttpContextAccessor();
services.AddSingleton(a => GetResponse<string>(a));
services.AddSingleton(a => GetResponse<int>(a));
services.AddSingleton(a => GetResponse<decimal>(a));
Func<T, MyResponse<T>> GetResponse<T>(IServiceProvider serviceProvider)
{
var contextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
var user = new User(contextAccessor);
return (data) => new MyResponse<T>(user, data);
}
然后注入到你想要的地方:
namespace WebAppFiles.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private Func<int, MyResponse<int>> ResponseFactory { get; }
public MyController(Func<int, MyResponse<int>> responseFactory)
{
this.ResponseFactory = responseFactory;
}
[HttpGet]
public IActionResult Get([FromQuery] int value)
{
return Ok(this.ResponseFactory(value));
}
}
}
我已经使用 .Net 5 开始了一个新项目(我之前的项目是 .Net Framework 4.7)。我正在编写一个网络 API 项目,我希望我所有的 controllers/action 响应都属于某种类型。这允许我在每个响应中添加一些我想要包含的信息,例如当前用户信息(以及更多内容)。 我的一般回复如下所示(我只留下了相关代码):
public class MyResponse<T>
{
public T data { get; set; }
public User user { get; set; }
public MyResponse(T inputData)
{
data = inputData;
}
}
我这样设置对控制器操作的响应:
public IActionResult Get()
{
var response = new MyResponse<string>("Hello");
return Ok(response);
}
所以这个想法是响应总是包含一个“数据”属性 和实际数据,以及一堆其他属性和元数据。
问题是如何在 .Net 5 中包含登录用户的信息。在 .Net 4.x 中,您可以从任何地方访问 HttpContext,因此您可以只填充用户 属性。但这在 .Net 5
中是不可能的我正在疯狂地尝试了解如何在 .Net 5 中实现这一目标。
我尝试的第一件事是 DI(我是新手,所以我可能没有正确理解它)。
我尝试的第一件事是让我的用户 class 依赖于 IHttpContextAccessor,因为大多数文档都指向:
public class User : IIdentity
{
private readonly IHttpContextAccessor _httpContextAccessor;
public User(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
并在 startup.cs 上以这种方式注册:
services.AddHttpContextAccessor();
services.AddTransient<User>();
但这效果不佳,因为当我尝试在 MyResponse class:
中创建我的用户 classvar user = new User(); // This doesn't work, as the constructor requires one argument
所以构造函数需要一个参数,所以我不能那样创建 class。我(相信)我需要从 DI 容器创建用户,但我无法在 MyResponse class 上访问它(或者至少我不能真正理解如何去做,或者如果可能的话)。
我可以将 HttpContext 从控制器传递到 MyResponse,但这似乎完全错误(另外,可能还有其他人在写控制器,所以我认为如果他们不明确需要将其传递给响应会更好,应该透明地处理)
我的具体问题:
关于如何在我的自定义响应中获取 HttpContext 的任何想法 class? 我是否应该寻找替代选项(例如中间件或过滤器)来生成我的响应?
非常感谢。
您可以将工厂与依赖注入一起使用。
创建您的用户class:
using Microsoft.AspNetCore.Http;
using System.Security.Principal;
public class User : IIdentity
{
private IHttpContextAccessor HttpContextAccessor { get; }
public User(IHttpContextAccessor httpContextAccessor)
{
this.HttpContextAccessor = httpContextAccessor;
}
public string AuthenticationType => this.HttpContextAccessor.HttpContext.User.Identity.AuthenticationType;
public bool IsAuthenticated => this.HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated;
public string Name => this.HttpContextAccessor.HttpContext.User.Identity.Name;
}
使用 DI 注入你想要的类型的工厂:
services.AddHttpContextAccessor();
services.AddSingleton(a => GetResponse<string>(a));
services.AddSingleton(a => GetResponse<int>(a));
services.AddSingleton(a => GetResponse<decimal>(a));
Func<T, MyResponse<T>> GetResponse<T>(IServiceProvider serviceProvider)
{
var contextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
var user = new User(contextAccessor);
return (data) => new MyResponse<T>(user, data);
}
然后注入到你想要的地方:
namespace WebAppFiles.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class MyController : ControllerBase
{
private Func<int, MyResponse<int>> ResponseFactory { get; }
public MyController(Func<int, MyResponse<int>> responseFactory)
{
this.ResponseFactory = responseFactory;
}
[HttpGet]
public IActionResult Get([FromQuery] int value)
{
return Ok(this.ResponseFactory(value));
}
}
}