[英]How to pass a method or parameter to an action filter in ASP.Net MVC
我將在操作過濾器中處理身份驗證和授權,並創建一個如下所示的操作過濾器:
public class Auth : ActionFilterAttribute
{
public int Access { get; set; }
public string Roles { get; set; } = "Default";
public Func<bool> AuthFunc { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
string UserId = HttpContext.Current.User.Identity.GetUserId();
//Authentication
if (Roles != "Default" && UserManager.IsInRole(UserId, Roles))
{
//Authorization
if (AuthFunc) { base.OnActionExecuting(actionContext); }
else
{
var response = actionContext.Request.CreateResponse(HttpStatusCode.Redirect);
Uri requestUrl = actionContext.Request.RequestUri;
response.Headers.Location = new Uri($"{requestUrl.Scheme}://{requestUrl.Host}:{requestUrl.Port}");
actionContext.Response = response;
}
}
else
{
var response = actionContext.Request.CreateResponse(HttpStatusCode.Redirect);
Uri requestUrl = actionContext.Request.RequestUri;
response.Headers.Location = new Uri($"{requestUrl.Scheme}://{requestUrl.Host}:{requestUrl.Port}");
actionContext.Response = response;
}
}
}
並在控制器中:
[Auth(Roles="Teacher" , Access = (short)TableEnum.Course , AuthFunc = Courses.CheckCoursesOfTeacher(CourseId))]
public ActionResult ShowExerciseAnswers(int CourseId,int ExerciseId)
{
return View(model: ChapterExerciseAnswer.ExerciseAnswerList(CourseId,ExerciseId));
}
AuthFunc
方法可能具有多個輸入,但只有bool
返回值。
如何將AuthFunc
( Courses.CheckCoursesOfTeacher(CourseId)
方法)傳遞給動作過濾器?
如何在動作過濾器屬性中獲取CourseId
動作參數(將CourseId
或ExerciseId
作為屬性值傳遞)?
處理這些問題的最佳方法是什么(不能將函數和變量發送到動作過濾器)?
我最近發現自己正在尋找這樣的解決方案。 每個MS Docs的屬性參數必須遵循以下規則:
屬性構造函數的參數限於簡單的類型/文字:bool,int,double,string,Type,enums等以及這些類型的數組。 您不能使用表達式或變量。 您可以自由使用位置或命名參數。
因此,我們無法通過屬性參數將函數傳遞給過濾器。 可能有很多選擇,但是這是我選擇要做的:
我使用依賴項注入向管理器注入了動作過濾器,然后使用了反射來告訴過濾器在管理器上執行哪個方法。 看起來是這樣的:
類:
public class Phone : AuditBase
{
...other props...
[AuditRuleset(AuditRule.PhoneNumber)]
public string Number { get; set; }
}
枚舉:
public enum AuditRule
{
PhoneNumber // You can add [Description] if you want
}
屬性:
public class AuditRulesetAttribute : Attribute
{
private readonly AuditRule _rule;
public AuditRulesetAttribute(AuditRule rule) => _rule = rule;
}
過濾:
public class FormAuditActionFilter : IActionFilter
{
private ILog _log { get; set; }
private IFormAuditor _auditor { get; set; }
public FormAuditActionFilter(ILog log, IFormAuditor auditor)
{
_log = log;
_auditor = auditor;
}
...lots of filter code...
... The following is from OnActionExecuted, having stored the props of the submitted object in objectProperties...
foreach(PropertyInfo propertyInfo in objectProperties)
{
// Check first for any special audit comparison rules which should be followed
var auditRuleAttributes = propertyInfo.CustomAttributes
.Where(x => x.AttributeType.Name == typeof(AuditRulesetAttribute).Name)
.ToList();
if (auditRuleAttributes.Any())
{
IEnumerable<IList<CustomAttributeTypedArgument>> attrList = auditRuleAttributes
.Select(x => x.ConstructorArguments);
foreach(IList<CustomAttributeTypedArgument> attr in attrList)
foreach(CustomAttributeTypedArgument arg in attr)
if (_auditRuleManager.IsChanged(oldValue, newValue, (AuditRule)arg.Value))
result.Add(BuildValueHistory(propertyInfo.Name, oldValue, newValue));
continue;
}
}
...lots more filter code...
}
AuditRuleManager:
public class AuditRuleManager : IAuditRuleManager
{
public bool IsChanged(object val1, object val2, AuditRule rule)
{
object[] objArray = {val1, val2};
var comparisonResult = typeof(AuditRuleManager)
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.Single(m => m.Name == rule.GetDescription()) // Try to get description, but falls back to name by default
.Invoke(this, objArray) as bool?;
return (bool)comparisonResult; // Throw an exception if the comparison result was not a valid bool
}
// Compare phone numbers with special rules, and return their equality
private bool PhoneNumber(object val1, object val2) // NOTE: Name of method matches name of enum value
=> GetNumbersFromString(val1 as string) != GetNumbersFromString(val2 as string);
最后花了我一段時間的是使用Ninject的濾波器的DI。 這是我的工作方式
的Global.asax.cs:
kernel.BindFilter<FormAuditActionFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<FormAuditAttribute>()
.WithConstructorArgument("log", log)
.WithConstructorArgument("auditor", auditManager);
我沒有使用函數作為屬性參數,而是使用DI將管理器注入到過濾器中。 這使您的過濾器可以訪問所需的功能。 其次,我使用了一個枚舉來保存應執行的函數的名稱。 因此,從本質上講,創建新函數並使用參數執行該函數所要做的就是:
我希望這有幫助!
https://blogs.cuttingedge.it/steven/posts/2014/dependency-injection-in-attributes-dont-do-it/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.