.NET Remoting Exception не се обработва от страна на клиента

Проверих останалите въпроси за отдалечено управление и този конкретен случай изглежда не е разгледан.

Имам настроен .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");
}

Когато извикам MyEquals с Guid, което кара CheckAuthentication да върне false, .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
}

person Dan Joseph    schedule 30.09.2009    source източник


Отговори (3)


Първо и най-важно, не наследявайте от ApplicationException. Този съвет съществува от известно време и вярвам, че FxCop автоматично ще генерира съобщение за това.

След това обикновено трябва да украсите вашето персонализирано изключение с атрибута [Serializable]. Мисля, че това е основният ви проблем, тъй като получавам изключение при извикването на метода, което казва, че AuthenticationException не е маркирано като сериализирано.

person Jesse C. Slicer    schedule 30.09.2009
comment
А, да. Ето съобщението на FxCop: предупреждение: CA1058: Microsoft.Design: Променете основния тип на „AuthenticationException“, така че вече да не разширява „ApplicationException“. Този базов тип изключение не предоставя никаква допълнителна стойност за рамкови класове. Вместо това разширете „System.Exception“ или съществуващ незапечатан тип изключение. Не създавайте нов базов тип изключение, освен ако няма конкретна стойност в активирането на създаването на манипулатор за улавяне за цял клас изключения. - person Jesse C. Slicer; 30.09.2009
comment
ах Съжалявам. Забравих да включа този ред, когато копирах моя клас. Украсих моето изключение с [Serializable]. - person Dan Joseph; 30.09.2009
comment
Чета коментара ви по-горе към Джо относно това, че изключението не е уловено от страна на клиента. Свързах бърз Remoting сървър и клиентска система и всеки път се хваща от страната на клиента, а НЕ на сървъра. Ще задам още няколко квалифициращи въпроса, за да се надяваме, че ще ни насочат към решението на тази мистерия. #1: Класът, който съдържа MyEquals произлиза ли от MarshalByRefObject? Ако не, трябва да бъде така, че да бъде пренасочен правилно към Remoting. #2: Как хоствате сървъра? IIS, услуга на Windows или просто самостоятелно приложение за тестване? - person Jesse C. Slicer; 30.09.2009
comment
Отговори на вашите въпроси (между другото благодаря, че проявихте търпение и дори направихте тестово приложение) #1: Да, MyEquals е в клас, който произлиза от MarshalByRefObject. Това е внук на този обект, но предполагам, че това няма да причини проблема. #2: Използвам самостоятелно тестово приложение. Това конзолно приложение обаче конструира отдалечения обект вътре в друг dll сборник, така че отдалеченият обект може да бъде обвързан към услуга на Windows по-късно. - person Dan Joseph; 30.09.2009
comment
Освен това сам създадох тестово приложение и имам същия проблем. От страната на сървъра имам метод, който хвърля CustomException. хвърля ново CustomException(); следвайки модела на този клас по-горе. Все още получавам същата грешка CustomException беше необработено от потребителски код на сървъра и нищо на клиента. - person Dan Joseph; 30.09.2009
comment
Толкова съм глупав! Дори не се сетих за това: имах дебъгера на Visual Studio за улавяне на необработени изключения от първа инстанция. Така че Visual Studio се намеси, преди моят клиент да може. Деактивиран дебъгер на Visual Studio: работи като чар! Все пак благодаря за цялата помощ. - person Dan Joseph; 30.09.2009
comment
Имам скрито подозрение, че това конзолно приложение конструира отдалечения обект вътре в друг dll модул, може да е свързано с причината. Конструираният обект трябва да бъде обвит от обекта, който вашият сървър излага и след това ТОЗИ обект трябва да улови и хвърли отново изключението. - person Jesse C. Slicer; 01.10.2009
comment
Той Х. Игнорирайте последния ми коментар тогава. Радвам се, че върви! - person Jesse C. Slicer; 01.10.2009

Опитайте 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" /> 
    ...
person Joe    schedule 30.09.2009
comment
Приложих моя AuthenticationException за вашия персонализиран шаблон за изключение. Изключението все още НИКОГА не беше уловено от страна на клиента. Сървърът, спрян с AuthenticationException, не беше обработен от потребителски код Трябва ли да посоча на сървърното приложение, че има клиент, желаещ и чакащ да обработва всички изключения, които са хвърлени? - person Dan Joseph; 30.09.2009
comment
Трябва ли да посоча на сървърното приложение ... - вижте актуализацията по-горе - person Joe; 01.10.2009

Има различни причини за тази грешка и вие споменахте повече от няколко.

Забелязах друга причина за тази грешка; и това е, когато конструкторът на отдалечения обект, който се извиква дистанционно, хвърля и изключение. изключенията не се сериализират, защото самият обект не е инициализиран в този момент. вярвам, че трябва да избягвате ВСЕКИ код, който може да доведе до хвърляне на персонализирано изключение вътре в конструктора на отдалечения обект. и ако системно изключение е хвърлено по време на изпълнението на кода вътре в конструктора, трябва да се справите с него като системна грешка (неизвестна) и да изградите механизъм за съхраняване на подробностите за това изключение, като използвате файловата система или каквото и да е друго.

Отдалеченото .net звучеше наистина привлекателно навремето, но колкото по-голям става вашият проект и колкото повече концепции въвеждате в кода си, толкова повече слабости разкрива тази технология. това е добра технология, но имате нужда от много опит, за да направите стабилно решение от нея.

person lilmoe    schedule 25.04.2010