MVC 的可扩展点:MVC 和 WEB-API 中的自定义操作选择





1.00/5 (1投票)
如何在 MVC 和 WebAPI 中创建自定义操作调用者
MVC 中的自定义操作选择
在本节中,我们将讨论 MVC 中的自定义操作选择。我们知道,在选择控制器后,框架通过调用 IHttpActionSelector.SelectAction
方法来选择操作。此方法接收一个 HttpControllerContext
并返回一个 HttpActionDescriptor
。默认实现由 ApiControllerActionSelector
类提供。为了选择一个操作,它会查看以下内容:
- 请求的 HTTP 方法。
- 如果存在,则在路由模板中的“
{action}
”占位符。 - 控制器上操作的参数。
现在,在需要时,我们可以覆盖默认行为并在两者之间插入我们自定义的代码。让我们尝试实现它。首先,我们必须从“ActionMethodSelectorAttribute
”类继承我们的自定义类。该类只有一个名为“IsValidForRequest
”的方法,该方法本质上是 abstract
。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public abstract class ActionMethodSelectorAttribute : Attribute
{
protected ActionMethodSelectorAttribute();
public abstract bool IsValidForRequest
(ControllerContext controllerContext, MethodInfo methodInfo);
}
由于此方法是 abstract
,我们可以在自定义类中定义它。以下是我们在执行此操作的示例代码:
public class ActionDecorationAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest
(ControllerContext controllerContext, MethodInfo methodInfo)
{
//Check for AJAX request
if (!controllerContext.HttpContext.Request.IsAjaxRequest())
throw new Exception("Accept AJAX call only");
//Check for HTTPS request only
if (!controllerContext.HttpContext.Request.IsSecureConnection)
throw new Exception("Support only HTTPS");
//Check for language
if (controllerContext.HttpContext.Request.UserLanguages[0] != "en-US")
throw new Exception("For English user only");
return true;
}
}
从请求上下文中验证一些内容。示例代码非常简单,只是为了帮助演示这一点。您可以在实际问题中实现您的实际逻辑。现在,我们必须将自定义类附加到操作,以便在控制器执行之前注入代码片段。
public class HomeController : Controller
{
[ActionDecoration]
public ActionResult Index()
{
return new EmptyResult();
}
}
现在,当 Index
操作的请求到达时,在执行 Index
之前,它将触发 ActionDecorationAttribute
类中的 Validation
方法。
您可能有一个问题是,“我们不能在操作筛选器中做同样的事情吗?” 对吧? 好的,但是操作选择器和操作筛选器的目的完全不同。操作选择器的任务是选择操作,而操作筛选器用于在操作执行之前和之后执行代码(在大多数情况下)。
Web API 中的自定义操作调用者
我们知道 Web API 默认支持基于 HTTP 动词的路由。这意味着框架将根据请求类型搜索匹配的操作,然后与参数匹配。要在 Web API 中实现自定义操作选择器,我们必须从以下类继承:
"ApiControllerActionSelector" class. Here is the definition of "ApiControllerActionSelector" class.
//
// Summary:
// Represents a reflection based action selector.
public class ApiControllerActionSelector : IHttpActionSelector
{
//
// Summary:
// Initializes a new instance of the
// System.Web.Http.Controllers.ApiControllerActionSelector class.
public ApiControllerActionSelector();
//
// Summary:
// Gets the action mappings for the
// System.Web.Http.Controllers.ApiControllerActionSelector.
// Parameters:
// controllerDescriptor:
// The information that describes a controller.
//
// Returns:
// The action mappings.
public virtual ILookup<string, HttpActionDescriptor>
GetActionMapping(HttpControllerDescriptor controllerDescriptor);
//
// Summary:
// Selects an action for the System.Web.Http.Controllers.ApiControllerActionSelector.
//
// Parameters:
// controllerContext:
// The controller context.
//
// Returns:
// The selected action.
public virtual HttpActionDescriptor SelectAction(HttpControllerContext controllerContext);
}
在此示例中,我们创建了一个非常简单的类,该类继承自“ApiControllerActionSelector
”类。
public class ApiActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction( HttpControllerContext context)
{
HttpMessageContent requestContent = new HttpMessageContent( context.Request);
var actionMethod = context.ControllerDescriptor.ControllerType
.GetMethods(BindingFlags.Instance | BindingFlags.Public)
.FirstOrDefault();
if (actionMethod != null)
{
return new ReflectedHttpActionDescriptor(
context.ControllerDescriptor, actionMethod);
}
return base.SelectAction(context);
}
}
所以我们在这里没有做太多事情。只想检查操作名称。由于 SelectAction
方法将 HttpControllerContext
对象作为参数,因此我们将从那里获得对每个请求对象的可见性。在实际场景中,您可以实现一些有用的逻辑。现在我们必须将代码挂接到操作中。挂接方式与我们在顶部部分看到的 MVC 方式略有不同。我们必须替换默认的操作选择机制。设置代码的好地方是 WebApiConfig
类。以下是显示如何操作的示例代码:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//Hook up custom action selector
config.Services.Replace(typeof(IHttpActionSelector), new ApiActionSelector());
}
}
现在当我们调用下面的操作时:
public class testController : ApiController
{
[System.Web.Http.ActionName("action1")]
public void Get()
{
}
}
我们看到执行序列击中了 ApiActionSelector
类中的 SelectAction
函数。
结论
在本例中,我们学习了如何在 MVC 和 Web API 中实现自定义操作调用者。请不要将操作调用者与操作筛选器混淆。两者的目的完全不同。