【发布时间】:2020-02-05 04:33:13
【问题描述】:
我有一个基类,我的 (api) 控制器从该基类继承。 我这样做是为了让我可以从我的身份验证提供者那里获取用户 ID,然后用它来处理用户、更新它或获取它的数据等。
public class BaseController : ControllerBase
{
protected readonly IBaseData _baseData;
public BaseController(IBaseData baseData)
{
_baseData = baseData;
}
public Guid GetUserId()
{
string nameIdentifier = User.FindFirst(ClaimTypes.NameIdentifier).Value;
Guid? userId = _baseData.GetInvestorId(nameIdentifier);
return userId != null ? (Guid)userId : Guid.Empty;
}
}
然后我在我的 API 端点中调用它:
Guid userId = GetUserId();
BaseModel m = _userData.GetBaseModel(userId);
return Ok(m);
很简单。它在控制器中的多个位置被调用。 不理想但工作正常。 但是现在我需要捕获一个错误,该错误有时会在用户不在数据库中时发生。 我可以像这样向 API 端点添加一些代码:
Guid userId = GetUserId();
if (userId == Guid.Empty)
return NotFound(new ResponseGapiModel { Response = Response.NotFound, Message = "user not found in DB" });
BaseModel m = _userData.GetBaseModel(userId);
return Ok(m);
但这意味着我会到处重复很多代码。 我一直在尝试使用动作过滤器。但我无法理解它。 我不知道如何在 actionfilter 中传递参数,比如我需要找到用户的名称标识符。也没有坦率地说如何将 ID 传回。
-更新-
我现在已经设法让 actionfilter 在找不到用户时返回失败的结果,所以我需要的一半有效。问题是现在我两次调用 DB,因为我仍然调用原始 BaseCass GetUserId 来获取要在以后的方法中使用的 ID。
为了让 ActionFilter 检查丢失的用户,我将 datacontext 注入其中:
private readonly NodeDBContext _context;
public ValidateAuth0UserInDBAttribute(NodeDBContext context)
{
_context = context;
}
以及使用 ActionExecutingContext 中的 HttpContext 来查找我的用户 Nameidentifier:
public void OnActionExecuting(ActionExecutingContext context)
{
//check if the user it in DB
var id = _context.Users.SingleOrDefault(i => i.NameIdentifier == context.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value)?.Id;
if (id == null)
{
context.Result = new NotFoundObjectResult(new ResponseModel { Response = Response.UserNotFound, Message = "User not found in DB" });
return;
}
}
现在的问题是如何将“id”从这里传递回我的控制器?有办法吗?还是我必须调用数据库两次?
【问题讨论】:
-
您不会将参数传递给动作过滤器(在 ctor 之外)。动作过滤器从请求中获取(部分)其参数。例如,您可以从查询字符串或表单数据中获取
userId。 -
也许您可以在您的
BaseController.GetUserId()方法中使用throw new HttpResponseException(HttpStatusCode.Status401Unauthorized)而不是return Guid.Empty? -
@maxbeaudoin 我明白了,你的意思,所以只有请求中的参数可用。我使用上下文本身进行了一些更改以检索我需要的用户 ID。但是如果没有失败,如何将信息返回到我的控制器时遇到了一些麻烦。
-
@vasily.sib 我正在尝试创建动作过滤器,这样我就不必抛出异常并在任何地方进行尝试和捕获
-
我的意思是 - 不要试图抓住它,这应该在结果中返回 404
标签: c# asp.net-core action-filter