There is a WCF that accepts files and stores on the server. Client code:

if (openFileDialog1.ShowDialog() == DialogResult.OK) { #region Загрузка и перевод файла FileStream fs = new FileStream(@openFileDialog1.FileName, FileMode.Open); byte[] buffer = new byte[fs.Length]; int len = (int)fs.Length; fs.Read(buffer, 0, len); #region Формируем массив buffer в ручном режиме //string st = string.Empty; //for (int i = 0; i < buffer.Length; i++) //{ // st += buffer[i].ToString() + ", "; //} //textBox1.Text = st; //byte[] buffer = { 37, 80, 68, 70, 45, 49, 46, 52, 10, 37, 226, 227, 207, 211, 10, 49, 32, 48, 32, 111, 98, 106, 10, 60, 60, 10, 47, 84, 121 }; #endregion fs.Close(); #endregion client.Load("Тест", 15, "Тестовый_файл.rtf", 60, buffer); //Обращаемся к WCF } 

The question is: why WCF throws an exception to the limit of waiting time - only when buffer is filled automatically. If the buffer is filled in manually then everything is OK, where to look for the error? filling buffer manually (extract from the array in the original 56Kb, size does not matter because files up to 200Mb were transferred in manual mode):

 byte[] buffer = { 37, 80, 68, 70, 45, 49, 46, 52, 10, 37, 226, 227, 207, 211, 10, 49, 32, 48, 32, 111, 98, 106, 10, 60, 60, 10, 47, 84, 121 }; 

app.config

 <?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IService1" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" /> </basicHttpBinding> <netTcpBinding> <binding name="MetadataExchangeTcpBinding_IService1" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> </netTcpBinding> </bindings> <client> <endpoint address="http://192.168.2.8:10207/Service1" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="svc.IService1" name="BasicHttpBinding_IService1" /> <endpoint address="net.tcp://192.168.2.8:10208/Service1" binding="netTcpBinding" bindingConfiguration="MetadataExchangeTcpBinding_IService1" contract="svc.IService1" name="MetadataExchangeTcpBinding_IService1" /> </client> </system.serviceModel> </configuration> 

When testing a WCF service through the WcfTestClient, everything goes off with a bang. those. Error somewhere in the client, the question is where?

In addition, let down the WCF service code: IService1

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WCFID { // ПРИМЕЧАНИЕ. Команду "Переименовать" в меню "Рефакторинг" можно использовать для одновременного изменения имени интерфейса "IService1" в коде и файле конфигурации. [ServiceContract] public interface IService1 { [OperationContract(Name = "ListFiles")] string[] ListFiles(int idLetter); [OperationContract(Name = "Load")] void Load(string Unit, int idLetter, string name, int idAuthor, byte[] file); [OperationContract(Name = "UnLoad")] byte[] UnLoad(string Unit, int idFile); } } 

Service1:

 using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WCFID { public class Service1 : IService1 { static string DirPatch = @"F:\Электронная приемная\Файлы"; private DataTable Get(string req) { DataTable dt = new DataTable(); MySqlConnectionStringBuilder mysqlSB = new MySqlConnectionStringBuilder(); mysqlSB.Server = "192.168.2.8"; mysqlSB.Port = порт; mysqlSB.Database = "БД"; mysqlSB.UserID = "логин"; mysqlSB.Password = "пароль"; using (MySqlConnection con = new MySqlConnection()) { con.ConnectionString = mysqlSB.ConnectionString; MySqlCommand com = new MySqlCommand(req, con); try { con.Open(); using (MySqlDataReader dr = com.ExecuteReader()) { if (dr.HasRows) dt.Load(dr); } } catch { } } return dt; } private void log(string text) { string path = "log.eprlog"; if (File.Exists(path)) { System.IO.StreamWriter writer = new System.IO.StreamWriter(path, true); writer.WriteLine(DateTime.Now.ToString() + " " + text); writer.Close(); } else { // Создаем файл. File.Create(path); System.IO.StreamWriter writer = new System.IO.StreamWriter(path, true); writer.WriteLine(DateTime.Now.ToString() + " " + text); writer.Close(); } } /*Загрузка документа с номером если его нет то ошибка продумать класс с полями: документ, информационное сообщение*/ public string[] ListFiles(int idLetter) { DataTable dt = Get("SELECT file_ep.idFile FROM file_ep WHERE file_ep.idLetter = '" + idLetter + "';"); string[] res = new string[dt.Rows.Count]; try { for (int i = 0; i < dt.Rows.Count; i++) { res[i] = dt.Rows[i].Field<object>(dt.Columns[0].Caption).ToString(); } } catch (Exception ex) { log(ex.ToString()); } return res; } public void Load(string Unit, int idLetter, string name, int idAuthor, byte[] file) { try { //Загружаем файл на сервер string nameFile = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Millisecond.ToString() + DateTime.Now.Second.ToString(); var path = DirPatch + @"\" + nameFile + "_" + name; FileStream fss = new FileStream(path, FileMode.Create, FileAccess.Write); fss.Write(file, 0, file.Length); fss.Close(); //пишем в бд инфу: ид письма, имя файла, автора, путь (автоматически) Get("INSERT INTO `file_ep` (`Unit`, `idLetter`, `name`, `path`, `idAuthor`) VALUES ('"+Unit+"', '" + idLetter.ToString() + "', '" + name + "', '" + path.Replace(@"\", "/") + "', '" + idAuthor.ToString() + "')"); log("INSERT INTO `file_ep` (`Unit`, `idLetter`, `name`, `path`, `idAuthor`) VALUES ('" + Unit + "', '" + idLetter.ToString() + "', '" + name + "', '" + path.Replace(@"\", "/") + "', '" + idAuthor.ToString() + "')"); } catch (Exception ex) { log(ex.ToString()); } } public byte[] UnLoad(string Unit, int idFile) { Byte[] buffer = new byte[0]; try { //Запрашиваем из БД путь к файлу DataTable dt = Get("SELECT file_ep.path FROM file_ep WHERE file_ep.idFile = '" + idFile.ToString() + "' and file_ep.Unit = '"+Unit+"';"); string path = dt.Rows[0].Field<string>(dt.Columns[0].Caption).Replace("/", @"\"); //Отдаем файл клиенту FileStream fs = new FileStream(path, FileMode.Open); buffer = new byte[fs.Length]; int len = (int)fs.Length; fs.Read(buffer, 0, len); fs.Close(); } catch (Exception ex) { log(ex.ToString()); } return buffer; } } } 

    1 answer 1

    Increase the timeout to send and receive messages (for example, 10 minutes):

     <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IService1" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" receiveTimeout="00:10:00" sendTimeout="00:10:00" /> </basicHttpBinding> 

    However, I recommend that you use another way to transfer files to WCF.

    By default, when communicating in WCF, the entire message is buffered entirely; fully read / formed in memory. This happens both when sending and when receiving a message. Obviously, if you try to send a file of several gigabytes (even several tens of megabytes), then a message of this size may simply not fit in memory, plus it takes a long time to form and read such a message.

    For large amounts of data in WCF is intended to stream . In this case, the data from the file will be transmitted not as an array of bytes, but as a Stream . This provides minimal memory consumption.

    However, this mode has a number of conditions and restrictions.

    First, the operation contract (in our case, Load ) must contain no more than one parameter. This parameter must be either directly streaming (serializable) with the data, or a message contract. The first option is not suitable, because we have additional parameters ( Unit , idLetter , etc.), so we have to wrap them in an additional class - the message contract:

     [ServiceContract] public interface IService1 { // параметры придется передавать через дополнительный класс [OperationContract] void Load(LoadParameters parameters); } [MessageContract] public class LoadParameters { [MessageHeader] public string Unit; [MessageHeader] public int idLetter; [MessageHeader] public string name; [MessageHeader] public int idAuthor; // Необходимо, чтобы в теле сообщения передавались данные из стрима, // а все остальные данные - через заголовки [MessageBodyMember] public Stream file; } 

    In the implementation of the contract, copy parameters.file :

     public void Load(LoadParameters parameters) { // ... using (var os = File.OpenWrite(fileName)) { parameters.file.CopyTo(os); } // ... } 

    Further, in the configuration (both server and client) for bindings, Streamed transfer mode must be enabled:

     <bindings> <basicHttpBinding> <binding name="streamedHttpBinding" transferMode="Streamed" maxReceivedMessageSize="4294967296" maxBufferSize="65536" receiveTimeout="00:10:00" sendTimeout="00:10:00" /> </basicHttpBinding> </bindings> <client> <endpoint address="http://192.168.2.8:10207/Service1" binding="basicHttpBinding" bindingConfiguration="streamedHttpBinding" <!-- так же для серверной части --> contract="svc.IService1" /> </client> 

    The maxReceivedMessageSize parameter specifies the maximum size of the entire message - i.e. file size + length of additional arguments + additional overhead due to serialization.

    The maxBufferSize parameter specifies the size of the buffer for reading the message. In the buffered (standard) mode, this value is not taken into account - it is automatically set equal to maxReceivedMessageSize (that is, the entire message will be read into memory as a whole). In streaming mode, the buffer size is already taken into account, the message will be read into memory in chunks of that size.

    Parameters receiveTimeout , sendTimeout also indicate if you need to save a very large file.

    On the client side, do not read the file into the array, but simply pass the stream in the parameters:

     using (FileStream fs = new FileStream(@openFileDialog1.FileName, FileMode.Open)) { var param = new LoadParameters() { Unit = ..., idAuthor = ..., idLetter = ..., name = ..., file = fs, }; client.Load(param); } 
    • really the problem was in the delay, corrected everything works. Since I recently started working with WCF about streaming information, it was interesting to know, I will use ... Thank you! - I.Vyrov
    • A big request to help implement this function (Load) via streaming (I understand that everything is painted, but something does not come out for me) describe in detail the client’s code and configuration and the service’s code and configuration will be very grateful. - I.Vyrov