在ASP.NET MVC框架中,Controller和Action是核心组件,负责处理用户请求并返回响应。Controller作为MVC模式中的"控制器",协调模型和视图之间的交互,而Action则是Controller中处理具体请求的方法。
每个Controller都必须继承自System.Web.Mvc.Controller基类,这个基类提供了大量现成的方法和属性:
csharp复制public class HomeController : Controller
{
// Action方法将在这里定义
}
Controller的命名约定是以"Controller"结尾,如"HomeController"。当浏览器请求时,MVC框架会自动去掉"Controller"后缀来匹配URL。
注意:虽然可以创建不继承Controller基类的自定义控制器,但这会失去许多内置功能,如View()、Redirect()等方法。
Action是Controller中返回ActionResult(或其派生类)的公共方法:
csharp复制public ActionResult Index()
{
return View();
}
Action方法有以下关键特性:
常见的ActionResult派生类包括:
| 返回类型 | 用途描述 | 示例代码 |
|---|---|---|
| ViewResult | 返回视图 | return View(); |
| JsonResult | 返回JSON数据 | return Json(data); |
| RedirectResult | 重定向到其他URL | return Redirect("/Home"); |
| ContentResult | 返回纯文本内容 | return Content("Hello"); |
| FileResult | 返回文件 | return File(fileBytes, "application/pdf"); |
MVC框架使用路由系统将URL映射到特定的Controller和Action。默认路由模板是:
csharp复制routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
这意味着URL "/Home/Index" 会调用HomeController的Index方法。
可以通过Route特性自定义Action的路由:
csharp复制[Route("products/{productId}")]
public ActionResult Details(int productId)
{
// ...
}
提示:使用特性路由时,需要在RouteConfig.cs中启用routes.MapMvcAttributeRoutes();
MVC框架自动将请求数据绑定到Action参数,支持多种数据源:
csharp复制public ActionResult Search(string query, int page = 1)
{
// query来自查询字符串或路由
// page有默认值1
}
可以绑定复杂对象作为参数:
csharp复制public ActionResult Create(Product product)
{
// MVC会自动将表单字段映射到Product对象属性
}
过滤器可以在Action执行前后插入逻辑,常见的内置过滤器:
自定义过滤器示例:
csharp复制public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Action执行前逻辑
Log("Action starting");
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Action执行后逻辑
Log("Action completed");
}
}
对于长时间运行的操作,可以使用异步Action提高服务器吞吐量:
csharp复制public async Task<ActionResult> GetDataAsync()
{
var data = await SomeLongRunningOperationAsync();
return View(data);
}
异步Action的特点:
现代ASP.NET MVC支持依赖注入,推荐在Controller中使用:
csharp复制public class ProductsController : Controller
{
private readonly IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var products = _repository.GetAll();
return View(products);
}
}
需要在Startup.cs中配置服务:
csharp复制services.AddTransient<IProductRepository, ProductRepository>();
Controller应该保持轻量级,核心逻辑放在服务层。测试示例:
csharp复制[TestClass]
public class HomeControllerTests
{
[TestMethod]
public void Index_ReturnsViewResult()
{
// 准备
var controller = new HomeController();
// 执行
var result = controller.Index();
// 断言
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
}
可以通过以下方式共享Controller间的逻辑:
全局错误处理配置:
csharp复制public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
然后在Web.config中启用自定义错误:
xml复制<system.web>
<customErrors mode="On"/>
</system.web>
csharp复制public class BlogController : Controller
{
private readonly IBlogService _blogService;
public BlogController(IBlogService blogService)
{
_blogService = blogService;
}
[HttpGet]
public ActionResult Index(int page = 1)
{
var posts = _blogService.GetPosts(page, 10);
return View(posts);
}
[HttpGet]
[Route("blog/{slug}")]
public ActionResult Details(string slug)
{
var post = _blogService.GetPostBySlug(slug);
if (post == null) return HttpNotFound();
return View(post);
}
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
_blogService.CreatePost(post);
return RedirectToAction("Index");
}
return View(post);
}
}
症状:404错误,但Controller和Action存在
可能原因:
解决方案:
症状:表单提交后模型属性为null或默认值
可能原因:
解决方案:
优化建议:
最佳实践:
可以创建自定义ActionResult:
csharp复制public class XmlResult : ActionResult
{
private readonly object _data;
public XmlResult(object data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var serializer = new XmlSerializer(_data.GetType());
var response = context.HttpContext.Response;
response.ContentType = "application/xml";
serializer.Serialize(response.Output, _data);
}
}
使用方式:
csharp复制public ActionResult GetXml()
{
var data = GetSomeData();
return new XmlResult(data);
}
通过重写ControllerActionInvoker实现动态Action:
csharp复制public class DynamicActionController : Controller
{
protected override void HandleUnknownAction(string actionName)
{
// 自定义处理未知Action的逻辑
View(actionName).ExecuteResult(ControllerContext);
}
}
实现多语言Action:
csharp复制public class HomeController : Controller
{
public ActionResult Index()
{
var culture = Request.UserLanguages[0];
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
return View();
}
}
在ASP.NET MVC中掌握Controller和Action的使用是开发高效、可维护Web应用的关键。从基础的路由绑定到高级的自定义ActionResult,理解这些概念将大大提升开发效率。