17

根据MSDN ,在 Windows 服务或 ASP.NET 服务中使用System.Drawing命名空间中的类并不是一个特别好的主意。现在我正在开发一个类库,它可能需要访问这个特定的命名空间(用于测量字体),但不能保证宿主进程不是服务。

现在,如果 System.Drawing 不可用,我可以回退到一个不太理想的方法,但如果可能的话,我宁愿使用 System.Drawing 中的类。所以我想做的是在运行时确定 System.Drawing 是否安全,如果是,请使用它,否则回退到次优选项。

我的问题是:我怎么可能检测 System.Drawing 是否可以安全使用?

我想我应该要么

  • 检测当前进程是 Windows 服务还是 ASP.NET 服务
  • 检测 GDI 是否可用
  • 或者也许有一种方法可以询问 System.Drawing.dll 本身是否可以安全使用

不幸的是,我无法想出一种方法来实现这些方法中的任何一种。有谁有想法吗?

4

5 回答 5

19

为了消除任何混淆,System.Drawing 确实在 ASP.NET 和服务下工作,它只是不受支持。可能存在高负载(用尽非托管资源)、内存或资源泄漏(实施不当或称为处置模式)和/或在没有桌面显示它们时弹出对话框的问题。

测试会处理后者,而监控会提醒您注意前者。但是,如果/当您遇到问题时,不要指望能够致电 PSS 并要求修复。

那么,你有什么选择?好吧,如果您不需要完全支持的路线,并且您不期望极端负载 - 很多人无视 MSDN 警告并成功使用 System.Drawing。他们中的一些人被咬了,但成功的故事比失败的故事多得多。

如果您想要支持某些东西,那么您需要知道您是否正在交互式运行。就个人而言,我可能只是将它留给托管应用程序在某处或其他地方设置非交互式标志。毕竟,应用程序最适合确定它们是否处于托管环境中和/或是否愿意冒 GDI+ 问题的风险。

但是,如果您想自动检测您的环境,我想有比SO 上提供的服务更糟糕的答案。总而言之,您可以检查 EntryAssembly 以查看它是否继承自 ServiceBase,或者尝试访问 System.Console。对于 ASP.NET,同理,检测 HttpContext.Current 就足够了。

认为会有一种托管或 p/invoke 方式来查找桌面(我认为这确实是所有这一切的决定性因素)和/或 AppDomain 之外的东西会提示你。但我我不确定它是什么,而 MSDN 对它的启发不足。

编辑:Trolling MSDN,我记得它实际上是一个Window Station(托管桌面),这是这里的重要部分。有了这些信息,我就能找到GetProcessWindowStation(),它返回当前窗口站的句柄。将该句柄传递给GetUserObjectInformation()将为您提供一个USEROBJECTFLAGS结构,如果您有一个可见的桌面,则该结构应该有一个带有 WSF_VISIBLE 的 dwFlags。

或者,EnumWindowsStations会给你一个你可以检查的电台列表——WinSta0 是交互式的。

但是,是的,我仍然认为让应用程序设置一个属性或其他东西是容易的方法......

再次编辑:7 年后,我被提示进入Environment.UserInteractive,MS为您执行我上面为您描述的确切 GetProcessWindowStation 舞蹈....我仍然建议委托给托管应用程序(他们可能希望更快,但稍微风险更高的 System.Drawing 路径),但 UserInteractive 似乎是一个很好的默认设置,而不需要自己调用它。

于 2008-12-24T02:27:46.777 回答
4

尽管它不受官方支持,但多年来我一直在大容量 Web 服务器(Web 应用程序和 Web 服务)上广泛使用 System.Drawing 类,而不会导致任何性能或可靠性问题。

我认为确定代码是否可以安全使用的唯一方法是在 using{} 语句中测试、监视和包装任何具有外部资源的对象。

于 2010-06-18T18:34:02.777 回答
1

您可以改用TextRenderer。我知道在 ASP.NET 中使用 System.Windows.Forms 中的某些东西很奇怪,但它似乎没有关于在 ASP.NET 中不受支持的相同警告。我已经使用 TextRenderer 和 Graphics.MeasureString 来测量 ASP.NET 应用程序中的字符串,所以它们都可以工作。我从未见过有关 System.Drawing 在 ASP.NET 中不可取的警告。

TextRenderer 比 Graphics.MeasureString、FWIW 慢很多。

于 2008-12-24T01:10:18.163 回答
0

这可能与需要 STA 线程的 GDI 子系统有关。如果是这种情况,请调查在您的 @PAGE 指令中为所涉及的 aspx 页面指定 ASPCOMPAT=TRUE。这将在 STA 线程 IIRC 中运行 aspx 页面。

-Oisin

于 2008-12-24T01:19:18.333 回答
-1

您也许可以将 System.Drawing.dll 复制到应用程序的 bin 中,然后以这种方式使用它。这可能保证它的可用性。

只需右键单击应用程序中的引用并将Copy Local的选项更改为true

虽然我可能误解了这个问题......

于 2008-12-24T01:16:13.020 回答