如何检测.Net应用程序类型?

4

我有一个库需要根据运行环境的不同方式来响应异常,包括控制台应用程序、WinForms、AspNet或Windows服务。我已经尝试查看System.Windows.Forms和System.Web命名空间中的各种属性,但是我找不到一种可靠的方法来检测哪种类型的应用程序托管了我的库。有人遇到过这种情况吗?有没有可靠的解决方案?


1
我使用的解决方案结合了Arul和Josh提供的答案以及以下链接:http://blogs.msdn.com/kstanton/archive/2004/03/31/105060.aspx,http://www.codeguru.com/cpp/w-p/system/misc/article.php/c2897。因此,首先我检查是否存在ASP上下文,如果不存在,则加载主应用程序二进制文件并检查标头中的标志,以查看它是否针对Windows或Console子系统。如果有人感兴趣,我可以提供代码示例。 - open-collar
5个回答

5

如果我正确理解你的需求,你有一个处理错误的单一库,但是你希望该库知道源是否为web、console、winforms等?

您可以利用库中的属性,例如枚举类型,来跟踪使用应用程序的类型。例如...

ErrorLogger error = new ErrorLogger(ErrorLoggerAppType.WinForm);
ErrorLogger error = new ErrorLogger(ErrorLoggerAppType.Web);
ErrorLogger error = new ErrorLogger(ErrorLoggerAppType.Console);

编辑
来自评论中的Samir...
此外,您可以针对每种类型的应用程序都创建一个类,并在您的错误记录器库中实现相同的接口。

例如,在Web应用程序中,您将使用:

WebErrorLogger error = new WebErrorLogger();

1
或者:error = new GUIErrorLogger(); / error = new WebErrorLogger(); / error = new ConsoleErrorLogger(); 它们都实现了 ErrorLogger 接口。 - Samir Talwar
这是我目前所在的位置 - 但我正在尝试消除消费者以这种方式初始化的需要。 如果没有人能提出更好的想法,那么我可能不得不坚持这个方法。 - open-collar

3
这似乎需要进一步研究设计,这是我的直觉。一个类库不应该知道调用者的那些信息。
您想根据运行环境改变异常处理行为中的哪些内容?
基于您的评论,我建议定义一个错误处理程序接口,然后创建所需数量的接口实现(例如WinForms、Console等),并让客户端应用程序创建和注入相应的实现到库中。这样,您就可以将知识需求从库中移出,并将责任转移到客户端应用程序上。这些实现仍然可以驻留在您的类库中,但使用哪个实现的决定将由客户端应用程序做出。

这是一个支持库,为其他库和应用程序提供基础设施,可在各种情境中使用。其理念是该库提供了一种处理未处理错误并将其报告给主机应用程序的通用方法。 - open-collar
在所有情况下,都会向Jira服务器发送带有详细信息的电子邮件。但在Windows中,会捕获屏幕截图并向用户显示对话框。在控制台应用程序中,详细信息将写入控制台。我在这里提到了错误处理,但也可能有其他目的。 - open-collar

3
这听起来最好通过配置来处理。也许可以通过IOC注入类似IExceptionHandler接口的东西来实现。

3

在进行这个步骤之前,我建议您先审查一下设计,但我认为这是一个有趣的挑战,想看看是否能找到其他方法。

ASP.Net:检查HttpContext.Current不为空。您也可以查看System.Web.Hosting.ApplicationManager.GetApplicationManager(),但我不确定在Asp.net之外会发生什么。

Windows窗体应用程序:您可以尝试使用System.Windows.Forms.Application.OpenForms,这将返回任何打开的窗体。假设是一个Windows窗体应用程序永远不会没有任何窗体。此外,控制台应用程序也可以启动Win表单。

服务:不确定,但我想知道您是否可以检查进程的名称。必须还有一个Windows API,因为任务管理器显示进程是否为服务(至少在Vista上是这样)。


1
在ASP.NET应用程序中的非请求线程中,使用HttpContext.Current时要小心,它会返回null。 - Tamas Czinege

1
BOOL IsConsole(PBYTE file)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)file;
    if(pDosHeader->e_magic == IMAGE_DOS_SIGNATURE) 
    {
        PIMAGE_NT_HEADERS pImageHeaders = (PIMAGE_NT_HEADERS)(file + pDosHeader->e_lfanew);
        if(pImageHeaders->Signature == IMAGE_NT_SIGNATURE) 
        {
            IMAGE_OPTIONAL_HEADER optionalHeader = pImageHeaders->OptionalHeader;
            return (optionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
        }
    }

    return FALSE;
}

IMAGE_SUBSYSTEM_WINDOWS_CUI 可以替换为 IMAGE_SUBSYSTEM_WINDOWS_GUI,以检测是否为 GUI 应用程序而不是控制台。

Windows 中的服务通常将 'services.exe' 作为它们的父进程,确定父进程的方法在 CodeProject 中有很好的描述。

ASP.NET 进程在名为 ASPNET 的特殊用户下运行,可以从 访问令牌 中获取用户名。


这是我试图实现的最接近的内容。这个链接似乎提供了关于二进制文件是否为控制台应用程序的合理数量的信息:http://www.codeguru.com/cpp/w-p/system/misc/article.php/c2897。我不能依赖于使用ASPNET用户 - 我们使用各种服务帐户运行以实现各种目的。我认为结合下面Josh的答案,我可能可以得出一个合理的答案。 - open-collar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接