Pergunta

Estou tentando usar o streaming do WCF com contratos de mensagem, porque preciso de parâmetros adicionais ao lado do próprio fluxo.

Basicamente, estou criando um serviço de upload de arquivo e download, com uma lógica adicional na parte superior.

Infelizmente, quando tento atingir o serviço do navegador para verificar se está tudo bem, recebo o seguinte erro:

Erro de Servidor na '/' Aplicação. Operação 'UploadFile' no contrato 'ifileTransferService' usa um MessagECOntract que possui cabeçalhos de sabão. Os cabeçalhos de sabão não são suportados pelo Net MessageVersion.

Infelizmente, pesquisar no Google, pois não produziu nenhum resultado significativo que me ajudou. Vocês podem me ajudar? Aqui, os detalhes do serviço (removi a parte de download para o motivo do espaço).

[ServiceContract(Namespace = "http://www.acme.org/2009/04")]
public interface IFileTransferService
{
    [OperationContract(Action = "UploadFile")]
    void UploadFile(FileUploadMessage request);
}

[MessageContract]
public class FileUploadMessage
{
    [MessageHeader(MustUnderstand = true)]
    public FileMetaData Metadata { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream FileByteStream { get; set; }
}

[DataContract(Namespace = "http://schemas.acme.org/2009/04")]
public class FileMetaData
{
    [DataMember(Name="FileType", Order=0, IsRequired=true)]
    public FileTypeEnum fileType;

    [DataMember(Name="localFilename", Order=1, IsRequired=false)]
    public string localFileName;

    [DataMember(Name = "remoteFilename", Order = 2, IsRequired = false)]
    public string remoteFileName;
}

Eu tentei usar o BasichttpBinding e uma ligação customhttp com efeito não positivo:

<customBinding>
    <binding name="customHttpBindingStream">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647"/>
    </binding>
</customBinding>

ATUALIZAR: Lendo a documentação on -line Parece que o streaming com o MessageContrates deve realmente ser possível. Consulte, por exemplo, para MSDN (Grandes dados e streaming):

Modelo de programação para transferências transmitidas

O modelo de programação para streaming é direto. Para receber dados transmitidos, especifique um contrato de operação com um único parâmetro de entrada digitado de fluxo. Para retornar dados transmitidos, retorne uma referência de fluxo. [...] Esta regra se aplica da mesma forma a contratos de mensagem. Conforme mostrado no contrato de mensagem a seguir, você pode ter apenas um único membro do corpo em seu contrato de mensagem que é um fluxo. Se você deseja comunicar informações adicionais com o fluxo, essas informações devem ser transportadas nos cabeçalhos da mensagem. O corpo da mensagem é reservado exclusivamente para o conteúdo do fluxo.

[MessageContract]
public class UploadStreamMessage
{
   [MessageHeader]
   public string appRef;
   [MessageBodyMember]
   public Stream data;
} 

Eu também vi posts de blog de pessoas que realizam serviços de upload de arquivos e download muito parecidos com o que estou tentando montar (por exemplo aqui).

Atualização 2Tentei criar um pequeno console e hospedar o serviço com um Basichttpbbinging e lá funciona como um charme. Estou começando a acreditar que o problema pode ser a hospedagem no IIS. Qualquer ideia?

Atualização 3 Veja minha própria resposta.

Foi útil?

Solução

Finalmente descobri qual foi o erro: não tinha nada a ver com versões de sabão, riachos, etc ... Acabei de dar um puro no nome do meu próprio serviço (!), Usando FileTransfer ao invés de FileTransferService.

No final, basichttpbinding estava perfeitamente bem, eu não precisava recorrer a uma ligação personalizada.

Versão original (ruim):

<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransfer">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

Nova versão (fixa):

<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransferService">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

Ainda não posso dizer que a mensagem de erro foi útil de alguma forma para entender o que estava acontecendo aqui ....

Se você estiver interessado em todo o serviço, poderá encontrar mais detalhes no meu blog no seguinte link: Transferência de arquivos com WCF

Outras dicas

Você precisa de streaming (ou seja, transferência de quantidades de dados enormes) tanto na solicitação quanto na resposta? Ou apenas na resposta (normalmente: baixar um arquivo ou um grande conjunto de dados)?

Se você precisar apenas da resposta, tente definir o TransferMode como "StreamedResponse":

<customBinding>
    <binding name="customHttpBindingStream">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport transferMode="StreamedResponse" 
                       maxReceivedMessageSize="2147483647"/>
    </binding>
</customBinding>

A configuração "transmitida" transmitirá nos dois sentidos - tanto a solicitação que vai para o servidor quanto a resposta do servidor, será transmitida. Na maioria das vezes, esse não é o cenário ideal.

Marc

Recebi o erro depois de usar o modelo 'WCF Data Service' para gerar o arquivo SVC em vez do modelo 'WCF Service'. Corrigindo o arquivo do host de serviço, o problema foi resolvido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top