为什么在ASP.NET Core Web API中要从ControllerBase派生而不是Controller?

131
我正在遵循此教程创建ASP.NET Core Web API,并在添加控制器的部分中,教程提供了代码以替换控制器的模板代码。其中一件真正引起我的注意的事情是,在模板代码中,我获得了:
TodoController : Controller

然后在教程代码中,我应该使用以下代码替换它:

[Route("api/[controller]")]
[ApiController]
TodoController : ControllerBase

我非常想知道为什么Web API控制器需要从ControllerBase派生而不是从Controller派生。这样做的原因是什么?


3
请注意,您可以创建一个不从任何类派生的控制器,至少在 .net 5+ 中可以工作,我不知道早期版本。 - Mark Adamson
5个回答

178
为什么在Web API控制器中,需要从ControllerBase派生,而不是Controller
这并非严格必要,只是更加准确。Controller类是从ControllerBase派生的,只是添加了一些支持视图的成员。
基本上:
public abstract class Controller : ControllerBase
{
    public dynamic ViewBag { get; }
    public virtual ViewResult View(object model) { }
    // more View support stuff
}

当你编写一个API时,ControllerBase更符合你的要求,但两者都可以工作。
文档中可以看到:

不要通过从Controller类派生来创建Web API控制器。Controller派生自ControllerBase并添加了对视图的支持,因此它用于处理Web页面,而不是Web API请求。这个规则有一个例外:如果你计划同时用于视图和Web API的同一个控制器,那么从Controller派生它

我记得在最初的MVC版本中没有ControllerBase,它是后来添加的。因此,命名/继承结构稍微有些奇怪。

9
正如ControllerBase类的摘要所述:ControllerBase - “用于MVC控制器但不支持视图的基类。” - Márk Gergely Dolinka

28

6
除非您在同时用于 API 请求和视图的控制器相同,否则不需要这样做。根据您提供的链接: "有一个例外是:如果您计划将相同的控制器用于视图和Web API,则从Controller派生它。" - hacker

1

控制器基类抽象类

控制器抽象类继承自控制器基类抽象类,因此支持创建视图,但不建议在API中创建视图。

控制器基类抽象类具有成员[属性、方法],但没有实现。

public abstract class ControllerBase{
        public HttpResponse Response { get; }
        public HttpRequest Request { get; }
        public HttpContext HttpContext { get; }
        public virtual RedirectToActionResult RedirectToAction(string actionName);}

ControllerBase拥有客户端和服务器端之间的所有请求和响应。

控制器抽象类

控制器抽象类使我们能够创建视图以在客户端显示数据,它派生自ControllerBase抽象类。

public abstract class Controller : ControllerBase{
        public dynamic ViewBag { get; }
        
        public ViewDataDictionary ViewData { get; set; }
       
        public ITempDataDictionary TempData { get; set; }
}

https://newbedev.com/why-derive-from-controllerbase-vs-controller-for-asp-net-core-web-api


控制器抽象类支持视图,而ControllerBase抽象类不支持创建视图。 - Ragab Mohamad

-2
另一个重要的区别是,ControllerBase 是抽象类,因此它不实现 Dispose 方法。所以你需要自己处理。请参见 SO entry

1
我很好奇这是如何尝试回答问题的? - Jim Aho
@JimAho 因为这是继承自ControllerBase而不是Controller的另一个原因。在已链接的条目中解释得很清楚。 - Emil
1
最好将其作为评论留下,而不是在这个已经受欢迎的回答上进行回复。 - Jim Aho

-4

当您将控制器更改为ControllerBase时,下面的Index方法会抛出一个错误“编译器错误CS0103”,即“名称'identifier'不存在于当前上下文中”,

    public IActionResult Index()
    {
    return View();
    }

1
我很好奇这是如何尝试回答问题的? - Jim Aho
这是控制器和控制器基础之间不同的事情之一。它直接回答了问题。这就是它们不可互换的原因。这个问题并不像大多数人想象的那样非黑即白。感谢您的提问。 - Marc Guvenc
1
虽然这仍然不能算是对原问题的完整回答,只是增加了一些额外信息,所以更适合作为评论。 - Jim Aho
1
虽然这并不是对原问题的完整回答,只是增加了一些额外的信息,所以更适合作为评论。 - undefined
Jimbo,你看看,如果你想从IActionResult返回一个视图,你不能使用ControllerBase,但是你可以使用Controller。这是在Core中常见的方法。这是一个回答问题的不同之处。 - Marc Guvenc
Jimbo,看这个,如果你想从一个IActionResult返回一个视图,你不能使用ControllerBase,但你可以使用Controller。这是Core中常见的一种方法。这是一个回答问题的不同之处。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接