【问题标题】:Razor view - emitting html outside Doctype tagRazor 视图 - 在 Doctype 标记之外发出 html
【发布时间】:2011-10-06 08:57:57
【问题描述】:

我正在尝试使用 razor 视图引擎编写基于模块/区域的 mvc3 CMS。我有两个布局视图,_site.cshtml 和 _modules.cshtml。 _site.cshtml 有一个 @RenderBody() 部分。我的应用程序总是调用一个名为“index.cshtml”的视图,它的布局设置为 _site.cshtml 页面。 问题:问题是我的模块/区域在 doctype 元素之前呈现 - 而不是在布局页面的 RenderBody 部分内。

【问题讨论】:

  • 你也可以发布 ~/Views/Shared/_Site.cshtml 吗?
  • 嗯,看起来不错。在我的脑海中,我想知道问题是否是由于继承语句导致它认为您正在显示的代码由于某种原因不是正文。
  • 老实说,如果不是这样,我不知道该告诉你什么。 :( 从我所看到的应该可以工作。您是否尝试过制作一个非常简单的 Hello World 视图并查看它是否正常工作?

标签: asp.net html asp.net-mvc-3 razor


【解决方案1】:

看起来您正在尝试执行的操作相当于 Html.RenderAction(或 Html.Action),那么您为什么要自己编写所有代码而不是使用内置功能?

【讨论】:

  • ASPX 视图引擎将文本写入器替换为缓冲的写入器,但 Razor 视图引擎不会。对 Response.Write 的任何直接或间接调用都将在 ASPX 中正常工作,但在 Razor 中则无法正常工作。在 ASPX 中这样做的原因纯粹是为了支持 MVC 之前的控件。
  • 调用整个 MVC 管道并非易事。我强烈建议您使用允许您使用 Action/RenderAction 的设计,或者至少查看 MVC 源代码以了解 Action/RenderAction 的作用,以便您可以在代码中复制它。
【解决方案2】:

简而言之,它是您的 Invoke() 方法! Razor 引擎通过写入内存流来工作,然后将其解析为响应。您获得该行为的原因是您的 Invoke() 方法直接写入响应流;即在解析内存流之前。

我在使用 Html.RenderAction() 时遇到了类似的行为,它指向返回 PartialView 的操作。解决方法是使用 Html.Action()。不同之处在于 Action() 返回一个字符串,该字符串附加到内存流中,而 RenderAction() 直接写入响应。

如果您发布您的 Invoke() 方法的代码,我也许可以进一步帮助您!

| -- 编辑 -- |

好的,事实证明这比最初预期的要复杂。问题是我无法让 ProcessRequest() 附加到当前响应;不过,我可能有一个解决方案。

public string ProcessRoute(ViewContext viewContext, RouteData routeData)
{
  var urlHelper = new UrlHelper(viewContext.RequestContext);
  var currentUrl = urlHelper.Action(routeData.Values["action"].ToString(),
    routeData.Values["controller"].ToString(), routeData.DataTokens);

  var stringWriter = new StringWriter();
  var simpleWorkerRequest = new SimpleWorkerRequest(currentUrl, "", stringWriter);

  var context = new HttpContext(simpleWorkerRequest);
  var contextBase = new HttpContextWrapper(context);
  var requestContext = new RequestContext(contextBase, routeData);

  var httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);
  httpHandler.ProcessRequest(context);

  context.Response.End();
  stringWriter.Flush();

  return stringWriter.GetStringBuilder().ToString();
}

上面的代码生成了一个新的请求,并将请求的 HTML 作为字符串返回。通过这样做,结果将作为当前响应的一部分附加。您现在可以重写您的 Invoke() 函数以返回一个字符串,该字符串可以显示在您的视图上。

public string Invoke(ViewContext viewContext)
{
  if (_mvcHandler == null)
  {
    var routeData = new RouteData(context.RouteData.Route,
      context.RouteData.RouteHandler);

    routeData.Values.Add("id", _id);
    routeData.Values.Add("moduleName", _moduleName);
    routeData.Values.Add("controller", _controllerName);
    routeData.Values.Add("action", _actionName);
    routeData.Values.Add("pageContext", _pageContext);

    if (!string.IsNullOrEmpty(_preferredNamespace))
    {
      routeData.DataTokens.Add("Namespaces", new[] { _preferredNamespace });
    }

    return ProcessRoute(viewContext, routeData);
  }

  return string.Empty;
}

你可能还需要改变;

mr.Invoke(ViewContext);

到;

Html.Raw(mr.Invoke(ViewContext));

为了停止 HTML 编码行为。

| -- 注意 -- |

由于我没有您的 ModuleRequests 类,因此我无法专门针对您的场景测试此代码。相反,我尽可能地复制了这个问题并解决了它。

如果您有任何问题,请告诉我。

马特

【讨论】:

  • 嘿 - 你能确定你正在输出对视图的响应吗?我在测试时做了同样的事情......即仅仅因为你调用了这个函数,并不意味着你使用它。我能描述的最好的就是期待 var testString = "hi";显示在您的页面上而不告诉它。首先,在 Invoke() 方法上设置断点并检查返回的内容;其次,使用@Html.Raw() 来显示结果。
  • 感谢 Matt 的所有帮助 - 我已设法解决所有问题。
  • 这真是个好消息!恭喜!这是一个很好的问题,但你最终到达了那里!欢迎您!
【解决方案3】:

在我尝试解决上述问题时,让我发布一个可行的第二种替代方法。

MVC 中有一个名为 Html.Partial() 的 html 扩展,它允许您使用 routedata 来返回控制器操作的结果。

因此,如果您的 AccountController 具有返回 PartialView 结果的 Register 方法,那么它将被附加到当前页面。

public class AccountController() : Controller
{
  public ActionResult Register()
  {
    return PartialView();
  }
}

对该操作的调用可能类似于:

@Html.Partial("Account", "Register");

| -- 注意 -- |

不要使用@Html.RenderPartial(),否则你会遇到和上面一样的问题! 我目前正在远离电脑发帖,所以我无法测试这个理论!

希望这会有所帮助!

马特

【讨论】:

  • 我可以看看你的 OnSaveModuleSettings() 方法吗?您从哪里获取要保存的数据?它是否正确填充?谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多