【问题标题】:How do I determine which View is used when calling View(Object model)调用 View(Object model) 时如何确定使用哪个 View
【发布时间】:2013-10-25 16:04:06
【问题描述】:

首先,一些上下文:

  • 语言 - C#
  • 平台 - .Net Framework 4.5
  • 项目类型 - ASP.Net MVC 4

我正在尝试确定 MVC 项目中的哪个视图正在处理对以下方法的显式调用。该方法的 MSDN 文档在这里:http://msdn.microsoft.com/EN-US/library/dd492930.aspx

protected internal ViewResult View(
    Object model
)

原作者使用视图生成带有第三方库的 PDF 文件。我需要修改视图以包含更多信息。

问题:我找不到要修改的视图。他们有数百个,而且(恕我直言)他们的名字和组织都很差。生成 PDF 的基本过程如下所示。我在第 3 步和第 4 步之间感到困惑。

  1. 一个实体的 ID 被传递给一个 ActionResult
  2. 从后备存储中检索实体
  3. 模型传递给上面提到的Controller.View方法:
    var viewModel = 视图(模型);
    var xmlText = RenderActionResultToString(viewModel);
  4. 生成的 ViewResult 与 ControllerContext 的实例一起使用以生成 HTML,就像浏览器请求一样。
  5. 生成的 HTML 被传递到第三方工具并转换为 PDF。

我非常清楚地了解其他一切。我不明白的是,对 View(model) 的调用如何确定返回 ViewResult 时使用哪个 View 文件。非常感谢任何帮助!

我将下面的代码包括在内,以防它帮助任何人确定答案。

ActionResult:

public ActionResult ProposalPDF(String id, String location, bool hidePrices = false)
{
    var proposal = _adc.Proposal.GetByKey(int.Parse(id));

    var opportunity = _adc.Opportunity.GetByKey(proposal.FkOpportunityId.Value);
    ViewData["AccountId"] = opportunity.FkAccountId;
    ViewData["AccountType"] = opportunity.FkAccount.FkAccountTypeId;

    ViewData["Location"] = location;
    ViewData["HidePrices"] = hidePrices;
    return ViewPdf(proposal);
}

ViewPDF 方法:

protected ActionResult ViewPdf(object model)
{
    // Create the iTextSharp document.
    var document = new Document(PageSize.LETTER);

    // Set the document to write to memory.
    var memoryStream = new MemoryStream();
    var pdfWriter = PdfWriter.GetInstance(document, memoryStream);
    pdfWriter.CloseStream = false;
    document.Open();

    // Render the view xml to a string, then parse that string into an XML dom.
    var viewModel = View(model);
    var xmlText = RenderActionResultToString(viewModel);

    var htmlPipelineContext = new HtmlPipelineContext();
    htmlPipelineContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());

    //CSS stuff
    var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(false);
    var cssResolverPipeline = new CssResolverPipeline(cssResolver, new HtmlPipeline(htmlPipelineContext, new PdfWriterPipeline(document, pdfWriter)));

    var xmlWorker = new XMLWorker(cssResolverPipeline, true);
    var xmlParser = new XMLParser(xmlWorker);

    xmlParser.Parse(new StringReader(xmlText));

    // Close and get the resulted binary data.
    document.Close();

    var buffer = new byte[memoryStream.Position];
    memoryStream.Position = 0;
    memoryStream.Read(buffer, 0, buffer.Length);

    // Send the binary data to the browser.
    return new BinaryContentResult(buffer, "application/pdf");
}

RenderActionResultToString 辅助方法:

protected string RenderActionResultToString(ActionResult result)
{
    // Create memory writer.
    var sb = new StringBuilder();
    var memWriter = new StringWriter(sb);

    // Create fake http context to render the view.
    var fakeResponse = new HttpResponse(memWriter);
    var fakeContext = new HttpContext(System.Web.HttpContext.Current.Request, fakeResponse);
    var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), this.ControllerContext.RouteData, this.ControllerContext.Controller);
    var oldContext = System.Web.HttpContext.Current;
    System.Web.HttpContext.Current = fakeContext;

    // Render the view.
    result.ExecuteResult(fakeControllerContext);

    // Restore data.
    System.Web.HttpContext.Current = oldContext;

    // Flush memory and return output.
    memWriter.Flush();
    return sb.ToString();
}

【问题讨论】:

  • varAR 将是一个 ActionResult,或者更具体地说,是一个 BinaryContentResult。我不知道我会询问哪种类型的属性以确定使用了哪个视图文件。我错过了什么吗?

标签: c# asp.net-mvc asp.net-mvc-4 model-view-controller viewresult


【解决方案1】:

我不确定确切你在问什么,但是,当你调用 View(model) 时,选择的视图是基于约定的。

这是一个例子:

public class HerbController : Controller {
    public ActionResult Cilantro(SomeType model) {
        return View(model)
    }
}

这将在名为 Herb (Views/Herb/Cilantro.cshtml) 的文件夹中查找名为 Cilantro.cshtml 的视图文件。该框架还将在 Shared 目录中查找,以防它是要在多个结果之间共享的视图。

但是,您可能还想查看Global.asax 文件,以查看是否为视图引擎设置了任何自定义视图路径。我上面给出的示例基于 ASP.NET MVC 的默认约定。如果需要,您可以覆盖它们以更好地满足您的需求。

【讨论】:

  • 我要问的是如何在不遵守约定的情况下找到视图文件。我最终搜索了模型的完整类型名称,即“CRM.Data.Proposal”。我确实在 .aspx 文件中得到了搜索结果,结果就是这样。但是,如果这种方法不起作用,那么仔细检查 Global.asax 文件中的数十个自定义路由将是下一个方法。谢谢!
【解决方案2】:

视图的约定是它们位于以控制器命名的文件夹中(没有“控制器”),并且该文件夹中的 .cshtml 文件以调用操作命名。在你的情况下,应该是:

~/Views/[Controller]/ProposalPdf.cshtml

【讨论】:

  • 谢谢。我应该提到我知道这些约定。他们没有被遵守。不管怎么说,还是要谢谢你。有大量的自定义路由。下次我会尝试在我的问题中提供更好的上下文。我知道给出一个完全有效的答案是多么烦人。
【解决方案3】:

确定将使用哪个视图模板的逻辑在调用返回的ViewResult

var viewModel = View(model);

如何选择视图由配置的 ViewEngine(s) 决定,但它将使用当前的 AreaControllerAction 路由值来确定应该提供哪个视图。

ProposalPDF 动作的路由值取决于您的路由配置方式,但假设默认设置,动作路由值将是 ProposalPDF,控制器路由值将是控制器类的名称此操作所在的位置(减去控制器后缀),并且区域将是控制器所在的区域文件夹,如果在默认控制器文件夹中,则值为空字符串。然后使用这些路由值,将使用以下约定在 Views 文件夹中查找视图

~/Views/{Area}/{Controller}/{View}.cshtml

总是有 Glimpse 可以帮助提供运行时诊断,例如使用哪个视图文件来提供返回的页面,尽管我不确定这会是什么样子ViewResult 在内部执行以提供文件的内容。

【讨论】:

  • 没有问题,很乐意提供帮助。 Glimpse 也可以在这种情况下为您提供帮助
猜你喜欢
  • 2012-11-22
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多