PDA

View Full Version : [CLOSED] When to use BaseControl Render() vs ToScript() for ASMX/ASHX type scenarios



anup
May 13, 2012, 2:20 PM
Hi,

For Ext.NET 2, I can see at least the following ways (I am sure there are more) to create a component on the server during an AJAX request and returning it to the client:

Using .Render() on a control and just returning a new DirectResponse() (e.g. ASMX)
Using return new DirectResponse(component.ToScript()); (e.g. ASMX)
Using return new DirectResponse(component.ToScript()).Return(); (e.g. ASHX)
ComponentLoader.Render(component) (e.g. Panel Loader handler)


Regarding 4), I've only just come across it, so need to look into it further, but it looks to me like a great new feature. After only a brief look, I can see why 4) may need to remain different to the others (i.e. it sends back a config object/JSON rather than a script to execute, so it needs to be explicitly loaded/used by the calling script - probably by Ext JS's own loader by the looks of it).

However, for the first 3, they all return JavaScript to be executed by the Ext.NET client side framework. However, I can't get option 1) to work for ASHX (see example below) but I can't tell if that is a bug or my misunderstanding of some important differences under the hood.

It would be nice and clean to use option 1) in both ASMX and ASHX approaches if possible (I acknowledge that if in ASHX type of scenario, then using new DirectResponse().Return() would be needed because ProcessRequest() doesn't have a return type.)

If 1) not working for ASHX is actually a bug and can be fixed, then I guess the next question would then be which should be considered "best" or "recommended" way, given both .ToScript and .Render are public methods? .Render() looks cleaner, but maybe I have missed scenarios where it cannot be used and .ToScript needs to be used instead?

Examples:

As suggested by Vladimir on this forum post http://forums.ext.net/showthread.php?18961-Components-created-in-a-Direct-Response-do-not-always-generate-correct-script it is possible to call .Render() on a component and return new DirectResponse() which looks cleaner than doing return new DirectResponse(component.ToScript());

Example:



[WebMethod]
public DirectResponse GetServerTimeWindow()
{
new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = DateTime.Now.ToString()
}.Render();

return new DirectResponse();
}


That's nice, and clean. So I tried it for an ASHX. It is virtually the same except because ProcessRequest has no return type, I use new DirectResponse().Return():



public void ProcessRequest(HttpContext context)
{
new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = DateTime.Now.ToString()
}.Render();

new DirectResponse().Return();
}


But if I do this it doesn't work. Looking at the response in FireBug, the window has come through twice with a < string > in the middle (I added line breaks/formatting to help make it more readable):



{
script:"Ext.net.ResourceMgr.destroyCmp(\"App.MyWindow\");
Ext.create(\"Ext.window.Window\",{id:\"MyWindow\",height:100,hidden:false,html:\"13/05/2012 14:33:30\",renderTo:Ext.getBody(),width:200,title:\"Server time\",iconCls:\"#Time\"});
<string>
Ext.net.ResourceMgr.destroyCmp(\"App.MyWindow\");
Ext.create(\"Ext.window.Window\",{id:\"MyWindow\",height:100,hidden:false,html:\"13/05/2012 14:33:30\",renderTo:Ext.getBody(),width:200,title:\"Server time\",iconCls:\"#Time\"});"
}


I tried to follow the code a bit but couldn't tell if that was bug or I have missed a difference about when to use the two different approaches because the first bit in the JavaScript above looks like what I'd expect, while the second bit looks like the start of what I'd expect if it were an ASMX returning the response in XML format...

So, for an ASHX, I find I have to stick with the way I used to do it in Ext.NET 1: new DirectResponse(myComponent.ToScript()).Return(); Example:



public class ServerTimeHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var window = new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = DateTime.Now.ToString()
};

new DirectResponse(window.ToScript()).Return();
}

public bool IsReusable
{
get { return false; }
}
}

Daniil
May 14, 2012, 9:38 AM
Hi,


I can see at least the following ways (I am sure there are more)

Generally, no. You have counted all main ways. Though you could look also into UserControlRenderer. It might be helpful in some scenarios.
http://forums.ext.net/showthread.php?18270&p=80829&viewfull=1#post80829

Though I'm not sure it will work in services/handlers, needs to check.


4. ComponentLoader.Render(component) (e.g. Panel Loader handler)

Regarding 4), I've only just come across it, so need to look into it further, but it looks to me like a great new feature. After only a brief look, I can see why 4) may need to remain different to the others (i.e. it sends back a config object/JSON rather than a script to execute, so it needs to be explicitly loaded/used by the calling script - probably by Ext JS's own loader by the looks of it).

Yes, it produces a widget config. It's mainly used in ComponentLoader with Mode="Component". But, certainly, it can be used in some different way as you can deal with that widget config as you wish.


the next question would then be which should be considered "best" or "recommended" way, given both .ToScript and .Render are public methods? .Render() looks cleaner, but maybe I have missed scenarios where it cannot be used and .ToScript needs to be used instead?


There is no principal difference, there is the same internally. So, you can use the option which is more comfortable for you.



1. Using .Render() on a control and just returning a new DirectResponse() (e.g. ASMX)

If 1) not working for ASHX is actually a bug and can be fixed

Vladimir will look into it. Personally, I believe it can be fixed and, certainly, it would be great to have this option working in both - web services and handlers.

We will notice you.

anup
May 14, 2012, 10:43 AM
Thanks for the detailed response. Will wait on the fix then and then decide which one to use...

I guess in the book that I'm writing I'll mention both approaches then. I am thinking readers might naturally wonder if there are two, which to use when. I can say either is fine.

I guess in theory (not tried it) in an ASHX or an ASMX etc one could create multiple components and render all of them and not put them inside a container (e.g. create 2 separate windows). In that case, calling .ToScript() doesn't help (you'd need to manually concatenate them and add that to the DIrectResponse constructor) and using .Render() is cleaner in that regards.

Hm... I wonder then: is making ToScript() internal rather than public useful? (It risks breaking backward compatibility of course, but may have the benefit that developers are encouraged to consistently just use one way, .Render())

Vladimir
May 14, 2012, 10:47 AM
Hi,

DirectResponse issue in conjunction with http handler is fixed

Also, there is another case: json webservice (i don't mind WCF case because WCF allows to manage by a response as you wish)
To work with json webservice you have to:
- set Json="true" for direct request
- WebMethod should have string return type
- use ToString method of DirectResponse



[WebMethod]
public string GetServerTimeWindow()
{
new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = DateTime.Now.ToString()
}.Render();


return new DirectResponse().ToString();
}

anup
May 14, 2012, 6:20 PM
Many thanks for fixing so quickly. Sorry it took a while to respond. I've tried it and it seems fine now. You can mark as closed.

As for whether to recommend to use .ToScript() or .Render() I will mention both in the book; I'll probably suggest .Render() as it feels cleaner.

It is also useful if people want to do something like the following (though I would think it should not happen too often, but who knows!)



public void ProcessRequest(HttpContext context)
{
new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = DateTime.Now.ToString()
}.Render();

new Window("Server time", Icon.Time)
{
ID = "MyWindow2",
X = 10,
Y = 10,
Html = DateTime.Now.ToString()
}.Render();

new DirectResponse().Return();
}

anup
May 14, 2012, 6:37 PM
Sorry, I forgot about MVC Controller. I tried the following and it works, as expected:



//
// GET: /ServerTime/GetTime
public ActionResult GetTime()
{
var window = new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = string.Format("Server time is {0}", DateTime.Now)
};

return new AjaxResult(window.ToScript());
}

But if I use .Render() instead, and return new AjaxResult() then it doesn't work



//
// GET: /ServerTime/GetTime
public ActionResult GetTime()
{
new Window("Server time", Icon.Time)
{
ID = "MyWindow",
Html = string.Format("Server time is {0}", DateTime.Now)
}.Render();

return new AjaxResult();
}


If I do the above I see the same < script > tag appearing as per the first bug report above (line breaks added):



{
script:
"Ext.net.ResourceMgr.destroyCmp(\"App.MyWindow\");
Ext.create(\"Ext.window.Window\",{id:\"MyWindow\",height:100,hidden:false,html:\"Server time is 14/05/2012 19:28:23\",renderTo:Ext.getBody(),width:200,title:\"Server time\",iconCls:\"#Time\"});
<string>
Ext.net.ResourceMgr.destroyCmp(\"App.MyWindow\");
Ext.create(\"Ext.window.Window\",{id:\"MyWindow\",height:100,hidden:false,html:\"Server time is 14/05/2012 19:28:23\",renderTo:Ext.getBody(),width:200,title:\"Server time\",iconCls:\"#Time\"});"
}

Vladimir
May 14, 2012, 7:09 PM
Thanks for the report. AjaxResult is fixed

anup
May 14, 2012, 7:28 PM
I can't keep up with your rapid fixing :) Many thanks. Really appreciated.

Daniil
May 14, 2012, 7:42 PM
I guess in theory (not tried it) in an ASHX or an ASMX etc one could create multiple components and render all of them and not put them inside a container (e.g. create 2 separate windows). In that case, calling .ToScript() doesn't help (you'd need to manually concatenate them and add that to the DIrectResponse constructor) and using .Render() is cleaner in that regards.

Hm... I wonder then: is making ToScript() internal rather than public useful? (It risks breaking backward compatibility of course, but may have the benefit that developers are encouraged to consistently just use one way, .Render())

Well, we think there might be scenarios when a developer will need a widget creation script as a string to manage that string as he wish.

And the backwards compatibility aspect you mentioned is also important.

So, combining these two arguments we would prefer to keep ToScript public.

anup
May 15, 2012, 12:06 AM
That's fair enough. And you make a good point about developers possibly wanting to manage their own string; now that you mention it you could insert your own scripts to execute; or even cache them more efficiently as strings into Session or Cache etc.

Thank you both for clarifying on these things; its been useful for me, not just for the chapter on AJAX I am writing but given me some ideas to improve my production code :)