Объединение AjaxOnlyAttribute и ChildActionOnlyAttribute в один фильтр действий - PullRequest
7 голосов
/ 02 марта 2012

Я хочу иметь возможность пометить действие на контроллере, которое будет вызываться как из вызовов ajax, так и через RenderAction.Проблема в том, что оба эти атрибута получают или реализуют разные абстракции.Одним из выходов является следующий:

[AjaxOnly]
PartialViewResult GetViewAjax(int foo) { return GetView(foo); }
[ChildActionOnly]
PartialViewResult GetView(int foo) { ... }

Но это совсем не аккуратно.


Атрибут AjaxOnly, о котором я говорю:* Этот метод взят из фьючерсов MVC3.Команда разработчиков сделала важный комментарий, почему условие не filterContext.HttpContext.Request.IsAjaxRequest(), и говорит следующее:

// Dev10 #939671 - If this attribute is going to say AJAX *only*, then we need to check the header
// specifically, as otherwise clients can modify the form or query string to contain the name/value
// pair we're looking for.

Ответы [ 2 ]

16 голосов
/ 02 марта 2012

Это не имеет никакого смысла.Эти 2 атрибута являются взаимоисключающими.Если действие помечено [ChildActionOnly], клиент никогда не сможет получить к нему прямой доступ с помощью HTTP-запроса (будь то синхронный или асинхронный).Поэтому, если вы хотите, чтобы действие было когда-либо доступно с использованием AJAX, вы никогда не должны украшать его атрибутом [ChildActionOnly].

Я не знаю, что это за атрибут [AjaxOnly] и откуда он берется, но в зависимости от того, как он реализован, вам может понадобиться настроить его, чтобы разрешить дочерние запросы действий, если он опирается только на Request.IsAjaxRequest() метод.Например, если это что-то вроде этого:

public class AjaxOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new HttpNotFoundResult();
        }
    }
}

, вы можете настроить его следующим образом:

public class AjaxOrChildActionOnlyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest() && 
            !filterContext.IsChildAction
        )
        {
            filterContext.Result = new HttpNotFoundResult();
        }
    }
}
1 голос
/ 20 мая 2015

Вдохновленный ответом Дарина и исходным кодом ChildActionOnlyAttribute, я пришел к этому решению, которое, я думаю, немного лучше:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AjaxOrChildAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return controllerContext.IsChildAction || controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
    }
}

Таким образом, проверкасделано до того, как даже попытаться выполнить, и ошибка, которую вы получите, если ввести URL-адрес, точно такая же, как и при попытке любого недопустимого URL-адреса.

...