/// <summary>Reads a remote exception from the stream.</summary> /// <returns>The remote exception.</returns> public RemoteException ReadException() { Push(InstanceType.Exception); Debug.Assert(_current != null); RemoteException?remoteEx = null; do { // Read the slice header; an exception's type ID cannot be null. string typeId = ReadSliceHeaderIntoCurrent() !; ReadIndirectionTableIntoCurrent(); // we read the indirection table immediately if (Communicator.FindRemoteExceptionFactory(typeId) is IRemoteExceptionFactory factory) { remoteEx = factory.Read(this); } else if (SkipSlice()) // Slice off what we don't understand. { remoteEx = new RemoteException(GetSlicedData() !.Value); } }while (remoteEx == null); Pop(null); return(remoteEx); }
/// <summary>Reads a remote exception from the stream.</summary> /// <returns>The remote exception.</returns> public RemoteException ReadException() { if (!_inEncapsulation) { throw new InvalidOperationException("cannot read an exception outside an encapsulation"); } if (Communicator == null) { throw new InvalidOperationException( "cannot read an exception from an InputStream with a null communicator"); } Debug.Assert(_current.InstanceType == InstanceType.None); _current.InstanceType = InstanceType.Exception; RemoteException? remoteEx = null; string? errorMessage = null; RemoteExceptionOrigin?origin = null; // The unmarshaling of remote exceptions is similar with the 1.1 and 2.0 encodings, in particular we can // read the indirection table (if there is one) immediately after reading each slice header because the // indirection table cannot reference the exception itself. // With the 1.1 encoding, each slice contains its type ID (as a string), while with the 2.0 encoding the // first slice contains all the type IDs. if (OldEncoding) { do { // The type ID is always read for an exception and cannot be null. (string?typeId, _) = ReadSliceHeaderIntoCurrent11(); Debug.Assert(typeId != null); ReadIndirectionTableIntoCurrent(); // we read the indirection table immediately. if (Communicator.FindRemoteExceptionFactory(typeId) is Func <string?, RemoteExceptionOrigin?, RemoteException> factory) { // The 1.1 encoding does not carry the error message or origin so they are always null. remoteEx = factory(errorMessage, origin); } else if (SkipSlice(typeId)) // Slice off what we don't understand. { break; } }while (remoteEx == null); } else { // The type IDs are always read and cannot be null or empty. string[]? allTypeIds; (allTypeIds, errorMessage, origin) = ReadFirstSliceHeaderIntoCurrent20(); Debug.Assert(allTypeIds != null && allTypeIds.Length > 0 && errorMessage != null); bool firstSlice = true; foreach (string typeId in allTypeIds) { if (firstSlice) { firstSlice = false; } else { ReadNextSliceHeaderIntoCurrent(); } ReadIndirectionTableIntoCurrent(); // we read the indirection table immediately. Func <string?, RemoteExceptionOrigin?, RemoteException>?factory = Communicator.FindRemoteExceptionFactory(typeId); if (factory != null) { remoteEx = factory(errorMessage, origin); break; // foreach } else if (SkipSlice(typeId)) { // It should be the last element of allTypeIds; if it's not, we'll fail when reading the slices. break; } // else, loop. } } remoteEx ??= new RemoteException(errorMessage); remoteEx.Read(this); _current = default; return(remoteEx); }