Disposable Canvas?

  • Thread starter Thread starter Jon Davis
  • Start date Start date
J

Jon Davis

OK, why is Canvas not IDisposable, and how do I get rid of all the Windows
handles?

I'm doing a performance test of looping through a dynamic XAML-to-JPEG
conversion. It gets to about 500 conversions and then crashes. Task Manager
says that about 6000 Windows handles were created and the count never
decrements.

My code (loop not shown):

protected System.IO.Stream GenImageStream()
{
System.IO.Stream retImageStream = null;
System.IO.StreamReader sr = new
System.IO.StreamReader("Window1.xaml");
string xaml = sr.ReadToEnd();
if (text != null)
{
xaml = xaml.Replace("{$TEXT$}", text
}
else
{
xaml = xaml.Replace("{$TEXT$}", "Enter text.");
}
sr.Close();
System.IO.MemoryStream ms = new
System.IO.MemoryStream(xaml.Length);
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
sw.Write(xaml);
sw.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
System.Windows.Controls.Canvas canvas =
(System.Windows.Controls.Canvas)
System.Windows.Markup.XamlReader.Load(ms);
canvas.Background = System.Windows.Media.Brushes.Yellow;
canvas.Measure(new System.Windows.Size(640d, 480d));
canvas.Arrange(new System.Windows.Rect(0d, 0d, 640d, 480d));
System.Windows.Media.Imaging.RenderTargetBitmap rtb
= new System.Windows.Media.Imaging.RenderTargetBitmap(
640, 480, 96d, 96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
System.Windows.Media.Imaging.JpegBitmapEncoder encoder
= new System.Windows.Media.Imaging.JpegBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb));
string fp = Request.PhysicalApplicationPath + "imgtmp\\"
+ (Guid.NewGuid()).ToString() + ".jpg";
retImageStream = new System.IO.MemoryStream();
encoder.Save(retImageStream);
retImageStream.Seek(0, System.IO.SeekOrigin.Begin);
ms.Dispose();
}

Jon
 
Hi,

Jon said:
OK, why is Canvas not IDisposable, and how do I get rid of all the Windows
handles?

I used a variation of your code to try this myself, but I was unable to
reproduce the crash behaviour your were referring to. I also used a
profiler to look out for resource leaks and I didn't find any of these
either. Here's the code I used:

private void OnButtonClick( object sender, RoutedEventArgs e) {
for (int i = 0; i < 1000; i++)
GenImageStream();
}


private static string GetXaml( ) {
StreamReader sr = new StreamReader("Canvas.xaml");
string xaml = sr.ReadToEnd( );
sr.Close( );
return xaml;
}

protected void GenImageStream( ) {
string xaml = GetXaml( );

using (MemoryStream ms = new MemoryStream(xaml.Length)) {
StreamWriter sw = new StreamWriter(ms);
sw.Write(xaml);
sw.Flush( );
ms.Seek(0, SeekOrigin.Begin);

Canvas canvas = (Canvas) XamlReader.Load(ms);
canvas.Background = Brushes.Yellow;
canvas.Measure(new Size(640d, 480d));
canvas.Arrange(new Rect(0d, 0d, 640d, 480d));
RenderTargetBitmap rtb = new RenderTargetBitmap(
640, 480, 96d, 96d, PixelFormats.Default);
rtb.Render(canvas);
JpegBitmapEncoder encoder = new JpegBitmapEncoder( );
encoder.Frames.Add(BitmapFrame.Create(rtb));
using (Stream outstream = new MemoryStream( ))
encoder.Save(outstream);
}
}


Oliver Sturm
 
Oliver Sturm said:
Hi,



I used a variation of your code to try this myself, but I was unable to
reproduce the crash behaviour your were referring to.

That's interesting. It might help if I mention I'm trying to do this on an
ASP.NET web page to see about the feasibility of dynamically-generating
images from XAML mark-up, on a heavily impacted web site. The output of
this is great and seems to be fast, it's just that it crashes after 500
times and IIS's process has 6000 Windows handles. I'm executing on Windows
Vista / IIS 7. Here's the full source. I'll take a look at yours as well,
but in the mean time ... maybe you can spot something really, really stupid
I'm doing? :)

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace ImageGenServer
{
public partial class GenImage : System.Web.UI.Page
{
private System.IO.Stream retImageStream;
protected void Page_Load(object sender, EventArgs e)
{
Gimme();
}

protected void Gimme()
{
System.Threading.Thread thread = new System.Threading.Thread(
GimmeMore);
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
while (thread.IsAlive)
{
System.Threading.Thread.Sleep(0);
}
Response.ContentType = "image/jpeg";
System.IO.BinaryReader br = new
System.IO.BinaryReader(retImageStream);
Response.BinaryWrite(br.ReadBytes((int)retImageStream.Length));
br.Close();
retImageStream.Close();
Response.Flush();

thread = null;
br = null;
retImageStream = null;

Response.End();
}

protected void GimmeMore()
{
System.IO.StreamReader sr = new
System.IO.StreamReader(Request.PhysicalApplicationPath + "Window1.xaml");
string xaml = sr.ReadToEnd();
if (Request["text"] != null)
{
xaml = xaml.Replace("{$TEXT$}", Request["text"]);
}
else
{
xaml = xaml.Replace("{$TEXT$}", "Add &quot;text=...&quot; to
querystring.");
}
sr.Close();
System.IO.MemoryStream ms = new
System.IO.MemoryStream(xaml.Length);
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
sw.Write(xaml);
sw.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
System.Windows.Controls.Canvas canvas =
(System.Windows.Controls.Canvas)
System.Windows.Markup.XamlReader.Load(
ms);
canvas.Background = System.Windows.Media.Brushes.Yellow;
canvas.Measure(new System.Windows.Size(640d, 480d));
canvas.Arrange(new System.Windows.Rect(0d, 0d, 640d, 480d));
System.Windows.Media.Imaging.RenderTargetBitmap rtb
= new System.Windows.Media.Imaging.RenderTargetBitmap(
640, 480, 96d, 96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
System.Windows.Media.Imaging.JpegBitmapEncoder encoder
= new System.Windows.Media.Imaging.JpegBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(
rtb));
string fp = Request.PhysicalApplicationPath + "imgtmp\\"
+ (Guid.NewGuid()).ToString() + ".jpg";
retImageStream = new System.IO.MemoryStream();
encoder.Save(retImageStream);
retImageStream.Seek(0, System.IO.SeekOrigin.Begin);
ms.Dispose();

}
}
}
 
Died with you code, too. I think this has to do with STA threading. Not sure
if there is such a thing as a "best practice" for STA threading on ASP.NET.

Jon


Jon Davis said:
Oliver Sturm said:
Hi,



I used a variation of your code to try this myself, but I was unable to
reproduce the crash behaviour your were referring to.

That's interesting. It might help if I mention I'm trying to do this on an
ASP.NET web page to see about the feasibility of dynamically-generating
images from XAML mark-up, on a heavily impacted web site. The output of
this is great and seems to be fast, it's just that it crashes after 500
times and IIS's process has 6000 Windows handles. I'm executing on Windows
Vista / IIS 7. Here's the full source. I'll take a look at yours as well,
but in the mean time ... maybe you can spot something really, really
stupid I'm doing? :)

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace ImageGenServer
{
public partial class GenImage : System.Web.UI.Page
{
private System.IO.Stream retImageStream;
protected void Page_Load(object sender, EventArgs e)
{
Gimme();
}

protected void Gimme()
{
System.Threading.Thread thread = new System.Threading.Thread(
GimmeMore);
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
while (thread.IsAlive)
{
System.Threading.Thread.Sleep(0);
}
Response.ContentType = "image/jpeg";
System.IO.BinaryReader br = new
System.IO.BinaryReader(retImageStream);
Response.BinaryWrite(br.ReadBytes((int)retImageStream.Length));
br.Close();
retImageStream.Close();
Response.Flush();

thread = null;
br = null;
retImageStream = null;

Response.End();
}

protected void GimmeMore()
{
System.IO.StreamReader sr = new
System.IO.StreamReader(Request.PhysicalApplicationPath + "Window1.xaml");
string xaml = sr.ReadToEnd();
if (Request["text"] != null)
{
xaml = xaml.Replace("{$TEXT$}", Request["text"]);
}
else
{
xaml = xaml.Replace("{$TEXT$}", "Add &quot;text=...&quot;
to querystring.");
}
sr.Close();
System.IO.MemoryStream ms = new
System.IO.MemoryStream(xaml.Length);
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
sw.Write(xaml);
sw.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
System.Windows.Controls.Canvas canvas =
(System.Windows.Controls.Canvas)
System.Windows.Markup.XamlReader.Load(
ms);
canvas.Background = System.Windows.Media.Brushes.Yellow;
canvas.Measure(new System.Windows.Size(640d, 480d));
canvas.Arrange(new System.Windows.Rect(0d, 0d, 640d, 480d));
System.Windows.Media.Imaging.RenderTargetBitmap rtb
= new System.Windows.Media.Imaging.RenderTargetBitmap(
640, 480, 96d, 96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
System.Windows.Media.Imaging.JpegBitmapEncoder encoder
= new System.Windows.Media.Imaging.JpegBitmapEncoder();

encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(
rtb));
string fp = Request.PhysicalApplicationPath + "imgtmp\\"
+ (Guid.NewGuid()).ToString() + ".jpg";
retImageStream = new System.IO.MemoryStream();
encoder.Save(retImageStream);
retImageStream.Seek(0, System.IO.SeekOrigin.Begin);
ms.Dispose();

}
}
}
 
Setting AspCompat="true" to the .aspx header to make the page STA threaded,
and dropping the spawning of a new thread, seemed to alleviate this
significantly. I executed 5000 times before I just killed the test (was
running low on drive space -- made that many images). Memory consumption by
the VS debugger web server did go up to 178MB and more than 1000 handles and
didn't go down after I stopped the test, so there's still a bad memory leak,
but not anything like before.

Interesting. However, now I get an error message in Visual Studio when I go
to debug:

Error connecting to undo manager of source file 'C:\Documents and
Settings\jdavis\My Documents\Visual Studio
2005\Projects\ImageGenServer\ThreadMode.aspx.designer.cs'.


Jon


Jon Davis said:
Died with you code, too. I think this has to do with STA threading. Not
sure if there is such a thing as a "best practice" for STA threading on
ASP.NET.

Jon


Jon Davis said:
Oliver Sturm said:
Hi,

Jon Davis wrote:

OK, why is Canvas not IDisposable, and how do I get rid of all the
Windows
handles?

I used a variation of your code to try this myself, but I was unable to
reproduce the crash behaviour your were referring to.

That's interesting. It might help if I mention I'm trying to do this on
an ASP.NET web page to see about the feasibility of
dynamically-generating images from XAML mark-up, on a heavily impacted
web site. The output of this is great and seems to be fast, it's just
that it crashes after 500 times and IIS's process has 6000 Windows
handles. I'm executing on Windows Vista / IIS 7. Here's the full source.
I'll take a look at yours as well, but in the mean time ... maybe you can
spot something really, really stupid I'm doing? :)

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace ImageGenServer
{
public partial class GenImage : System.Web.UI.Page
{
private System.IO.Stream retImageStream;
protected void Page_Load(object sender, EventArgs e)
{
Gimme();
}

protected void Gimme()
{
System.Threading.Thread thread = new System.Threading.Thread(
GimmeMore);
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
while (thread.IsAlive)
{
System.Threading.Thread.Sleep(0);
}
Response.ContentType = "image/jpeg";
System.IO.BinaryReader br = new
System.IO.BinaryReader(retImageStream);

Response.BinaryWrite(br.ReadBytes((int)retImageStream.Length));
br.Close();
retImageStream.Close();
Response.Flush();

thread = null;
br = null;
retImageStream = null;

Response.End();
}

protected void GimmeMore()
{
System.IO.StreamReader sr = new
System.IO.StreamReader(Request.PhysicalApplicationPath + "Window1.xaml");
string xaml = sr.ReadToEnd();
if (Request["text"] != null)
{
xaml = xaml.Replace("{$TEXT$}", Request["text"]);
}
else
{
xaml = xaml.Replace("{$TEXT$}", "Add &quot;text=...&quot;
to querystring.");
}
sr.Close();
System.IO.MemoryStream ms = new
System.IO.MemoryStream(xaml.Length);
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
sw.Write(xaml);
sw.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
System.Windows.Controls.Canvas canvas =
(System.Windows.Controls.Canvas)
System.Windows.Markup.XamlReader.Load(
ms);
canvas.Background = System.Windows.Media.Brushes.Yellow;
canvas.Measure(new System.Windows.Size(640d, 480d));
canvas.Arrange(new System.Windows.Rect(0d, 0d, 640d, 480d));
System.Windows.Media.Imaging.RenderTargetBitmap rtb
= new System.Windows.Media.Imaging.RenderTargetBitmap(
640, 480, 96d, 96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
System.Windows.Media.Imaging.JpegBitmapEncoder encoder
= new System.Windows.Media.Imaging.JpegBitmapEncoder();

encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(
rtb));
string fp = Request.PhysicalApplicationPath + "imgtmp\\"
+ (Guid.NewGuid()).ToString() + ".jpg";
retImageStream = new System.IO.MemoryStream();
encoder.Save(retImageStream);
retImageStream.Seek(0, System.IO.SeekOrigin.Begin);
ms.Dispose();

}
}
}
 
Setting AspCompat="true" to the .aspx header to make the page STA threaded,
and dropping the spawning of a new thread, seemed to alleviate this
significantly. I executed 5000 times before I just killed the test (was
running low on drive space -- made that many images). Memory consumption by
the VS debugger web server did go up to 178MB and more than 1000 handles and
didn't go down after I stopped the test, so there's still a bad memory leak,
but not anything like before.

Would like to fix that lingering memory leak. The stuff HAS to be flushed or
else it's no good for production use, unless I want to reset IIS every hour
(which I don't).

Jon

Jon Davis said:
Died with you code, too. I think this has to do with STA threading. Not
sure if there is such a thing as a "best practice" for STA threading on
ASP.NET.

Jon


Jon Davis said:
Oliver Sturm said:
Hi,

Jon Davis wrote:

OK, why is Canvas not IDisposable, and how do I get rid of all the
Windows
handles?

I used a variation of your code to try this myself, but I was unable to
reproduce the crash behaviour your were referring to.

That's interesting. It might help if I mention I'm trying to do this on
an ASP.NET web page to see about the feasibility of
dynamically-generating images from XAML mark-up, on a heavily impacted
web site. The output of this is great and seems to be fast, it's just
that it crashes after 500 times and IIS's process has 6000 Windows
handles. I'm executing on Windows Vista / IIS 7. Here's the full source.
I'll take a look at yours as well, but in the mean time ... maybe you can
spot something really, really stupid I'm doing? :)

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace ImageGenServer
{
public partial class GenImage : System.Web.UI.Page
{
private System.IO.Stream retImageStream;
protected void Page_Load(object sender, EventArgs e)
{
Gimme();
}

protected void Gimme()
{
System.Threading.Thread thread = new System.Threading.Thread(
GimmeMore);
thread.SetApartmentState(System.Threading.ApartmentState.STA);
thread.Start();
while (thread.IsAlive)
{
System.Threading.Thread.Sleep(0);
}
Response.ContentType = "image/jpeg";
System.IO.BinaryReader br = new
System.IO.BinaryReader(retImageStream);

Response.BinaryWrite(br.ReadBytes((int)retImageStream.Length));
br.Close();
retImageStream.Close();
Response.Flush();

thread = null;
br = null;
retImageStream = null;

Response.End();
}

protected void GimmeMore()
{
System.IO.StreamReader sr = new
System.IO.StreamReader(Request.PhysicalApplicationPath + "Window1.xaml");
string xaml = sr.ReadToEnd();
if (Request["text"] != null)
{
xaml = xaml.Replace("{$TEXT$}", Request["text"]);
}
else
{
xaml = xaml.Replace("{$TEXT$}", "Add &quot;text=...&quot;
to querystring.");
}
sr.Close();
System.IO.MemoryStream ms = new
System.IO.MemoryStream(xaml.Length);
System.IO.StreamWriter sw = new System.IO.StreamWriter(ms);
sw.Write(xaml);
sw.Flush();
ms.Seek(0, System.IO.SeekOrigin.Begin);
System.Windows.Controls.Canvas canvas =
(System.Windows.Controls.Canvas)
System.Windows.Markup.XamlReader.Load(
ms);
canvas.Background = System.Windows.Media.Brushes.Yellow;
canvas.Measure(new System.Windows.Size(640d, 480d));
canvas.Arrange(new System.Windows.Rect(0d, 0d, 640d, 480d));
System.Windows.Media.Imaging.RenderTargetBitmap rtb
= new System.Windows.Media.Imaging.RenderTargetBitmap(
640, 480, 96d, 96d,
System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
System.Windows.Media.Imaging.JpegBitmapEncoder encoder
= new System.Windows.Media.Imaging.JpegBitmapEncoder();

encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(
rtb));
string fp = Request.PhysicalApplicationPath + "imgtmp\\"
+ (Guid.NewGuid()).ToString() + ".jpg";
retImageStream = new System.IO.MemoryStream();
encoder.Save(retImageStream);
retImageStream.Seek(0, System.IO.SeekOrigin.Begin);
ms.Dispose();

}
}
}
 
Jon Davis said:
Setting AspCompat="true" to the .aspx header to make the page STA
threaded,
and dropping the spawning of a new thread, seemed to alleviate this
significantly. I executed 5000 times before I just killed the test (was
running low on drive space -- made that many images). Memory consumption
by
the VS debugger web server did go up to 178MB and more than 1000 handles
and
didn't go down after I stopped the test, so there's still a bad memory
leak,
but not anything like before.

Would like to fix that lingering memory leak. The stuff HAS to be flushed
or else it's no good for production use, unless I want to reset IIS every
hour (which I don't).

Jon


XAML and WPF is a desktop technology and IMO not designed and not supported
server side, note that the same applies to System.Windows.Forms. A lot of
the System.Windows namespace classes need a pumping STA thread to run in,
and the System.Windows.Markup.XamlReader should throw an exception when
called from a non-STA thread (don't know why it didn't in your case though).
The documentation should include a warning just like the one included in
Windows.Forms
<Classes within the Windows Forms namespace are not supported for use within
a Windows service. Trying to use these classes from within a service may
produce unexpected problems, such as diminished service performance and
run-time exceptions.


Willy.
 
Oliver,

I'm running your code in a console app now and watching memory consumption
go up in a similar way to IIS. Handle count is frozen solid at 151, but
memory utilization is currently at 271MB at 10000 instances of the loop.
GC.Collect() after the loop completed had no significant effect; took it to
245MB on second pass.

Jon
 
Willy Denoyette said:
XAML and WPF is a desktop technology and IMO not designed and not
supported server side, note that the same applies to System.Windows.Forms.

I know. This was a feasibility test.

Jon
 
Jon Davis said:
Oliver,

I'm running your code in a console app now and watching memory consumption
go up in a similar way to IIS. Handle count is frozen solid at 151, but
memory utilization is currently at 271MB at 10000 instances of the loop.
GC.Collect() after the loop completed had no significant effect; took it
to 245MB on second pass.

Jon

OK, I think in conclusion a service that does what I'm considering might
still be feasible but there's some plumbing to be done. If Windows itself
can clear out the memory when the process dies, which it should (haven't
tested), I should be able to use IPC to do this through a Windows Service
that proxies and controls Windows process instances that get reset now and
then (depending on non-use or memory overload). IIS never gets unloaded but
now I'm dealing with parallel "cowboy processes".

Jon
 
Willy Denoyette said:
A lot of the System.Windows namespace classes need a pumping STA thread
to run in, and the System.Windows.Markup.XamlReader should throw an
exception when called from a non-STA thread (don't know why it didn't in
your case though).

BTW as you'd see if you look at the code and comments I posted, I was
executing in STA context. Two ways of going about this: create a new thread
and set System.Threading.Thread.SetApartmentState(), or on the page
AspCompat="true".

Jon
 
Willy Denoyette said:
XAML and WPF is a desktop technology and IMO not designed and not supported
server side, note that the same applies to System.Windows.Forms.

That's a good point - but I have to wonder what MS expects people to
use if they want to generate/process images on the server side. Java
specifically has a "headless" mode so that it can perform image
manipulation for this case. It's not exactly rare to need to generate
images dynamically on the server side (CAPTCHA, reports etc) - I wonder
what the recommended technology is for this.
 
Jon Davis said:
BTW as you'd see if you look at the code and comments I posted, I was
executing in STA context. Two ways of going about this: create a new
thread and set System.Threading.Thread.SetApartmentState(), or on the page
AspCompat="true".

Jon

Yep, but executing in an STA context is not enough, you also need to make
sure the threads message queue gets pumped. Calling SetApartmentState(), to
set the apartment to STA calls CoInitilalize to enter an STA but doesn't
install a message pump, setting the AspCompat="true", on the other end,
forces the request to be handled on a thread from a dedicated STA thread
that pumps the message queue.
Willy.
 
Jon Skeet said:
That's a good point - but I have to wonder what MS expects people to
use if they want to generate/process images on the server side. Java
specifically has a "headless" mode so that it can perform image
manipulation for this case. It's not exactly rare to need to generate
images dynamically on the server side (CAPTCHA, reports etc) - I wonder
what the recommended technology is for this.

Well, not quite my domain of expertise, but I just started to look at
[1]SilverLight (aka. WPF/E) and it looks like this is what MS is heading at.
Note that there is nothing wrong in producing XAML server side, the problem
is with server side rendering. So what can be done with SilverLight is
dynamically create XAML server side and send the XAML (which is XML) to the
front end (browser or rich client) where it gets parsed and rendered. It's
also possible (but currently quite restrictive) to use SilverLight in
windowless mode to create dynamic contents that overlays HTML using DHTML.

Willy.

[1]
http://www.microsoft.com/silverlight/default.aspx
http://channel9.msdn.com/ShowForum.aspx?ForumID=38
 
Willy Denoyette said:
Well, not quite my domain of expertise, but I just started to look at
[1]SilverLight (aka. WPF/E) and it looks like this is what MS is heading at.
Note that there is nothing wrong in producing XAML server side, the problem
is with server side rendering. So what can be done with SilverLight is
dynamically create XAML server side and send the XAML (which is XML) to the
front end (browser or rich client) where it gets parsed and rendered. It's
also possible (but currently quite restrictive) to use SilverLight in
windowless mode to create dynamic contents that overlays HTML using DHTML.

But not all rendering can be done client-side. With a CAPTCHA, for
instance, it would entirely defeat the point. There are plenty of other
times when you'd want to do server-side rendering too - embedding
images in emails, etc. It's definitely a missing piece of the story.
 
Jon Skeet said:
Willy Denoyette said:
Well, not quite my domain of expertise, but I just started to look at
[1]SilverLight (aka. WPF/E) and it looks like this is what MS is heading
at.
Note that there is nothing wrong in producing XAML server side, the
problem
is with server side rendering. So what can be done with SilverLight is
dynamically create XAML server side and send the XAML (which is XML) to
the
front end (browser or rich client) where it gets parsed and rendered.
It's
also possible (but currently quite restrictive) to use SilverLight in
windowless mode to create dynamic contents that overlays HTML using
DHTML.

But not all rendering can be done client-side. With a CAPTCHA, for
instance, it would entirely defeat the point. There are plenty of other
times when you'd want to do server-side rendering too - embedding
images in emails, etc. It's definitely a missing piece of the story.

True "SilverLight" is basically client-side technology. It includes a
light-weight version of WPF - "WPF for SilverLight" to produce, parse and
render anything like vector graphics, text, animations etc.. from XAML,
while nothing stops you (I've done it with success) from using it
server-side, it lacks a great deal of what's available in WPF, notably it
doesn't include the System.Windows.Media.Imaging namespace needed to render
XAML as bitmaps, as provided by WPF, and it's precisely that stuff (among
other) that needs COM to interop with the codec's library hence the
requirement to run in a STA thread. Don't know if they plan something more
light-weight, but what's available now is definitely not usable server side.


Willy.
 
Sorry, I didn't have time to catch up with the thread again. I see that you
discussed things with others and you seem to have reached a conclusion for
your purposes, so I'm not going to try to reply to each single thought.


Oliver Sturm
 
Willy Denoyette said:
True "SilverLight" is basically client-side technology. It includes a
light-weight version of WPF - "WPF for SilverLight" to produce, parse and
render anything like vector graphics, text, animations etc.. from XAML,
while nothing stops you (I've done it with success) from using it
server-side, it lacks a great deal of what's available in WPF, notably it
doesn't include the System.Windows.Media.Imaging namespace needed to
render XAML as bitmaps,

Exactly. It also lacks 3D capabilities. For that matter, Silverlight isn't
even the same rendering codebase; in fact it has nothing in common with WPF
except shared linguistics, but even the XAML parser is different.
Silverlight is also COM-based on the outset, which is how/why it supports
being driven by JScript, although I'm not sure that matters if one can avoid
touching its COM interfaces.
Don't know if they plan something more light-weight, but what's available
now is definitely not usable server side.

Not without man-handling WPF. Which I intend to do, per my conclusion
mentioned in another sub-thread, unless they offer an ASP.NET solution
themselves.

Jon
 
Willy Denoyette said:
Yep, but executing in an STA context is not enough, you also need to make
sure the threads message queue gets pumped. Calling SetApartmentState(),
to set the apartment to STA calls CoInitilalize to enter an STA but
doesn't install a message pump, setting the AspCompat="true", on the other
end, forces the request to be handled on a thread from a dedicated STA
thread that pumps the message queue.

Once again, I had already posted in this thread that I learned that
instantiating a thread in STA context was not enough, but AspCompat="true"
behaved differently. That said, thank you for explaining what was going on
behind what I had already posted.

Jon
 
Back
Top