tags:

views:

48

answers:

2

I am experimenting with creating a proof of concept upload WCF service. I have found the following partly in blog posts around the net:

namespace GreenWebMediaService
{    
    [ServiceContract]
    public interface IMediaServer
    {

        [OperationContract]
        void UploadData(UploadFile data);
    }


    // Use a data contract as illustrated in the sample below
    // to add composite types to service operations.
    [DataContract]
    public class UploadFile
    {
        public UploadFile() { }

        [MessageHeader]
        public string MetaData { get; set; }

        [MessageBodyMember]
        public Stream data { get; set; }
    }
}

i start it (hosting in Visual Studio) and make a reference from a newly created windows forms application, this is my reference, from app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IMediaServer" closeTimeout="00:01:00"
                 openTimeout="00:01:00" receiveTimeout="00:10:00"
                 sendTimeout="00:01:00" allowCookies="false"
                 bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                 maxBufferSize="65536" maxBufferPoolSize="524288"
                 maxReceivedMessageSize="65536" messageEncoding="Text"
                 textEncoding="utf-8" transferMode="Buffered"
                 useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192"
                        maxArrayLength="16384" maxBytesPerRead="4096"
                        maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
                       realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:49689/MediaServer.svc"
                binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IMediaServer"
                contract="mediaServer.IMediaServer"
                name="BasicHttpBinding_IMediaServer" />
    </client>
  </system.serviceModel>
</configuration>

when i make a instance of it and refer to it like this:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
            IMediaServer mediaServer = new mediaServer.MediaServerClient();
            UploadFile file = new UploadFile();            
            mediaServer.UploadData(null);
        }
    }

When i access the "file" variable, it only has a "file.ExtensionData" property whereas i would have expected to have access to the properties i made in my "UploadFile" class. What am i missing? I have tried to make a tick in the configure dialog in visual studio as i found this information in other threads, still no luck: see my dialog here: http://screencast.com/t/NzhhNzM3Y2Q (sorry i dont know how long screencast.com will keep this image)

+1  A: 

You are combining a DataContract with MessageHeader and MessageBodyMember attributes. You should either use

not a combination of these. So your UploadFile declaration should look like this:

[DataContract]
public class UploadFile
{
    [DataMember] public string MetaData { get; set; }
    [DataMember] public Stream data { get; set; }
}

or like this:

[MessageContract]
public class UploadFile
{
    [MessageHeader] public string MetaData { get; set; }
    [MessageBodyMember] public Stream data { get; set; }
}
Ronald Wildenberg
A: 

I see two problems in your code. The first problem is definition of DataContract. It is completely wrong. As Ronald already pointed you are combining DataContract and MessageContract. You have to use second Ronald's suggestion (first will not work):

[MessageContract] 
public class UploadFileRequest // Good naming convention for message contracts 
{ 
    // Streaming over HTTP demands only single body member of type Stream
    // any other data have to be passed as custom headers - that is the reason
    // why mentioned data contract doesn't work. 
    [MessageHeader] public string MetaData { get; set; } 
    [MessageBodyMember] public Stream Data { get; set; } 
} 

Second problem is Stream as body member for your request. It is only possible when you use Streamed or StreamedRequest transfer mode on your BasicHttpBinding. This information has to be set on the client binding definition manually - it is not transfered in WSDL / metadata and it is not interoperable feature.

Ladislav Mrnka