C# Windows 或 ASP.NET 服务中的 System.Drawing
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/390532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
System.Drawing in Windows or ASP.NET services
提问by Tamas Czinege
According to MSDN, it is not a particularly good idea to use classes within the System.Drawingnamespace 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.
根据MSDN,在 Windows 服务或 ASP.NET 服务中使用System.Drawing命名空间内的类并不是一个特别好的主意。现在我正在开发一个类库,它可能需要访问这个特定的命名空间(用于测量字体),但不能保证主机进程不是服务。
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.
现在,如果 System.Drawing 不可用,我可以使用一种不太理想的方法,但如果可能,我宁愿使用 System.Drawing 中的类。所以我想做的是在 runtume 确定 System.Drawing 是否安全,如果是,使用它,否则回退到次优选项。
My problem is: How could I possibly detect if System.Drawing is safe to use?
我的问题是:我怎么可能检测到 System.Drawing 是否可以安全使用?
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
- 检测当前进程是 Windows 服务还是 ASP.NET 服务
- 检测 GDI 是否可用
- 或者也许有一种方法可以询问 System.Drawing.dll 本身是否可以安全使用
Unfortunately, I cannot come up with a way to implement any of these approaches. Does anyone have any idea?
不幸的是,我无法想出一种方法来实现这些方法中的任何一种。有谁有想法吗?
采纳答案by Mark Brackett
To clear up any confusion, System.Drawing does workunder 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.
为了消除任何混淆,System.Drawing在 ASP.NET 和 Services 下确实可以工作,只是不受支持。可能存在高负载(耗尽非托管资源)、内存或资源泄漏(实施不当或称为处置模式)和/或在没有桌面显示它们时弹出对话框的问题。
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.
测试会处理后者,监控会提醒你注意前者。但是,如果/当您遇到问题时,不要期望能够致电 PSS 并要求修复。
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.
那么,你有什么选择?好吧,如果您不需要完全支持的路由,并且您不期望极端负载 - 很多人已经无视 MSDN 警告并成功使用 System.Drawing。他们中的一些人被咬了,但成功的故事比失败的故事多得多。
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.
如果您想要支持某些东西,那么您需要知道您是否以交互方式运行。就个人而言,我可能只是让托管应用程序在某处或其他地方设置非交互式标志。毕竟,该应用程序最适合确定它们是否处于托管环境中和/或想要冒 GDI+ 问题的风险。
But, if you want to automagically detect your environment, I suppose there's worse answers than are offered right here on SOfor 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.
但是,如果你想自动检测你的环境,我想有比这里提供的服务更糟糕的答案。总而言之,您可以检查 EntryAssembly 以查看它是否继承自 ServiceBase,或者尝试访问 System.Console。对于 ASP.NET,同样,检测 HttpContext.Current 就足够了。
I'd thinkthere'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.
我认为会有一种托管或 p/invoke 方式来寻找桌面(我认为这确实是所有这一切的决定因素)和/或 AppDomain 之外的东西,这会提示你。但我我不确定它是什么,MSDN 对它的启发不大。
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 USEROBJECTFLAGSstruct with should have a dwFlags with WSF_VISIBLE if you have a visible desktop.
编辑:Trolling MSDN,我记得它实际上是一个Window Station(承载桌面),这是这里的重要部分。有了这些信息,我就能找到GetProcessWindowStation(),它返回当前窗口站的句柄。将该句柄传递给GetUserObjectInformation()将为您提供一个USEROBJECTFLAGS结构,如果您有一个可见的桌面,它应该有一个带有 WSF_VISIBLE 的 dwFlags。
Alternatively, EnumWindowsStationswill give you a list of stations which you could check - WinSta0 is the interactive one.
或者,EnumWindowsStations会给你一个你可以检查的电台列表——WinSta0 是交互式的。
But, yeah, I still think just having the app set a property or something is the mucheasier route....
但是,是的,我仍然认为让应用程序设置属性或其他东西是更简单的方法......
Edit again: 7 years later, I get clued into Environment.UserInteractivewhere MS does the exact GetProcessWindowStation danceI described above for you....I'd still recommend delegating to the hosting app (they may well wantthe faster, but slightly riskier System.Drawing path), but UserInteractive seems a good default to have without having it pinvoke it yourself.
再次编辑:7 年后,我开始了解Environment.UserInteractive,其中 MS为您执行了我上面为您描述的确切 GetProcessWindowStation 舞蹈......我仍然建议委托给托管应用程序(他们可能想要更快,但稍微有点风险更高的 System.Drawing 路径),但 UserInteractive 似乎是一个很好的默认设置,而无需自己调用它。
回答by MusiGenesis
You could use TextRendererinstead. 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。我知道在 ASP.NET 中使用 System.Windows.Forms 中的东西很奇怪,但它似乎没有关于 ASP.NET 不支持的相同警告。我已经使用 TextRenderer 和 Graphics.MeasureString 来测量 ASP.NET 应用程序中的字符串,所以它们都可以工作。我从未见过有关 System.Drawing 在 ASP.NET 中不可取的警告。
TextRenderer is a lot slower than Graphics.MeasureString, FWIW.
TextRenderer 比 Graphics.MeasureString、FWIW 慢很多。
回答by Hugoware
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.
您可以将 System.Drawing.dll 复制到应用程序的 bin 中,然后以这种方式使用它。这可能保证它的可用性。
Just right click on the reference in your application and change the option for Copy Localto true.
只需右键单击应用程序中的引用并将Copy Local选项更改为true。
I may be misunderstanding the question though...
虽然我可能误解了这个问题......
回答by x0n
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.
这可能与需要 STA 线程的 GDI 子系统有关。如果是这种情况,请调查在您的 @PAGE 指令中为所涉及的 aspx 页面指定 ASPCOMPAT=TRUE。这将在 STA 线程 IIRC 中运行 aspx 页。
-Oisin
-Oisin
回答by Martin Cron
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.
尽管它不受官方支持,但多年来我一直在大容量 Web 服务器(Web 应用程序和 Web 服务)上广泛使用 System.Drawing 类,而没有导致任何性能或可靠性问题。
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.
我认为确定代码是否可以安全使用的唯一方法是在 using{} 语句中测试、监视和包装具有外部资源的任何对象。