2010-10-28 41 views
1

This question让我想到了如何做相对可撤销的事情:通过javascript无缝集成服务器生成的ASP.NET中的客户端控件HTML。当然,你总是可以使用javascript/jquery /库来创建相同的显示客户端。但是大多数时候,在服务器上执行所有的渲染更容易,而不是将数据传递到必须处理用户界面和渲染的客户端控件。或者,也许你已经有很多交互性较差的服务器代码,你真的不会完全重新使用JavaScript库来添加一些更好的交互性。使用ajax更新ASP.NET服务器呈现的控件

我有一个理论,似乎工作在一个基本的概念证明。假设您想完全重新呈现基于客户端事件的服务器生成的控件的HTML,而不回发。所以使用jQuery,我有一个页面:

default.aspx: 
    <a id="link1" href="#">Click Here</a> 
    <div id="container"> 
    <asp:PlaceHolder id="MyPlaceholder" runat="server" /> 
    </div> 
    <script type="text/javascript"> 
     $(document).ready(function() { 
      $('#link1').click(function() { 
       $.ajax({ 
        url: "default.aspx", 
        type: "GET", 
        dataType: "html", 
        async: true, 
        data: { "ajax": "1" }, 
        success: function(obj) { 
        // replace the HTML 
         $('#container').html(obj); 
        } 
       }); 
      }); 
     }); 

事件导致它使用Ajax查询本身。 ,做挂羊头卖狗肉的代码隐藏是这样的:

TestUserControl ctl; 
    string ajax; 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     ctl = (TestUserControl)Page.LoadControl("TestUserControl.ascx"); 
     Myplaceholder.Controls.Add(ctl); 
     ctl.OnRender += new TestuserControl.RenderHandler(ctl_Render); 
    } 
    protected void Page_PreRender() 
    { 
     ajax = Request.QueryString["ajax"] == null ? "" : Request.QueryString["ajax"]; 
    } 
    void ctl_Render() 
    { 
     if (ajax == "1") 
     { 
      StringBuilder sb = new StringBuilder(); 
      StringWriter sw = new StringWriter(sb); 

      using (HtmlTextWriter writer = new HtmlTextWriter(sw)) 
      { 
       ctl.DoRender(writer); 
      } 

      Response.Write(sb.ToString()); 
      Response.End(); 
     } 
    } 

在TestUserControl,我揭露base.render得到输出:基本上

public void DoRender(HtmlTextWriter writer) 
    { 
     base.Render(writer); 
    } 

,如果页面被称为没有“Ajax”的查询字符串,它只是像自己一样行事。但是,当使用查询字符串时,它将截取来自我所关心的内容(称为TestUserControl.ascx的用户控件)的输出流,并呈现。这将返回给客户端,客户端会更新HTML。所有的ID都会像以前一样重新创建,因为我不是在单独渲染那个控件,而是在它自己的页面上下文中。理论上讲,ASP.NET创建的每一点魔法都应该被ajax查询重现,检索和更新。

除了效率明显不足之外,它似乎在这个小测试中运行得很顺畅。我可以完全重新使用服务器生成的HTML没有回发的控件,我写了零JavaScript。这个例子实际上并没有改变任何东西,但是传递更多参数来改变输出会很简单。

我想知道有没有人在实践中尝试过这样的事情?我可能没有想到什么潜在的问题?

如果服务器性能不是问题,看起来它可能是一种非常简单的方法,可以通过ASP.NET服务器控件的所有优点获得大量功能。但我似乎无法在实践中找到有关使用这种技术的任何讨论,所以我想知道我可能会错过什么。

回答

2

那么,对于初学者,您发送GET请求到您的页面,所以您要更新的控件将不会收到最新的表单数据。更重要的是,ViewState将会丢失,你可能不想要这样,除非你的用户控制非常简单。

您可以通过使用POST请求来解决该问题,但还存在其他潜在问题,例如,你能保证嵌入在你的用户控件中的客户端脚本再次运行,或者当你在所有浏览器上一致地更新客户端脚本吗?

幸运的是,others已经解决了这些问题。我建议你把从客户端的UpdatePanelforce a refresh内用户控件:

__doPostBack("yourUpdatePanelClientID", ""); 
+1

你知道,这来自于避免UpdatePanels的愿望,因为有很多方法在将它们与javascript和其他更新面板混合时遇到了麻烦。最后我想我只是想通过后门重新创造一个......好吧。 – 2010-10-28 18:11:15

0

如果替代方案是用一个UpdatePanel,这绝对是值得考虑局部呈现。即使您仅使用UpdatePanel更新页面的一小部分,这些更新也必须将整个ViewState发送回服务器,服务器必须run the entire page through its life cycle,呈现它,然后提取部分区域。您为了方便起见采取a significant performance hit

就你而言,由于你在ASPX pae中渲染该部分,所以仍然会导致页面生命周期命中。它没有UpdatePanel那么糟糕,但没有必要。

我发现splitting the partial rendering out to a web service or HttpHandler handler效果很好。它的很多比在WebForms中渲染partials的大多数其他方法更快,但仍允许使用用户控件进行模板的灵活性。

缺点是用户控件中的控件无法处理回发。例如,你可以重新渲染它和/或传入参数来控制渲染,但是你不能用它来渲染一个GridView并且期望它的分页链接工作。

+0

你在那里描述的技术有很多更好的想法,以及我试图完成的事情。缺点是无法处理状态/回发,这就是为什么我在提取html之前试图将其保留在其所有者页面的上下文中的原因。同样,我认为你的技术可能会导致ID冲突,因为它不再处于INamingContainer中。也就是说,ID将完全按照服务器端ID进行渲染,不是吗?无论如何,都可以管理。但是这绝对是工具箱中另一个有用的工具,我可以想到它将会有用的地方。 – 2010-11-05 20:20:05

0

我希望有更多关于将ASP.NET web表单移动到现代时代的讨论。我必须自己弄清楚所有的一切。我个人一直在寻求最简单的解决方案,并避免所有需要更多Microsoft层次的解决方案。没有任何反对MS,我只是想保持简单,并使用普通的网络标准。

到目前为止,我已经能够使用jQuery加载AJAX了解我尝试过的所有东西。没有轻拍,简单的答案,但如果你持久,你可能可以解决老派ASP.NET实践导致的任何客户端问题。

我认为最重要的事情就是停止使用ViewState。完全。这会迫使你摆脱许多可能会给客户带来问题的可怕做法。这实际上比你想象的要容易得多。在那个时候,AJAX的东西往往会起作用。即使DataGrids。做自己的分页,无论是客户端还是服务器端,都不那么困难,然后你可以在任何地方重用你的解决方案。

这些问题将来自您无法控制的第三方内容。在这些情况下,您可以使用IE开发人员工具(F12)查看ASP.NET最初发送的内容。最糟糕的情况是,你必须剔除一些JavaScript并自己运行它。在实践中,我很少需要做任何可怕的事情。我想如果你使用很多重量控制,这将是不切实际的,但在这种情况下,你已经买了农场。

相关问题