.NET Remoting Exception not handled Client-Side
I checked the rest of the remoting questions, and this specific case did not seem to be addressed.
I have a .NET Remoting server/client set up. On the server side I have an objec开发者_如何学Ct with a method that can throw an exception, and a client which will try to call that method.
Server:
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);
}
}
Client:
try
{
bool result = RemotedObject.MyEquals(myGuid, "cat", "dog");
}
catch (Services.Exceptions.AuthenticationException e)
{
Console.WriteLine("You do not have permission to execute that action");
}
When I call MyEquals with a Guid which causes CheckAuthentication to return false, .NET tries to throw the exception and says the AuthenticationException was unhandled. This happens server side. The exception is never marshaled over to the client-side, and I cannot figure out why. All of the questions I have looked at address the issue of an exception being handled client-side, but it isn't the custom exception but a base type. In my case, I can't even get any exception to cross the remoting boundary to the client. Here is a copy of AuthenticationException. It is in the shared library between both server and client.
[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
}
First and foremost, do not inherit from ApplicationException. This advice has been around for a while, and I believe FxCop will automatically generate a message around this.
Next, you should usually decorate your custom exception with the [Serializable]
attribute. I think this is your main issue, as I get an exception on the method call saying AuthenticationException is not marked as serializable.
Try catch(Exception) on the client side, and inspect the type of the exception being caught as well as any inner exceptions. It might give some clues.
Some other remarks:
ApplicationException is deprecated. You should normally derive from System.Exception.
I normally add the [Serializable] attribute to custom exceptions. Not sure if this is important.
You should normally override System.Exception.GetObjectData rather than explicitly implementing ISerializable.GetObjectData. In your case you're not serializing any additional data, so I would neither override it nor explicitly implement it. Again I'm unsure if this would have any impact.
My template for a serializable custom exception looks like the following, and I haven't had any problems with serialization over a remoting connection.
[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)
{
}
}
UPDATE
Also if you're hosting the server code in IIS, you need the following in web.config to allow exceptions to propagate to the client:
<system.web>
...
<customErrors mode="Off" />
...
There are different reasons for this error, and you guys have mentioned more than a couple.
I have noticed another reason for this error; and that's when the constructor of the remotable object being called remotely throws and exception. the exceptions are not being serialized because the object itself wasn't initialized at that point. i believe you should avoid ANY code that might cause a custom exception to be thrown inside the remotable object's constructor. and if a system exception was thrown during the execution of the code inside the constructor, you should deal with it as a system error (unknown) and build a mechanism to store the details of that exception using the file system or whatever.
.net remoting sounded really appealing back in the days, but the larger your project gets, and the more concepts you introduce to your code, the more weaknesses this technology reveals. it's a good technology, but you need lots of experience to make a robust solution out of it.
精彩评论