6

I have a WCF service which returns a Stream much like the following:

public Stream StreamFile(string filepath)
{
    try
    {
        // Grab the file from wherever it is
        // Throw an exception if it doesn't exist
        return fileStream;
    }
    catch (Exception ex)
    {
        // Log the exception nicely in a place of my user's choosing
    }
    return Stream.Null;
}

I used to attempt to return null, but I began running into this issue if the file could not be found: WCF - MessageBodyMember - Stream - "Value cannot be null"

By returning Stream.Null, I've gotten rid of that error, but now I have another problem - how does my client know if I sent back Stream.Null? I can't/shouldn't check the length, because these files can be quite big, but even if they weren't, I would be faced with this problem: Find Length of Stream object in WCF Client?

Here's my (much-simplified) client code, just for posterity, but the issue for me with just downloading the Stream.Null is that I end up with an empty file, and nobody likes that.

public FileInfo RetrieveFile(string fileToStream, string directory)
{
    Stream reportStream;
    string filePath = Path.Combine(directory, "file.txt");
    using (Stream incomingStream = server.StreamFile(fileToStream))
    {
        if (incomingStream == null) throw new FileExistsException(); // Which totally doesn't work      
        using (FileStream outgoingStream = File.Open(filePath, FileMode.Create, FileAccess.Write))
        {
            incomingStream.CopyTo(outgoingStream);
        }
    }
    return new FileInfo(filePath);
}

It seems like I'm just designing this method wrong somehow, but I can't think of a better way to do it that doesn't involve throwing an uncaught exception. Any suggestions?

Community
  • 1
  • 1
Crystal
  • 153
  • 1
  • 10
  • `Stream.Null` has nothing to do with `null` or any special fallback value, it's a special stream instance that corresponds to the DOS `NUL` stream or `/dev/null` on Linux/POSIX. Therefore you should not return it. – Dai Jul 28 '15 at 05:19
  • If you're in an error condition, consider using WCF's "Fault" system which is used to indicate to clients that a typical response (e.g. with a suitable `Stream` object) could not be completed. – Dai Jul 28 '15 at 05:20
  • Add a status messages to beginning of stream. Client will read status from beginning of message and remove before processing rest of data. Doing this is a very good robust design and people who say it is not necessary is eliminating important debug info that is important when error conditions do occur. – jdweng Jul 28 '15 at 06:00

1 Answers1

0

When something unexpected happens in a WCF service (or any well designed service for that matter) the client cannot / should not know the details or care. All it needs to know it that something went wrong.

You should allow the exception to rise without catching it and the client would know that a Fault occurred and the operation failed, regardless to the fact that the file was missing, no permissions to read it or maybe the file is corrupt on disk. None of that matters to the client since i cannot do anything with the information anyway except from being too coupled to the service.

In that case of course, the return value is meaningless and in fact the proxy would (generally) be in a faulted state and would not be usable any more. (This depends on your session mode and instance lifestyle).

Note that if you wanted to let the client know about the faults and react, you should design those faults as part of the contract and throw a FaultException<> wrapping the contracted exception you explicitly declared in the contract. This would allow the proxy to continue to be usable. You can read more here

Yoad Snapir
  • 528
  • 2
  • 10