Большой двоичный файл (byte []) Передача файлов через WCF

Я пытаюсь создать службу WCF, которая позволяет мне отправлять большие двоичные файлы от клиентов к службе.

Однако я могу успешно передавать файлы размером до 3-4 МБ. (У меня не получается передать 4,91 МБ и, конечно же, что-либо еще)

При попытке отправить файл размером 4,91 МБ возникает следующая ошибка:

Сообщение об исключении: произошла ошибка при получении ответа HTTP на http://localhost:56198/Service.svc. Это может быть связано с тем, что привязка конечной точки службы не использует протокол HTTP. Это также может быть связано с прерыванием контекста HTTP-запроса сервером (возможно, из-за завершения работы службы). См. Журналы сервера для более подробной информации.

Сообщение о внутреннем исключении: основное соединение было закрыто: при получении произошла непредвиденная ошибка.

Сообщение о внутреннем исключении: Невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным узлом.

Сообщение о внутреннем исключении: существующее соединение было принудительно закрыто удаленным хостом.

Эта ошибка возникает на стороне клиента, как только файл byte [] отправляется в качестве параметра метода в открытый метод службы.

У меня есть точка останова в первой строке метода службы, в случае успешной передачи файлов (ниже 3 МБ) эта точка останова срабатывает, и файл передается. Однако в этом случае, как только метод вызывается, возникает ошибка. В случае этой ошибки точка останова в службе не срабатывает.

Я собираюсь вставить свои разделы в свой Service Web.config и Asp Page (Client) Web.config. Если вам также нужен код, который отправляет файл и принимает файл, дайте мне знать, я тоже пришлю его.

Сервис Web.Config

<system.serviceModel>
<bindings>
  <basicHttpBinding>
    <binding name="basicHttpEndpointBinding" closeTimeout="01:01:00"
      openTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00"
      allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
      maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
      messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedRequest"
      useDefaultWebProxy="true">
      <readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
        maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"
          realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>        
  </basicHttpBinding>      
</bindings>
    <services>
        <service behaviorConfiguration="DragDrop.Service.ServiceBehavior" name="DragDrop.Service.Service">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" contract="DragDrop.Service.IService">
                <identity>
                    <dns value="localhost"/>
                </identity>
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="DragDrop.Service.ServiceBehavior">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
      <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Клиент (страница Asp.net) Web.Config

<system.serviceModel>
<bindings>
   <basicHttpBinding>
      <binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
         openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
         allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
         maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
         messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedResponse"
         useDefaultWebProxy="true">
         <readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
            maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
         <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
               realm="">
               <extendedProtectionPolicy policyEnforcement="Never" />
            </transport>
            <message clientCredentialType="UserName" algorithmSuite="Default" />
         </security>
      </binding>
   </basicHttpBinding>
</bindings>

<behaviors>
  <endpointBehaviors>
    <behavior name="debuggingBehaviour">
      <dataContractSerializer maxItemsInObjectGraph="2147483646" />
    </behavior>
  </endpointBehaviors>
</behaviors>

<client>
   <endpoint address="http://localhost:56198/Service.svc" binding="basicHttpBinding"
      bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference.IService"
      name="BasicHttpBinding_IService" behaviorConfiguration="debuggingBehaviour" />
</client>
</system.serviceModel>

person user402186    schedule 17.05.2011    source источник
comment
извините, редактировал (каким-то образом моя конфигурация службы не отображалась ....) все еще нужен код C # ... ???   -  person user402186    schedule 17.05.2011
comment
Я решил, что это исправление: stackoverflow.com/questions/998927/   -  person daniele3004    schedule 23.03.2017


Ответы (4)


(Хотя я согласен, что предпочтительнее потоковая передача, ниже должно заставить его работать без каких-либо других изменений)

Вам также необходимо увеличить максимальную длину сообщения в Web.config:

<configuration>
  <system.web>
  <httpRuntime maxMessageLength="409600"
    executionTimeoutInSeconds="300"/>
  </system.web>
</configuration>

Это установит максимальную длину сообщения в 400 МБ (параметр в килобайтах). Дополнительные сведения см. На этой странице MSDN.

person Thorarin    schedule 17.05.2011
comment
Спасибо ... он работает ... Я только что протестировал файл размером 30 МБ, и он работает, я сделаю тест на 1-2 ГБ, а затем посмотрю, как оно пойдет, но пока что на мой вопрос дан ответ ... Большое спасибо. - person user402186; 17.05.2011
comment
Для 1-2 ГБ я бы серьезно подумал о возможностях потоковой передачи, а не об использовании byte[]. Во-первых, у .NET framework есть проблемы даже с распределением массивов такого размера, не говоря уже о их передаче. - person Thorarin; 17.05.2011
comment
Я не понял этого. Вы имеете в виду, должен ли я передавать файлы кусками (и каждый фрагмент через потоковую передачу, как мы только что сделали выше для 30 МБ). А затем, когда все фрагменты достигнут сервера, объедините их вместе .... это сработает, или у них есть какой-нибудь лучший способ сделать это? - person user402186; 17.05.2011
comment
или u означает способ, описанный в приведенной выше ссылке u: msdn.microsoft.com /en-us/library/ms789010.aspx - person user402186; 17.05.2011
comment
Не собираясь перехватывать этот ответ, но я добавил ответ, показывающий именно это :-) По сути, вы возвращаете Stream вместо byte[]. Удачи! - person Jakob Möllås; 17.05.2011
comment
@ Якоб: нет проблем. Я решил не изо всех сил перефразировать ваш ответ и ответ Ника, поэтому я просто добавил ссылку, которая, по крайней мере, указала на возможность :) - person Thorarin; 17.05.2011
comment
Боже мой ... Сколько раз я забуду это? Спасибо. - person NestorArturo; 30.11.2011
comment
Спасибо, это мне очень помогло! - person Paul T Davies; 03.01.2012
comment
Ссылка на страницу MSDN, указанная в ответе, предназначена для WSE - проблема в том, что атрибуты в элементе httpRuntime отличаются от сегодняшних атрибутов, которыми являются ExecutionTimeout и maxRequestLength, как показано здесь, что заставляет меня задаться вопросом, как @ user402186 реализовал решение, предоставленное, если он использует WCF. Невозможно нет? В моем случае мне пришлось добавить элемент как на стороне клиента, так и на стороне сервера, чтобы это работало для меня. Но я перейду к приготовлению на пару как можно скорее. Просто любопытно все. - person dyslexicanaboko; 16.01.2013

Как уже указывалось, попробуйте использовать Streaming Transfer, вот пример кода, показывающий как отправка, так и получение (возможно) больших объемов данных с использованием потоковой передачи.

Используйте такую ​​привязку, обратите внимание на настройки MaxReceivedMessageSize и TranferMode.

<binding name="Streaming_Binding" maxReceivedMessageSize="67108864"  
    messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed">
</binding>

Добавьте служебный код:

[OperationContract]
public Stream GetLargeFile()
{
    return new FileStream(path, FileMode.Open, FileAccess.Read);
}

[OperationContract]
public void SendLargeFile(Stream stream)
{
    // Handle stream here - e.g. save to disk    
    ProcessTheStream(stream);

    // Close the stream when done processing it
    stream.Close();
}

И немного клиентского кода:

public Stream GetLargeFile()
{
    var client = /* create proxy here */;
    try
    {
        var response = client.GetLargeFile();

        // All communication is now handled by the stream, 
        // thus we can close the proxy at this point
        client.Close();

        return response;
    }
    catch (Exception)
    {
        client.Abort();
        throw;
    }
}

public void SendLargeFile(string path)
{
    var client = /* create proxy here */;
    client.SendLargeFile(new FileStream(path, FileMode.Open, FileAccess.Read));
}

Кроме того, убедитесь, что вы не получаете тайм-аут, для передачи большого файла может потребоваться некоторое время (хотя по умолчанию значение receiveTimeout составляет 10 минут).

Вы можете загрузить образец кода Microsoft WCF / WF здесь ( ссылка на C # на момент написания не работает, но другие примеры кода кажутся нормальными).

person Jakob Möllås    schedule 17.05.2011
comment
Спасибо, Якоб, я вроде как получил ваш ответ, но чего я здесь не понимаю, так это того, что вы возвращаете поток от службы к клиенту. Я хочу наоборот, клиент будет выгружать большие файлы на сервер ..... или я ошибся в вашем ответе? - person user402186; 17.05.2011
comment
Ага, извините, пропустил, ну это более-менее вопрос обращения процесса вспять. Добавлен код, чтобы показать это! - person Jakob Möllås; 17.05.2011
comment
Правильный! Я изменил название, чтобы избежать путаницы в будущем. - person Jakob Möllås; 25.05.2013
comment
ссылка на образцы не работает как обычно (не ваша вина) - person Veverke; 29.07.2018
comment
@Veverke: Спасибо, ссылка обновлена, хотя образец страницы все еще не работает - person Jakob Möllås; 30.07.2018

Вы когда-нибудь видели использование Streaming Transfer?

Windows Communication Foundation (WCF) может отправлять сообщения с использованием буферизованной или потоковой передачи. В режиме буферизации передачи по умолчанию сообщение должно быть полностью доставлено, прежде чем получатель сможет его прочитать. В режиме потоковой передачи получатель может начать обработку сообщения до того, как оно будет полностью доставлено. Режим потоковой передачи полезен, когда передаваемая информация имеет большой объем и может обрабатываться последовательно. Потоковый режим также полезен, когда сообщение слишком велико для полной буферизации.

http://msdn.microsoft.com/en-us/library/ms789010.aspx

person Nick    schedule 17.05.2011
comment
Я использую потоковую передачу в качестве режима передачи. В моем сервере Web.config у меня есть: messageEncoding = Mtom textEncoding = utf-8 transferMode = Streamed - person user402186; 17.05.2011
comment
В приведенной выше конфигурации у меня есть transferMode = StreamedRequest, я тоже пробовал, но это тоже не сработало. - person user402186; 17.05.2011
comment
Вам также необходимо изменить свои контракты, чтобы использовать объекты Stream. - person Nick; 17.05.2011
comment
Я пытаюсь добавить режим передачи, но в файле web.config возникает ошибка. - person user3217843; 11.02.2015

Я повторю то, что говорили другие, и скажу, что использование потоковой передачи - это лучший вариант при использовании Windows Communication Foundation. Ниже приведено отличное руководство, в котором объясняются все шаги для потоковой передачи файлов через WCF. Он довольно подробный и очень информативный.

Вот оно: Руководство по потоковой передаче файлов через WCF.

person Derek W    schedule 23.05.2013