views:

1233

answers:

5

According to MSDN, it is not a particularly good idea to use classes within the System.Drawing namespace in a Windows Service or ASP.NET Service. Now I am developing a class library which might need to access this particular namespace (for measuring fonts) but it cannot be guaranteed that the host process is not a service.

Now there is a less optimal method I can fall back to if System.Drawing is unavailable, but if it is possible, I would rather use classes in System.Drawing. So what I would like to do is to determine at runtume if System.Drawing is safe or not, and if it is, use it, otherwise fall back to the suboptimal option.

My problem is: How could I possibly detect if System.Drawing is safe to use?

I think I should either

  • Detect if the current process is a Windows Service or ASP.NET service
  • Detect if GDI is available
  • Or maybe there is a way to ask System.Drawing.dll itself if it is safe to use

Unfortunately, I cannot come up with a way to implement any of these approaches. Does anyone have any idea?

+1  A: 

You could use TextRenderer instead. I know it's weird to use something from System.Windows.Forms in ASP.NET, but it doesn't appear to have the same warning about not being supported in ASP.NET. I have used both TextRenderer and Graphics.MeasureString to measure strings in ASP.NET applications, so they both work. I had never seen the warning about System.Drawing not being advisable in ASP.NET.

TextRenderer is a lot slower than Graphics.MeasureString, FWIW.

MusiGenesis
System.Drawing is available in ASP.NET web applications, but not in ASP.NET web services.
DrJokepu
Not sure I follow you. System.Drawing is available from ASP.NET web applications and ASP.NET web services. I just tried it out to make sure.
MusiGenesis
It is indeed available, it's just that it is not advised to use it. Check out http://msdn.microsoft.com/en-us/library/system.drawing.aspx (look for a big blue box)
DrJokepu
I'd go with TextRenderer then, on the grounds that MSDN doesn't say not to.
MusiGenesis
Not sure where you'd get the Font or Size without going into System.Drawing....
Mark Brackett
@Mark: very true.
MusiGenesis
A: 

You might be able to copy the System.Drawing.dll to the bin of your application and then use it that way. That might guarantee its availability.

Just right click on the reference in your application and change the option for Copy Local to true.

I may be misunderstanding the question though...

Hugoware
The problem is not the availability as System.Drawing.dll is part of the .NET Framework. The problem is that without GDI being present, it cannot function properly.
DrJokepu
Right - I understand now
Hugoware
A: 

It might be something to do with the GDI subsystem needing an STA thread. If this is the case, investigate specifying ASPCOMPAT=TRUE in your @PAGE directive for the aspx page involved. This will run the aspx page in an STA thread, IIRC.

-Oisin

x0n
+7  A: 

To clear up any confusion, System.Drawing does work under ASP.NET and Services, it's just not supported. There can be issues with high load (running out of unmanaged resources), memory or resource leaks (badly implemented or called dispose patterns) and/or dialogs being popped when there's no desktop to show them on.

Testing will take care of the latter, and monitoring will alert you to the former. But, if/when you have a problem, don't expect to be able to call PSS and ask for a fix.

So, what are you options? Well, if you don't need a completely supported route, and you don't expect extreme load - a lot of folks have disregarded the MSDN caveat and used System.Drawing with success. A few of them have been bitten, but there's alot more success than failure stories.

If you want something supported, then you need to know if you're running interactively or not. Personally, I'd probably just leave it up to the hosting app to set a non-interactive flag somewhere or other. After all, the app is in the best position to determine if they're in a hosted environment and/or want to risk the GDI+ issues.

But, if you want to automagically detect your environment, I suppose there's worse answers than are offered right here on SO for a service. To summarize, you can either check the EntryAssembly to see if it inherits from ServiceBase, or try to access System.Console. For ASP.NET, along the same lines, detecting HttpContext.Current should be sufficient.

I'd think there'd be a managed or p/invoke way to look for a desktop (which is really the defining factor in all this, I think) and/or something off the AppDomain which would clue you in. But I'm not sure what it is, and MSDN is less than enlightening on it.

Edit: Trolling MSDN, I recalled that it's actually a Window Station (which hosts a desktop) that's the important bit here. With that info, I was able to find GetProcessWindowStation() which returns a handle to the current window station. Passing that handle to GetUserObjectInformation() will get you a USEROBJECTFLAGS struct with should have a dwFlags with WSF_VISIBLE if you have a visible desktop.

Alternatively, EnumWindowsStations will give you a list of stations which you could check - WinSta0 is the interactive one.

But, yeah, I still think just having the app set a property or something is the much easier route....

Mark Brackett
A: 

Even though it's not officially supported, I've used the System.Drawing classes extensively on a high-volume web server (both web application and web services) for years without it causing any performance or reliability problems.

I think the only way to determine if the code is safe to use is to test, monitor, and wrap any object with external resources in using{} statements.

Martin Cron