如何在多个控制器的多个动作中实现一些代码
How to implement some code in many actions of many controllers
我有带动作的控制器,它与某些实体(驱动程序)一起工作。此外,每个驱动程序都与身份配置文件相关联。
public async Task<ActionResult> Details(int? id)
{
if ((id == null))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
DriverDetailVM model = mapper.Map<DriverDetailVM>(db.Drivers.Find(id));
if ((model == null))
{
return HttpNotFound();
}
return View(model);
}
public async Task<ActionResult> Edit(int? id = null, bool isNewUser = false)
{
/////////
}
如果用户具有 "Superadmin" 角色,那么他可以访问具有任何 id 值的页面。如果用户具有 "Driver" 角色,那么只有当 id 值与他的个人资料相同时,我们才能访问。我尝试在 ActionFilter 上实现它:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
public int DriverID { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.IsInRole("Driver"))
{
if (filterContext.ActionParameters.ContainsKey(IdParamName))
{
var id = filterContext.ActionParameters[IdParamName] as Int32;
if (id != DriverID)
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
}
else
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
else
base.OnActionExecuting(filterContext);
}
}
但是当我尝试使用此代码时:
[DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")]
public async Task<ActionResult> Details(int? id)
{
不想编译,因为
An object reference is required for the non-static field, method, or
property
如何实现?
属性参数在编译时计算,而不是在 运行 时计算。所以它们必须是编译时常量。您不能在 运行 时将值传递给操作属性。也就是说,在 [DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")]
中,您超过了 DriverID = currentUser.DriverId
。属性用作 controller/action 元数据,需要在程序集中编译元数据。这就是属性只能取常量值的原因。
您必须按如下方式更改您的属性:
- 使用依赖注入注入您的服务,returns 登录用户。
- 或者实施自定义委托人并为其分配当前请求委托人。
如果您实施 CustomPrinicpal,您可以按如下方式修改您的属性:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
private int DriverID { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.IsInRole("Driver"))
{
var customPrincipal = filterContext.HttpContext.User as CustomPrincipal;
DriverID = customPrincipal.Id;
// Rest of you logic
}
else
base.OnActionExecuting(filterContext);
}
}
如果您选择 DI 路径,则可以使用以下代码段:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
private int DriverID { get; set; }
public DriverAccessActionFilterAttribute(IYourIdentityProvider provider)
{
DriverID = provider.LoggedInUserID;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Your logic
}
}
然后将您的属性用作 [DriverAccessActionFilter(IdParamName = "id")]
我有带动作的控制器,它与某些实体(驱动程序)一起工作。此外,每个驱动程序都与身份配置文件相关联。
public async Task<ActionResult> Details(int? id)
{
if ((id == null))
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
DriverDetailVM model = mapper.Map<DriverDetailVM>(db.Drivers.Find(id));
if ((model == null))
{
return HttpNotFound();
}
return View(model);
}
public async Task<ActionResult> Edit(int? id = null, bool isNewUser = false)
{
/////////
}
如果用户具有 "Superadmin" 角色,那么他可以访问具有任何 id 值的页面。如果用户具有 "Driver" 角色,那么只有当 id 值与他的个人资料相同时,我们才能访问。我尝试在 ActionFilter 上实现它:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
public int DriverID { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.IsInRole("Driver"))
{
if (filterContext.ActionParameters.ContainsKey(IdParamName))
{
var id = filterContext.ActionParameters[IdParamName] as Int32;
if (id != DriverID)
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
}
else
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
else
base.OnActionExecuting(filterContext);
}
}
但是当我尝试使用此代码时:
[DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")]
public async Task<ActionResult> Details(int? id)
{
不想编译,因为
An object reference is required for the non-static field, method, or property
如何实现?
属性参数在编译时计算,而不是在 运行 时计算。所以它们必须是编译时常量。您不能在 运行 时将值传递给操作属性。也就是说,在 [DriverAccessActionFilter(DriverID = currentUser.DriverId, IdParamName = "id")]
中,您超过了 DriverID = currentUser.DriverId
。属性用作 controller/action 元数据,需要在程序集中编译元数据。这就是属性只能取常量值的原因。
您必须按如下方式更改您的属性:
- 使用依赖注入注入您的服务,returns 登录用户。
- 或者实施自定义委托人并为其分配当前请求委托人。
如果您实施 CustomPrinicpal,您可以按如下方式修改您的属性:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
private int DriverID { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.IsInRole("Driver"))
{
var customPrincipal = filterContext.HttpContext.User as CustomPrincipal;
DriverID = customPrincipal.Id;
// Rest of you logic
}
else
base.OnActionExecuting(filterContext);
}
}
如果您选择 DI 路径,则可以使用以下代码段:
public class DriverAccessActionFilterAttribute : ActionFilterAttribute
{
public string IdParamName { get; set; }
private int DriverID { get; set; }
public DriverAccessActionFilterAttribute(IYourIdentityProvider provider)
{
DriverID = provider.LoggedInUserID;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Your logic
}
}
然后将您的属性用作 [DriverAccessActionFilter(IdParamName = "id")]