【问题标题】:.NET Remoting Exception not handled Client-Side.NET Remoting 异常未处理客户端
【发布时间】:2009-09-30 15:15:23
【问题描述】:

我检查了其余的远程问题,但这个具体案例似乎没有得到解决。

我设置了一个 .NET Remoting 服务器/客户端。在服务器端,我有一个对象,它带有一个可以抛出异常的方法,以及一个将尝试调用该方法的客户端。

服务器:

public bool MyEquals(Guid myGuid, string a, string b)
{
    if (CheckAuthentication(myGuid))
    {
        logger.Debug("Request for \"" + a + "\".Equals(\"" + b + "\")");
        return a.Equals(b);
    }
    else
    {
        throw new AuthenticationException(UserRegistryService.USER_NOT_REGISTERED_EXCEPTION_TEXT);
    }
}

客户:

try
{
    bool result = RemotedObject.MyEquals(myGuid, "cat", "dog");
}
catch (Services.Exceptions.AuthenticationException e)
{
    Console.WriteLine("You do not have permission to execute that action");
}

当我使用导致 CheckAuthentication 返回 false 的 Guid 调用 MyEquals 时,.NET 尝试抛出异常并说 AuthenticationException 未处理。这发生在服务器端。异常永远不会被编组到客户端,我不知道为什么。我看过的所有问题都解决了在客户端处理异常的问题,但它不是自定义异常而是基本类型。就我而言,我什至没有任何异常可以跨越远程边界到客户端。这是 AuthenticationException 的副本。它在服务器和客户端之间的共享库中。

[Serializable]
public class AuthenticationException : ApplicationException, ISerializable
{

    public AuthenticationException(string message)
        : base(message)
    {
    }

    public AuthenticationException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }

    #region ISerializable Members

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
    }

    #endregion
}

【问题讨论】:

    标签: c# .net exception-handling remoting


    【解决方案1】:

    首先,do not inherit from ApplicationException。这个建议已经存在了一段时间,我相信 FxCop 会自动生成一条消息。

    接下来,您通常应该使用[Serializable] 属性来装饰您的自定义异常。我认为这是您的主要问题,因为我在方法调用中遇到异常,说 AuthenticationException 未标记为可序列化。

    【讨论】:

    • 啊,是的。这是 FxCop 的消息:警告:CA1058:Microsoft.Design:更改“AuthenticationException”的基本类型,使其不再扩展“ApplicationException”。此基本异常类型不为框架类提供任何附加值。改为扩展“System.Exception”或现有的未密封异常类型。不要创建新的异常基类型,除非为整个异常类创建捕获处理程序有特定价值。
    • 啊。对不起。我在复制我的课程时忘记包含该行。我确实用 [Serializable] 装饰了我的异常。
    • 我正在阅读您对 Joe 的评论,内容是关于没有在客户端捕获异常。我已经将一个快速的远程处理服务器和客户端工具组合在一起,它每次都被客户端捕获,而不是在服务器上。我会再问几个符合条件的问题,希望能引导我们找到这个谜团的解决方案。 #1:持有 MyEquals 的类是 MarshalByRefObject 的后代吗?如果不是,它应该能够正确地编组到远程处理上。 #2:你如何托管服务器? IIS、Windows 服务或只是一个要测试的独立应用程序?
    • 回答您的问题(感谢您耐心等待,甚至开发了一个测试应用程序)#1:是的,MyEquals 属于 MarshalByRefObject 的后代。它是那个对象的孙子,但我猜这不会导致问题。 #2:我正在使用一个独立的测试应用程序。但是,此控制台应用程序在另一个 dll 程序集中构造了远程对象,因此可以稍后将远程对象绑定到 Windows 服务。
    • 另外,我自己构建了一个测试应用程序,我也遇到了同样的问题。在服务器端,我有一个抛出 CustomException 的方法。 “抛出新的自定义异常();”遵循上面的那个类模型。我仍然在服务器上收到相同的错误“CustomException was unhandled by user code”,而在客户端上什么也没有。
    【解决方案2】:

    在客户端尝试 catch(Exception),并检查被捕获的异常类型以及任何内部异常。它可能会提供一些线索。

    其他一些评论:

    • ApplicationException 已弃用。您通常应该从 System.Exception 派生。

    • 我通常将 [Serializable] 属性添加到自定义异常。不确定这是否重要。

    • 您通常应该重写 System.Exception.GetObjectData 而不是显式实现 ISerializable.GetObjectData。在您的情况下,您没有序列化任何其他数据,因此我既不会覆盖它也不会显式实现它。同样,我不确定这是否会产生任何影响。

    我的可序列化自定义异常模板如下所示,并且我在通过远程连接进行序列化时没有遇到任何问题。

    [Serializable]
    public class CustomException : Exception
    {
    
    /// <summary>
    /// Initializes a new instance of the <see cref="CustomException"/> class.
    /// </summary>
    public CustomException()
    {
    }
    
    /// <summary>
    /// Initializes a new instance of the <see cref="CustomException"/> class with
    /// a specified error message.
    /// </summary>
    public CustomException(string message) : base(message)
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="CustomException"/> class with
    /// a specified error message and a reference to the inner exception that is a cause
    /// of this exception.
    /// </summary>
    public CustomException(string message, Exception inner) : base(message, inner)
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="CustomException"/> class with
    /// serialized data.
    /// </summary>
    protected CustomException(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }
    
    }
    

    更新

    此外,如果您在 IIS 中托管服务器代码,则需要在 web.config 中添加以下内容以允许异常传播到客户端:

      <system.web>
        ...
        <customErrors mode="Off" /> 
        ...
    

    【讨论】:

    • 我根据您的自定义异常模板实现了我的 AuthenticationException。该异常仍然从未在客户端捕获。服务器因“用户代码未处理 AuthenticationException”而停止我是否必须向服务器应用程序指定有客户端愿意并等待处理抛出的任何异常?
    • “我是否必须指定服务器应用程序...” - 请参阅上面的更新
    【解决方案3】:

    这个错误有不同的原因,你们提到的不止一对。

    我注意到此错误的另一个原因;那就是被远程调用的远程对象的构造函数抛出异常的时候。异常没有被序列化,因为对象本身当时没有被初始化。我相信您应该避免任何可能导致在远程对象的构造函数中引发自定义异常的代码。如果在构造函数内部代码执行期间引发了系统异常,您应该将其作为系统错误(未知)处理,并构建一种机制来使用文件系统或其他方式存储该异常的详细信息。

    .net 远程处理在过去听起来确实很有吸引力,但是你的项目越大,你在代码中引入的概念越多,这项技术揭示的弱点就越多。这是一项很好的技术,但您需要丰富的经验才能从中获得强大的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-18
      • 2010-09-07
      • 2019-07-27
      • 2015-04-26
      • 1970-01-01
      • 2016-09-07
      • 2011-02-07
      相关资源
      最近更新 更多