アクションフィルターにサービスを挿入しようとしていますが、必要なサービスがコンストラクターに挿入されていません。ここに私が持っているものがあります:
public class EnsureUserLoggedIn : ActionFilterAttribute
{
private readonly ISessionService _sessionService;
public EnsureUserLoggedIn()
{
// I was unable able to remove the default ctor
// because of compilation error while using the
// attribute in my controller
}
public EnsureUserLoggedIn(ISessionService sessionService)
{
_sessionService = sessionService;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Problem: _sessionService is null here
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
}
そして、私は自分のコントローラーを次のように飾ります:
[Route("api/issues"), EnsureUserLoggedIn]
public class IssueController : Controller
{
}
Startup.cs
services.AddScoped<ISessionService, SessionService>();
これらの記事を参照として使用:
ASP.NET 5およびMVC 6のアクションフィルター、サービスフィルター、およびタイプフィルター
ServiceFilterとしてフィルターを使用する
フィルターはServiceType
として使用されるため、フレームワークIoCに登録する必要があります。アクションフィルタが直接使用された場合、これは必要ありません。
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddScoped<ISessionService, SessionService>();
services.AddScoped<EnsureUserLoggedIn>();
...
}
次のようなServiceFilter
属性を使用して、MVCコントローラーメソッドとコントローラークラスにカスタムフィルターが追加されます。
[ServiceFilter(typeof(EnsureUserLoggedIn))]
[Route("api/issues")]
public class IssueController : Controller {
// GET: api/issues
[HttpGet]
[ServiceFilter(typeof(EnsureUserLoggedIn))]
public IEnumerable<string> Get(){...}
}
他の例がありました
フィルターをグローバルフィルターとして使用する
ベースコントローラーでフィルターを使用する
注文でフィルターを使用する
見て、試してみて、問題が解決するかどうかを確認してください。
お役に立てれば。
IFilterFactory
を実装する必要があります:
public class AuthorizationFilterFactory : IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
// manually find and inject necessary dependencies.
var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));
return new AuthorizationFilter(context);
}
}
Startup
クラスでは、実際のフィルターを登録する代わりに、フィルターファクトリを登録します。
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizationFilterFactory());
});
この問題を解決するもう1つの方法。次のコードのように、コンテキストを介してサービスを取得できます。
public override void OnActionExecuting(ActionExecutingContext context)
{
_sessionService = context.HttpContext.RequestServices.GetService<ISessionService>();
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
Startup.csでこのサービスを登録する必要があることに注意してください
services.AddTransient<ISessionService, SessionService>();
この記事を読んだ後 ASP.NET Core-Real-World ASP.NET Core MVC Filters(Aug 2016) 私はこのように実装しました:
Starup.cs/ConfigureServicesで:
services.AddScoped<MyService>();
MyFilterAttribute.cs内:
public class MyFilterAttribute : TypeFilterAttribute
{
public MyFilterAttribute() : base(typeof (MyFilterAttributeImpl))
{
}
private class MyFilterAttributeImpl : IActionFilter
{
private readonly MyService _sv;
public MyFilterAttributeImpl(MyService sv)
{
_sv = sv;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_sv.MyServiceMethod1();
}
public void OnActionExecuted(ActionExecutedContext context)
{
_sv.MyServiceMethod2();
}
}
}
MyFooController.csで:
[MyFilter]
public IActionResult MyAction()
{
}
編集:[MyFilter("Something")]
などの引数を渡すには、TypeFilterAttributeクラスのArgumentsプロパティを使用します。 asp.netでアクションフィルターにパラメーターを追加する方法 物を注入する(同じ方法))
例
private ILoginService _loginService;
public override void OnActionExecuting(ActionExecutingContext context)
{
_loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
}
それが役に立てば幸い。
質問は暗黙的に「属性を介したフィルター」に言及していますが、「タイプ別にグローバルに」フィルターを追加すると、すぐに使用できるDIがサポートされることを強調する価値があります。
[タイプ別に追加されたグローバルフィルターの場合]すべてのコンストラクター依存関係は、依存関係注入(DI)によって設定されます。タイプによるフィルターの追加は、filters.Add(new TypeFilterAttribute(typeof(MyFilter)))と同等です。 https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
属性ベースのフィルターに関して:
属性として実装され、コントローラークラスまたはアクションメソッドに直接追加されるフィルターは、依存性注入(DI)によって提供されるコンストラクターの依存関係を持つことはできません。これは、属性が適用されるコンストラクターパラメーターを指定する必要があるためです。これは、属性の機能の制限です。 https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
ただし、OPに対する以前の回答で述べたように、DIを達成するために使用できる間接化の方法があります。完全を期すため、公式ドキュメントへのリンクは次のとおりです。