在ASP.NETMVC和Web API框架中,动作选择器起着至关重要的作用。它负责根据HTTP请求选择相应的动作(Action)来处理请求。默认情况下,框架会根据HTTP方法、路由模板中的占位符以及控制器上动作的参数来选择动作。但是,在某些情况下,可能需要根据特定的逻辑来自定义动作选择的过程。本文将介绍如何在MVC和Web API中实现自定义动作选择器,并解释其与动作过滤器的区别。
在MVC中,可以通过继承ActionMethodSelectorAttribute
类并重写IsValidForRequest
方法来实现自定义动作选择器。下面是一个简单的示例,展示了如何仅接受AJAX请求、HTTPS连接以及特定语言(例如英语)的请求。
public class ActionDecorationAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
// 检查是否为AJAX请求
if (!controllerContext.HttpContext.Request.IsAjaxRequest())
throw new Exception("只接受AJAX调用");
// 检查是否为HTTPS请求
if (!controllerContext.HttpContext.Request.IsSecureConnection)
throw new Exception("只支持HTTPS");
// 检查用户语言是否为英语
if (controllerContext.HttpContext.Request.UserLanguages[0] != "en-US")
throw new Exception("仅限英语用户");
return true;
}
}
在上面的代码中,定义了一个名为ActionDecorationAttribute
的自定义动作选择器。它通过检查请求的类型、安全性和用户语言来决定是否接受该请求。如果请求不符合条件,将抛出异常。接下来,需要将这个自定义动作选择器应用到控制器的动作上。
public class HomeController : Controller
{
[ActionDecoration]
public ActionResult Index()
{
return new EmptyResult();
}
}
现在,当请求Index
动作时,会在执行动作之前触发ActionDecorationAttribute
类中的验证方法。
在Web API中,可以通过继承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);
}
}
在上面的代码中,定义了一个名为ApiActionSelector
的自定义动作选择器。它通过检查请求的内容来决定选择哪个动作。在实际应用中,可以在这个基础上实现更复杂的逻辑。接下来,需要在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 }
);
// 配置自定义动作选择器
config.Services.Replace(typeof(IHttpActionSelector), new ApiActionSelector());
}
}
现在,当调用以下动作时:
public class testController : ApiController
{
[System.Web.Http.ActionName("action1")]
public void Get()
{
}
}