使用HTML和JavaScript返回部分视图

时间:2009-04-16 15:55:33

标签: javascript asp.net-mvc ajax

我正在进行AJAX调用(使用jQuery)来检索PartialView。与HTML一起,我想发送一个View正在显示的对象的JSON表示。我一直在使用的糟糕方式是将属性作为隐藏输入嵌入到HTML中,这很快变得笨拙并且紧密地耦合了很多东西。

我可以在HTML之后的<script>标记中发送JavaScript,但我真的很擅长将这些内容分开。这看起来像这样:

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<Person>" %>
<div class="person">
  First Name: <%= Html.TextBox("FirstName", Model.FirstName) %>
  Last Name: <%= Html.TextBox("LastName", Model.LastName) %>
</div>
<script type="text/javascript">
  // JsonSerialized object goes here
</script>

我考虑的另一个选择是对返回JsonResult的动作进行第二次AJAX调用,但这也感觉设计不好。

4 个答案:

答案 0 :(得分:2)

我认为我找到了一个非常好的方法,只需将JSON包裹在HtmlHelper扩展名中。这是班级:

using System.Web.Script.Serialization;

public static class JsonExtensions {
    public static string Json(this HtmlHelper html, string variableName) {
        return Json(html, variableName, html.ViewData.Model);
    }

    public static string Json(this HtmlHelper html, string variableName, object model) {
        TagBuilder tag = new TagBuilder("script");
        tag.Attributes.Add("type", "text/javascript");
        JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
        tag.InnerHtml = "var " + variableName + " = " + jsonSerializer.Serialize(model) + ";";
        return tag.ToString();
    }
}

您可以通过以下方式致电:

<%= Html.Json("foo") %>
<%= Html.Json("bar", Model.Something) %>

我能想到的一个问题是它不是完全完美的分离;你仍然在技术上将JavaScript放在HTML中。 但是,它不会对服务器进行额外调用,IDE中的标记仍然非常干净。

答案 1 :(得分:1)

可能不是你会得到的最优雅的答案,只是把它扔到那里:

你可以从你的动作方法返回纯粹的json,

看起来像这样的东西:

{
    Html: "<div class=\"person\"> etc...",
    Json: { // your object here
          }
}

在你的控制器中,你需要这样的东西来渲染你的观点:

var existingContext = HttpContext.Current;
var writer = new StringWriter();
var response = new HttpResponse(writer);
var httpContext = new HttpContext(existingContext.Request, response);

var viewResult = myAction(bla);

HttpContext.Current = httpContext;

viewResult.ExecuteResult(this.ControllerContext)

HttpContext.Current = existingContext;
var viewAsHtml = writer.ToString();

答案 2 :(得分:1)

和安德鲁一样的解决方案,但也许更多MVC'ish ......

创建一个继承自ViewPage的新类。重写其Render方法以呈现页面本身,然后将其填充到Andrew建议的输出中。因此,所有的黑客攻击都发生在Render方法中,它应该发生在哪里。

现在您创建的每个视图都会更改该行:

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyModel>" %>

<%@ Page Title="" Language="C#" Inherits="CustomViewPage<MyModel>" %>

我自己没有检查,但猜猜它应该有效。如果你愿意,我可以尝试构建它。

答案 3 :(得分:0)

public static string RenderPartialToString(string controlName, object viewData, object model, System.Web.Routing.RequestContext viewContext)
            {

                ViewDataDictionary vd = new ViewDataDictionary(viewData);
                ViewPage vp = new ViewPage { ViewData = vd };

                vp.ViewData = vd;
                vp.ViewData.Model = model;
                vp.ViewContext = new ViewContext();
                vp.Url = new UrlHelper(viewContext);

                Control control = vp.LoadControl(controlName);

                vp.Controls.Add(control);

                StringBuilder sb = new StringBuilder();

                using (StringWriter sw = new StringWriter(sb))
                {

                    using (HtmlTextWriter tw = new HtmlTextWriter(sw))
                    {

                        vp.RenderControl(tw);

                    }

                }

                return sb.ToString();

            }