0

I have been following the various tutorials that explain how to upload files via WCF and I am having some issues when I try to share the classes containing MessageContract between the client and the server.

Basically my issue is as follows:

I have a RemoteFileInfo MessageContract class inside of a separate class library:

[MessageContract]
public class RemoteFileInfo : IDisposable
{

    private System.IO.Stream fileByteStream;

    [MessageBodyMember(Order = 1)]
    public System.IO.Stream FileByteStream
    {
        set { this.fileByteStream = value; }
        get { return this.fileByteStream; }
    }

    /*More properties here declared as regular properties or [MessageHeader]*/
}

I then share that library with both the server and the client. This should mean that the client should not implement its own RemoteFileInfo class. However, after I add the .dll to my client project and then use Add Service Reference with Reuse Types enabled, it still remakes the RemoteFileInfo class inside of the service reference's namespace which creates ambiguity between the itself and the type in the class library I originally declare it in.

So my question is, how can I share a class that has been declared as a MessageContract between the client and the server? I need to do this because my OperationContract requires a RemoteFileInfo object and I would like to keep the same properties that I have declared in the original RemoteFileInfo class.

My OperationContract:

    [OperationContract]
    void uploadFile(RemoteFileInfo request);

I want to be able to call that method on the client exactly how it is declared in the service contract. So far even when I toy around with the Generate message headers option when adding the service reference, I end up with a method uploadFile that has a byte[] parameter instead of a stream, and I need it to be a stream.

Any ideas?

Edit: I was going to post a client config but I need to mention that I am developing for a Windows Store App so I do not have the traditional app.config.

Heres what the WCF Test client generated for a client config anyway:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IRTMobileWebService" sendTimeout="00:05:00" />
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="uploadEndpoint" sendTimeout="00:05:00" transferMode="Streamed">
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="http://ipaddress/RTWebServices/RTMobileWebService.svc/basic"
          binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IRTMobileWebService"
          contract="IRTMobileWebService" name="BasicHttpBinding_IRTMobileWebService" />
      <endpoint address="net.tcp://ipaddress/RTWebServices/RTMobileWebService.svc/upload"
          binding="netTcpBinding" bindingConfiguration="uploadEndpoint"
          contract="IRTMobileImageService" name="uploadEndpoint">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

How would I replicate this in a windows store app with no app.config?

Giardino
  • 1,367
  • 3
  • 10
  • 30

1 Answers1

1

If you're sharing a dll with the service interface already in it, then you shouldn't bother adding a service reference using the wizard - it'll miss stuff a good portion of the time and creates a whole heck of a lot more code than you need, including a completely new instance of the service interface, in a lot of cases.

Instead, in the application that consumes the service, create your own proxy class for the service like this:

class ClientServiceClass : ClientBase<ITheServiceContract>, ITheServiceContract
{

    public ClientServiceClass ( string endpointConfigurationName ) :
        base( endpointConfigurationName )
    {
    }

    internal void uploadFile(RemoteFileInfo request)
    {
        Channel.uploadFile(request);
    }
}

Where ITheServiceContract is the interface from your shared dll that is the service contract, and ClientServiceClass is whatever you want to call your implementation of the service proxy class (the wizard usually calls it by the name of the service).

To use the service in your code, do it like this:

NetTcpBinding binding = new NetTcpBinding();
binding.TransferMode = TransferMode.Streamed;
binding.Security = new NetTcpSecurity();
binding.Security.Mode = SecurityMode.None;
EndpointAddress address = new EndpointAddress("net.tcp://serviceEndpointAddress");
ClientServiceClass uploadClient = new ClientServiceClass(binding, address);
uploadClient.Open( );
uploadClient.uploadFile( yourFileInfoRequest );
uploadClient.Close( );
dodexahedron
  • 4,584
  • 1
  • 25
  • 37
  • the "endpointNameFromAppConfig" is the name of the endpoint which I can get by copying the client config from the WCFTest client that runs when I run the service in visual studio, correct? – Giardino Dec 24 '14 at 19:38
  • Yes. I will add example client configuration in a moment, to make the answer more complete. – dodexahedron Dec 24 '14 at 19:40
  • I'll post my config along with a new error regarding nettcpbinding. – Giardino Dec 24 '14 at 19:42
  • That will help. Post the server-side config, as well. Client has to match up to it. – dodexahedron Dec 24 '14 at 19:45
  • I added the client config that was pasted from the wcf test client which auto-generates it when you run it from VS. I also added that because I am developing for a windows store app, I don't have access to an app.config file :( – Giardino Dec 24 '14 at 19:46
  • No access at all? I'm unfamiliar with the Windows Store restrictions on that. If you can't configure it via XML, though, you can also configure it in code. Let's take this into a chat and we can work through it a bit quicker. – dodexahedron Dec 24 '14 at 19:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67642/discussion-between-user1806716-and-dodexahedron). – Giardino Dec 24 '14 at 19:50