WCF: использование потоковой передачи с сообщениями
Я пытаюсь использовать потоки WCF с Контрактами сообщений, потому что мне нужны дополнительные параметры рядом с самим потоком.
В основном я создаю службу загрузки и загрузки файлов с некоторой дополнительной логикой сверху.
К сожалению, когда я пытаюсь воспользоваться службой из браузера, чтобы проверить, что все в порядке, я получаю следующую ошибку:
Ошибка сервера в приложении "/".
Операция "UploadFile" в контракте "IFileTransferService" использует MessageContract с заголовками SOAP. Заголовки SOAP не поддерживаются ни одним MessageVersion.
К сожалению, для Google это не принесло значительного результата, который помог мне. Можете ли вы, ребята, помочь мне? Здесь подробности службы (я удалил часть загрузки по причине пробела).
[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;
}
Я попытался использовать как basichttpbinding, так и customhttp-привязку с положительным эффектом:
<customBinding>
<binding name="customHttpBindingStream">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647"/>
</binding>
</customBinding>
ОБНОВЛЕНИЕ: чтение документации онлайн кажется, что потоковая передача с MessageContracts действительно должна быть возможна. Обратитесь, например, к MSDN (Large Data and Streaming):
Модель программирования для потоковых передач
Модель программирования для потоковой передачи простой. Для получения потоковые данные, укажите операцию контракт с одним потоком введенный входной параметр. Для возвращения потоковые данные, вернуть поток Справка. [...] Это правило аналогично применяется к контрактам с сообщениями. Как показано в следующем сообщении, вы может иметь только один член тела в договор с вашим сообщением, поток. Если вы хотите общаться дополнительную информацию с поток, эта информация должна быть переносится в заголовки сообщений. тело сообщения зарезервировано исключительно для содержимого потока.
[MessageContract]
public class UploadStreamMessage
{
[MessageHeader]
public string appRef;
[MessageBodyMember]
public Stream data;
}
Я также видел сообщения в блогах от людей, выполняющих службы загрузки и загрузки файлов, очень похожие на то, что я пытаюсь собрать (например здесь).
ОБНОВЛЕНИЕ 2
Я попытался создать небольшую консоль и самостоятельно разместить службу с помощью basicHttpBinding, и там она работает как шарм. Я начинаю верить, что проблема может заключаться в размещении в IIS. Любая идея?
ОБНОВЛЕНИЕ 3
См. Мой собственный ответ.
Ответы
Ответ 1
Наконец-то я узнал, в чем была ошибка: это не имело ничего общего с версиями Soap, потоками и т.д. Я просто неправильно использовал имя моей собственной службы (!), используя FileTransfer
вместо FileTransferService
.
В конце basicHttpBinding было прекрасно, мне не нужно было прибегать к пользовательской привязке.
Оригинальная (плохая) версия:
<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>
Новая (исправленная) версия:
<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>
Тем не менее, я не могу сказать, что сообщение об ошибке было полезно любым способом понять, что здесь происходит.
Если вас интересует весь сервис, вы можете найти более подробную информацию в своем блоге по следующей ссылке: Передача файлов с WCF
Ответ 2
Вам нужна потоковая передача (т.е. передача объемных данных) как по запросу, так и по ответу? Или просто ответ (обычно: загрузка файла или большой набор данных)?
Если вам нужен только ответ, вы должны попытаться установить передаточный режим в "StreamedResponse":
<customBinding>
<binding name="customHttpBindingStream">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport transferMode="StreamedResponse"
maxReceivedMessageSize="2147483647"/>
</binding>
</customBinding>
Параметр "Потоковый" будет транслироваться в обе стороны - поток, отправляемый на сервер, а также ответ от сервера, будет транслироваться. Чаще всего это не идеальный сценарий.
Марк
Ответ 3
Я получил ошибку после использования шаблона "Служба данных WCF" для генерации файла svc вместо шаблона "WCF Service". Исправляя файл хоста службы, проблема была решена.