AuthenticationRequiredAttributeクラス
public class AuthenticationRequiredAttribute : ActionFilterAttribute
{
ILoginTokenKeyApi _loginTokenKeyApi;
IMemoryCache _memoryCache;
public AuthenticationRequiredAttribute(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
_loginTokenKeyApi = new LoginTokenKeyController(new UnitOfWork());
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var memory = _memoryCache.Get(Constants.KEYNAME_FOR_AUTHENTICATED_PAGES);
string requestedPath = filterContext.HttpContext.Request.Path;
string tokenKey = filterContext.HttpContext.Session.GetString("TokenKey")?.ToString();
bool? isLoggedIn = _loginTokenKeyApi.IsLoggedInByTokenKey(tokenKey).Data;
if (isLoggedIn == null ||
!((bool)isLoggedIn) ||
!Constants.AUTHENTICATED_PAGES_FOR_NORMAL_USERS.Contains(requestedPath))
{
filterContext.Result = new JsonResult(new { HttpStatusCode.Unauthorized });
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
HomeController
public class HomeController : Controller
{
IUserApi _userApi;
ILoginTokenKeyApi _loginTokenKey;
IMemoryCache _memoryCache;
public HomeController(IUserApi userApi, ILoginTokenKeyApi loginTokenKey, IMemoryCache memoryCache)
{
_loginTokenKey = loginTokenKey;
_userApi = userApi;
_memoryCache = memoryCache;
}
[AuthenticationRequired] // There is AN ERROR !!
public IActionResult Example()
{
return View();
}
}
エラー:
エラーCS7036 'AuthenticationRequiredAttribute.AuthenticationRequiredAttribute(IMemoryCache)' Project.Ground.WebUIの必須仮パラメーター 'memoryCache'に対応する引数が指定されていません
実際の問題は、属性クラスで依存性注入を使用できないです。
パラメーターなしでその属性を使用します。それを解決する解決策はありますか?依存性注入を使用しますが、属性には使用できません。どのように使用できますか?
ドキュメント に従って、ここにいくつかのオプションがあります:
DIからアクセスする必要がある依存関係がフィルターにある場合、いくつかのサポートされるアプローチがあります。次のいずれかを使用して、クラスまたはアクションメソッドにフィルターを適用できます。
これをすぐに機能させたい場合は、最初の2つのオプションのいずれかを使用して、コントローラーまたはコントローラーアクションにフィルターを適用できます。これを行う場合、フィルターは属性そのものである必要はありません。
[TypeFilter(typeof(ExampleActionFilter))]
public IActionResult Example()
=> View();
ExampleActionFilter
は、たとえば IAsyncActionFilter
そして、コンストラクター注入を使用して物事に直接依存できます。
public class ExampleActionFilter : IAsyncActionFilter
{
private readonly IMemoryCache _memoryCache;
public ExampleActionFilter(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{ … }
}
代わりに[ServiceFilter]
属性を使用して同じ効果を得ることができますが、ExampleActionFilter
の依存関係注入コンテナーにStartup
を登録する必要もあります。
さらに柔軟性が必要な場合は、独自のフィルターファクトリを実装できます。これにより、ファクトリコードを記述して、実際のフィルターインスタンスを自分で作成できます。上記のExampleActionFilter
の可能な実装は次のようになります。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ExampleActionFilterAttribute : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetService<ExampleActionFilter>();
}
}
次に、その[ExampleActionFilter]
属性を使用して、DIコンテナーを使用して、MVCフレームワークにExampleActionFilter
のインスタンスを作成させます。
この実装は、基本的にServiceFilterAttribute
と同じものであることに注意してください。自分で実装すると、ServiceFilterAttribute
を直接使用する必要がなくなり、独自の属性を持つことができます。
最後に、コンストラクターの挿入を完全に回避できる別のクイックオプションがあります。これは、サービスロケーターパターンを使用して、フィルターが実際に実行されるときにサービスを動的に解決します。そのため、依存関係を注入して直接使用する代わりに、コンテキストから明示的に取得します。
public class ExampleActionFilter : ActionFilterAttribute
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var memoryCache = context.HttpContext.RequestServices.GetService<IMemoryCache>();
// …
}
}
構築時に解決する代わりに、ActionExecutingContext.HttpContext.RequestServices
は、リクエスト時にリクエストのサービスコンテナへの参照を提供する必要があります。
そう:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var svc = filterContext.HttpContext.RequestServices;
var memCache = svc.GetService<IMemoryCache>();
//..etc