1

I'm retro-fitting a .aspx page with AJAX functionality (using VB, not C#). The codebehind populates the page with data pulled from a web-service. The page has two panels that are populted (with different data, of course) in this way. On a full page refresh, one or both panels might need to be populated. But populating Panel 2 can take a long time, and I need to be able to update panel 1 without refreshing Panel 2. Hence the need for AJAX (right?)

The solution I've come up with still has the old .aspx page with .aspx.vb codebehind, but introduces a Generic Handler (.ashx) page into the mix. Those first two components do the work on the user's first visit or on a full page refresh, but when AJAX is invoked, the request is handled by the .ashx page.

First question: Is this sound architecture? I haven't found a situation online quite like mine. Originally, I wanted to make the .aspx page into the AJAX handler by having the codebehind implement IHttpRequest, and then providing "ProcessRequest" and "IsReusable" methods, but I found I couldn't separate a regular visit to the page from an AJAX request, so my AJAX handlers took over even on the first visit to the page. Second question: Am I right to think that this approach (making the .aspx page do double-duty as the AJAX handler) will never work? Is it impossible to tell whether we're getting a full-page request or a partial-page (AJAX) request?

If the architecture is good, then I need to dynamically generate a lot of HTML in the .ashx file, right? If that is right, should I send HTML back to the client, or should I encode it in some way? I've heard of JSON encryption, but haven't figured out how to use it yet. So, Third question: Is "context.Response.Write" the only pipeline for sending data back to the client? And, if so, should I send back HTML or some kind of JSON-encoded objects?

Thanks in advance.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
nttaylor
  • 788
  • 3
  • 11
  • 25
  • 1
    A couple of questions. Was there a particular design constrained for why went with an `.ashx` handler to do the asynch stuff over a straight up `.asmx` webservice call? Is client side JS templating at all a viable option? If it is you could have a webservice that returns JSON data and you can format it to HTML client side using JavaScript and insert the new content into the DOM. – Roman Apr 07 '11 at 20:05
  • I'm not familiar with .asmx (just had to look it up!) but the web-service part of this equation is pretty straightforward. As to the JSON data, yes, I could format it into HTML with javascript on the client side, I just haven't learned how to generate JSON-encoded objects yet. – nttaylor Apr 07 '11 at 20:33
  • Which version of ASP.NET are you on? – Roman Apr 07 '11 at 21:18

4 Answers4

1

It sounds as if the page requires some AJAX functionality added to the UI.

Suggest using an UpdatePanel for each web form element that needs to have AJAXy refresh functionality. That'll save you from having to refactor a bunch of code, and introduce a whole lot of HTML creation on your .ashx.

It'll be more maintainable over the long run, and require a shorter development cycle.

p.campbell
  • 98,673
  • 67
  • 256
  • 322
  • `UpdatePanel` would probably be the easiest way to get this to work, but could have a negative impact on performance since each async request still runs the page through a full life cycle ([related question](http://stackoverflow.com/questions/1151821/advantages-and-disadvantages-of-using-ajax-update-panels-in-asp-net-application)). – Roman Apr 07 '11 at 20:11
  • My first attempt used "UpdatePanel" but I found it hopelessly complicated for my situation. I think it would be easier if the user interaction takes place in the same area on the page where the AJAX update needs to occur, but in my case, user interaction in Panel 2 (see my description of the page in my original post) is actually triggers an update to Panel 1. I've never used UpdatePanels before so maybe they could help, but I couldn't make it work in this situation that is more complicated than examples I could find on line. – nttaylor Apr 07 '11 at 20:37
0

I agree with @p.campbell and @R0MANARMY here. UpdatePanel could be the easiest approach here.

But then like me, if you don't want to go the UpdatePanel route, I don't see anything wrong with your approach. However, generating the html dynamically (entirely) at the back end is not a route I'll personally prefer (for the maintainence reasons). I'd rather prefer implementing a solution that will keep the design separate from the data.

Roman
  • 19,581
  • 6
  • 68
  • 84
Narmatha Balasundaram
  • 867
  • 3
  • 11
  • 26
  • 1
    Personally I often find Microsoft's "easy" solutions to things to be much more difficult than doing the coding myself, b/c when I code it myself I usually have a better idea of what is going on. – nttaylor Apr 07 '11 at 20:38
  • That said, I would love a solution that would keep the design separate from the data. Writing the HTML out on the backend also seemed very ugly to me. Suggestions? Is this where I'm supposed to use JSON? – nttaylor Apr 07 '11 at 20:39
  • One possible solution for this - 1.to have the html mark up on the front end with placeholders for data 2. Use JQuery to trigger a Ajax server side data for call 3. This server side call could return JSON. 4. Javascript function that parses the JSON received and fill into the placeholders – Narmatha Balasundaram Apr 08 '11 at 12:59
0

JSON is not for that purpose, it is to pass objects serialized with a nice light weight notation, is you need to stream dinamically generated html using ashx, response.Write is what you have. You may want to take a look at MVC

Or you could use jquery if it's just html, the simpliest would be the load function, or you can look into Ajax with jquery. Since the ashx can be served as any resource it can be used in the load function.

Ernesto
  • 1,523
  • 1
  • 14
  • 32
0

As pointed out by others, UpdatePanel would be a easier way - but you need to use multiple update panels with UpdateMode property set as conditional. Then you can trigger the update-panel refresh using any button on the page (see AsyncPostBackTrigger) or even using java-script (see this & this). On the server side, you may decide what has triggered the partial post-back and act accordingly by bypassing certain code if not needed.

You can also go with your approach - trick here is to capture the page output using HttpServerUtility.Execute in your ashx and write it back into the response (see this article where this trick has been used to capture user control output). Only limitation with this approach is that you can only simulate GET requests to your page and so you may have to change your page to accept parameters via query string. Personally, I will suggest that you create a user control that accept parameters via method/properties and will generate necessary output and then use the control on your page and in ashx (by dynmaically loading it in a temperory page - see this article).

EDIT: I am using jquery to illustrate how to do it from grid-row-view.

$(document).ready(function() {
   $("tr.ajax-grid-row").click(function() {
       $("#hidden-field-id").val($(this).find(".row-id").val()); // fill hidden filed
       $("#hidden-button-id").click(); // simulate button click
   });
});

You can place above script in the head element in markup - it is assuming that you have decorated each grid-row-view with css class "ajax-grid-row" and each row will have hidden field decorated with css class "row-id" to store row identifier or the value that you want to pass to server for that row. You can also use cell (but then you need to use innerHTML to get the value per row). "hidden-field-id" and "hidden-button-id" are client ids for hidden field and submit button - you should use Control.ClientID to get actual control ids if those are server controls.

VinayC
  • 47,395
  • 5
  • 59
  • 72
  • Thank you for the help: Still trying madly to implement your first suggestion, but there are complications. One is that the controls are dynamically generated, and another is that they are not normal buttons. They are rows in a grid view, and each row has to send a different parameter to whatever subroutine will be controlling the refresh. So far all I have is `For Each drRow as GridViewRow in MyGridView: Dim trigger As System.Web.UI.AsyncPostBackTrigger = New System.Web.UI.AsyncPostBackTrigger(): scriptManager1.RegisterAsyncPostBackControl(drRow)` – nttaylor Apr 11 '11 at 20:11
  • But how do I dynamically add a click handler to a GridViewRow (which has no ".Click" attribute), and then what goes in the javascript on the client side? Please help if you can! I'm still very confused! – nttaylor Apr 11 '11 at 20:12
  • @Noel, you are probably doing it in a hard way. What you should do is to have a hidden field and hidden ASP.NET submit button in UpdatePanel. Now all you have to do is to write java-script to fill the hidden field to tell which row and then simulate the click of button. Please see edit in my answer. Hope this helps! – VinayC Apr 12 '11 at 04:18
  • Dear VinayC, thank you for your help. I finally got it to work, although the performance is a little slow. This excercise has only left me with more questions, however. Now I'm trying to do Ajax calls without UpdatePanels by making my aspx page implement IHttpHandler like I described above. I followed your links, but it wasn't quite working. Would you mind reading my new question at http://stackoverflow.com/questions/5656474/using-aspx-page-as-ajax-event-handler ? You've been the most help of anyone so far, so it would be great if you had time. Thank you! – nttaylor Apr 13 '11 at 22:37