Передайте объект из ActionFilter.OnActionExecuting() в ApiController

Я хочу создать объект для каждого запроса HTTP в ActionFilter и передать этот объект контроллеру. До сих пор я пробовал Request.Properties [] следующим образом

public class DbReadonlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        actionContext.Request.Properties["CustomObjectKey"] = new MyClass();

И я также попытался назначить новый объект непосредственно классу ControllerBase.

public class DbReadonlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var controller = (MyControllerBase) actionContext.ControllerContext.Controller;
        controller.StorageContextFactory = new MyClass();

Проблема заключается в том, что ни один из методов не предоставляет экземпляр MyClass для контроллера, потому что новое свойство ["CustomObjectKey"] теряется в конвейере Webapi к моменту вызова метода контроллера.

Контроллер повторно создается конвейером webapi после фильтра вызова OnActionExecuting().

Точки перехвата подтверждают, что конвейер Webapi рассылает следующий поток событий во время одного HTTP-запроса.

  • конструктор MyControllerBase()
  • MyAuthenticationFilter
  • Фильтр OnActionExecuting()
  • конструктор MyControllerBase()
  • MyController.MethodA()

Двойная инстанция MyControler нечетна, но прямо сейчас я ищу любую технику передачи вновь созданного объекта из фильтра действий в контроллер.

Edit-1: MyAuthorizationFilter, упомянутый в v1 этого вопроса, фактически является фильтром аутентификации. Все еще расследует.

Решение: ошибка была в другом фильтре. После того как я удалил свой фильтр проверки подлинности, проблема, о которой сообщалось в этом вопросе, ушла.

Ответ 1

Вы должны будете использовать .add метод Request.Properties коллекции.

public class DbReadonlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        actionContext.Request.Properties.Add(new KeyValuePair<string, object>("CustomObjectKey", new MyClass()));

Вы можете получить это значение из своего контроллера api.

object _customObject= null;

if (Request.Properties.TryGetValue("CustomObjectKey", out _customObjectKey))
{
    MyClass myObject = (MyClass)_customObject;
}

Ответ 2

Другой способ передать переменную из ActionFilter.OnActionExecuting() в ApiController:

public class CustomFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext actionContext)
    {
        actionContext.ControllerContext.RequestContext.RouteData.Values["CustomValue"] = "CustomValue";
    }
}

Обратите внимание на использование ActionFilterAttribute для веб-API:

System.Web.Http.Filters.ActionFilterAttribute

Не для классики MVC:

System.Web.Mvc.ActionFilterAttribute

С помощью:

[CustomFilter]
public class SomeController : ApiController
{
    string customValue = RequestContext.RouteData.Values.ToDictionary(x => x.Key, y => y.Value)["user_id"].ToString();
    //...
}