This question got me thinking about how one might go about doing the relatively undoable: seamlessly integrate server-generated HTML from ASP.NET with client-side control via javascript. Sure, you can always use javascript/jquery/libraries to create the same display client-side. But much of the time, it's easier to do all the rendering on the server instead of just passing data to a client-side control which must handle the user interface and rendering. Or maybe you've already got a lot of less-interactive server code that you'd really rather not completely re-do using javascript libraries to just add some better interactivity.
I had a theory which seems to work in a basic proof of concept. Suppose you want to completely re-render the HTML of a server-generated control based on a client-side event, without posting back. So using jquery, I have a page:
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);
}
});
});
});
The event causes it to query itself with ajax. The codebehind that does the trickery is like this:
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();
}
}
In TestUserControl, i expose base.render to get the output:
public void DoRender(HtmlTextWriter writer)
{
base.Render(writer);
}
Basically, if the page is called without the "ajax" querystring, it just acts like itself. But when that querystring is used, it intercepts the output stream from the content I am concerned with (a usercontrol called TestUserControl.ascx) and renders just that. This is returned to the client, which updates the HTML. All the IDs will be recreated exactly as before since I am not trying to render just that control in isolation, but in context of its own page. Theoretically, every bit of magic created by ASP.NET should be reproduced, retrieved and updated by the ajax query.
A开发者_如何学编程part from the obvious lack of efficiency, it seems to work swimmingly in this little test. I can completely rerender the control using the server generated HTML without a postback and I've written zero javascript. This example doesn't actually change anything, but it would be simple to pass more parameters to change the output.
I was wondering if anyone had tried anything like this in practice? What potential problems might I not be thinking of?
If server performance is not an issue, it seems like it might be quite easy way to get a heck of a lot of functionality with all the benefits of ASP.NET server controls. But I can't seem to find any discussion of using this technique in practice so I am wondering what I might be missing.
Well, for starters, you're sending a GET
request to your page, so the control you want to update won't receive up-to-date form data. More importantly, ViewState will be lost and you probably don't want that, unless your user control is very simple.
You could work around the problem by using a POST
request, but there are other potential issues, e.g. can you guarantee that the client scripts embedded in your user control either run again or don't when you update it, consistently, on all browsers?
Fortunately, others have already solved those problems. I'd suggest you place your user control inside an UpdatePanel and force a refresh from the client side:
__doPostBack("yourUpdatePanelClientID", "");
If the alternative is using an UpdatePanel, it's definitely worthwhile to consider partial rendering. Even if you're only updating a small portion of a page with the UpdatePanel, these updates must send the entire ViewState back to the server, the server must run the entire page through its life cycle, render it, and then extract the partial area. You take a significant performance hit for its convenience.
In your case, you're still incurring a page life cycle hit since you're rendering that partial within an ASPX pae. It's not as bad as the UpdatePanel, but unnecessary.
I've found that splitting the partial rendering out to a web service or HttpHandler handler works well. It's much faster than most other methods for rendering partials in WebForms, but still allows the flexibility of using User Controls for templating.
The drawback is that controls inside the User Control cannot handle PostBacks. You can definitely re-render it and/or pass parameters in to control its rendering, but you can't use this to render a GridView and expect its paging links to work, for example.
I wish there was more discussion about the topic of moving ASP.NET web forms into the modern era. I've had to figure out most everything on my own. I personally strive for the simplest solutions, and avoid all solutions that require layering on even more Microsoft. Nothing against MS, I just want to keep it simple and use ordinary web standards.
So far, I've been able to AJAX down everything I've tried, using jQuery load. There are no pat, simple answers, but if you are persistent, you can probably solve any client side problem resulting from old school ASP.NET practices.
I think the number one most important thing to do is stop using ViewState. Completely. This will force you out of many terrible practices that would cause you problems on the client. This is actually easier to do than you might think. And at that point, AJAXing stuff down will usually just work. Even DataGrids. Do your own paging, whether client- or server-side, it's not that hard, and then you can reuse your solution everywhere.
The problems will come from third party stuff that you have no control over. In those cases you can make use of IE developer tools (F12) to see what ASP.NET was originally sending down. Worst case, you'll have to scrape out some JavaScript and run it yourself. In practice I rarely have to do anything that terrible. I suppose if you are using a lot of heavy weight controls this would be impractical, but in that case you've already bought the farm.
精彩评论