Controller Action可以返回什么视图?

时间:2014-05-01 22:41:52

标签: asp.net-mvc

在ASP.NET MVC 5中,每个Controller Action都必须返回一个与Controller同名的View吗?

这是我的项目。有一个网页,其中包含一个将图像上传到数据库的按钮。加载网页时,我希望它显示已上传的所有图像的列表。因此,此Controller的索引(默认)操作从数据库加载图像,并返回索引视图,而索引视图又显示图像列表:

public ActionResult Index()
{
    // Load the images from the database
    var images = GetImages();

    return View(images);
}

在同一网页上,有一个按钮,允许用户将图像上传到数据库。该按钮调用Upload Action,它根据传递的“file”和“folder”参数上传文件,然后最终再次返回Index View:

[HttpPost]
public ActionResult Upload(HttpPostedFileBase file, string folder)
{
    // Upload the file from the specified folder
    // ...
    // ...
    // ...

    return Index();
}

但是,当用户点击此上传按钮时,会显示以下错误消息:

The view 'Upload' or its master was not found or no view engine supports the searched locations

但我不是要渲染名为“上传”的视图 - 我正在尝试渲染名为“索引”的视图,这就是为什么我有一行return Index();

对我出错的地方有任何帮助吗?

4 个答案:

答案 0 :(得分:1)

答案

虽然 Vitaliy Nathan A 提供了足够的答案,但我想解释为什么您的初始方法不起作用,因为这是一个很好的问题并且似乎没有意义。

要获得我们的答案,我们必须查看ASP.NET MVC source code

在我们开始之前,让我们来看看你的代码。

  1. 用户访问(或发送至/Controller/Upload
  2. 我们做了一些逻辑,然后返回Index()
  3. Index()是一种使用自己的模型返回自己视图的方法
  4. MVC无法找到“上传”视图并引发异常
  5. 出了什么问题?

    首先要知道Index() 调用并成功返回。模型对象也被传递给视图(如果找到了)。

    当您返回Index()时,它返回View()这是Controller类中的继承方法,它返回ViewResult

    ViewResult继承自ViewResultBase

    当返回ViewResult时,它会调用ExecuteResult()

    查看ExecuteResult()的源代码:

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (string.IsNullOrEmpty(this.ViewName))
        {
            this.ViewName = context.RouteData.GetRequiredString("action");
        }
        ViewEngineResult viewEngineResult = null;
        if (this.View == null)
        {
            viewEngineResult = this.FindView(context);
            this.View = viewEngineResult.View;
        }
        TextWriter output = context.HttpContext.Response.Output;
        ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
        this.View.Render(viewContext, output);
        if (viewEngineResult != null)
        {
            viewEngineResult.ViewEngine.ReleaseView(context, this.View);
        }
    }
    

    这里的关键是context.RouteData.GetRequiredString("action")。此代码获取操作名称,以便可以查找和呈现视图。请注意,它使用的是ControllerContext

    因此,您的操作实际上是在首次调用Upload()方法时设置的。如果您单步执行Index()方法,则会看到调用context.RouteData.GetRequiredString("action")将返回字符串"Upload"

    这是因为,在用户请求的上下文中,操作实际上是上传(这是他们请求的页面)。

    有趣的事实

    如果你返回Index()并且该方法碰巧改变了ViewBag(ViewData),那么无论渲染什么,ViewData都会被改变。

    如果您的Upload()执行此操作:

    ViewBag.Test = "Upload method";
    

    然后您返回Index(),而Index()执行此操作:

    ViewBag.Test = "Index method";
    

    然后Test的值将是“索引方法”

答案 1 :(得分:0)

查看View方法的文档。它有几个你可以提供的参数,其中一个是视图名称的字符串,但如果你想返回一个视图,你总是使用View()方法。

但是,如果您不想使用默认的视图名称(作为操作方法的名称),只需使用字符串指定一个新名称,如下所示:

public ActionResult Upload(HttpPostedFileBase file, string folder)
{
    return View("Index");
}

答案 2 :(得分:0)

你可以这样做:

return RedirectToAction("Index");

或:

return View("Index");

答案 3 :(得分:0)

只是旁注,您不必限制在View文件夹中显示控制器名称的视图。你可以做到

public ActionResult something()
{
    return View("../OtherView/somethingElse");
}