Главная страница   /   16.3. Действие, авторизация и фильтры результатов (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

16.3. Действие, авторизация и фильтры результатов

Первой возможностью расширения действий является использование ActionFilter. Данная возможность расширения позволяет прерывать выполнение действия и дополнять поведение до или после того, как выполнится действие. Это похоже на аспектно-ориентированное программирование, которое является способом применения в коде сквозной функциональности, что исключает необходимость хранения большого количества продублированного кода. На рисунке 16-3. показана структура ActionFilterAttribute.

Рисунок 16-3: Методы фильтров действий, которые можно переопределить для модификации действия

Фильтр действия ChildActionOnlyAttribute был выпущен вместе с ASP.NET MVC 2. Этот фильтр реализует интерфейс IAuthorizationFilter, и используется фреймворком для того, чтобы убедиться, что действие в представлении вызывается только из метода Html.Action(). Действие, обладающее этим атрибутом, не может быть вызвано посредством роута верхнего уровня и не является вызываемым из веба.

Код в следующем листинге демонстрирует применение ChildActionOnlyAttribute к методу ChildAction.

Листинг 16-1: Использование ChildActionOnlyAttribute
using System.Web.Mvc;
namespace ChildActionSample.Controllers
{
	public class HomeController : Controller
	{
		public ActionResult Index()
		{
			ViewBag.Message = "Welcome to ASP.NET MVC!";
			return View();
		}
		[ChildActionOnly]
		public ActionResult ChildAction()
		{
			return View();
		}
	}
}

Строка 6: Действие Index по умолчанию

Строки 11-12: Фильтр действия, применяемый к действию

Атрибут ChildActionOnly не дает методу ChildAction использоваться в качестве действия, которое может вызываться веб-браузером. Но этот метод все еще может быть вызван посредством вызова Html.Action() в рамках представления, как это показано ниже:

@Html.Action("ChildAction")

Учет фильтров в тестах

Может показаться странным, что режим работы, определенный в атрибуте, вызывается при вызове действия. Во время выполнения метод не вызывается напрямую; он передается в ControllerActionInvoker, который прочитывает фильтры действий, присутствующие в контроллере и действии. Такая возможность во фреймворке является довольно привлекательным вариантом расширения, потому что, если вы хотите настроить семантику, то вам позволяется использовать свой собственный IActionInvoker.

В рамках модульных тестов вы будете вызывать методы действий напрямую. Ни одно из поведений, определенных в фильтрах действий, не будет выполнено, поэтому вы должны обрабатывать ваши тесты, как если бы фильтры действий были выполнены (например, загрузите любые данные во ViewData, которые могли бы быть загружены фильтром действия). Для того чтобы определить, были ли применены такие фильтры, как [Authorize] или [HttpPost], вы можете просто протестировать наличие атрибута посредством рефлексии.

Ниже представлен класс, который поможет вам упростить код рефлексии, необходимый для получения атрибутов:

public static class ReflectionExtensions
{
	public static TAttribute GetAttribute<TAttribute>(this MemberInfo member) 
		where TAttribute : Attribute
	{
		var attributes = member.GetCustomAttributes(typeof(TAttribute), true);
		if (attributes != null && attributes.Length > 0)
			return (TAttribute)attributes[0];
		return null;
	}
	public static bool HasAttribute<TAttribute>(this MemberInfo member) 
		where TAttribute : Attribute
	{
		return member.GetAttribute<TAttribute>() != null;
	}
}

Вы можете использовать этот метод расширения так, как это показано ниже:

type.GetMethod("Index").HasAttribute<AcceptVerbsAttribute>()...

Метод расширения принимает тип атрибута в качестве универсального параметра, а затем убеждается в том, что запрашиваемый метод помечен этим атрибутом.