WCF - потоковая загрузка файлов через http - PullRequest
2 голосов
/ 22 сентября 2011

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

Я адаптировал пример кода из The Code Project ( Потоковая передача WCF: выгрузка / загрузка файлов по HTTP ), и я также просмотрел несколько сообщений SO, но, похоже, это не работает .

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

На данный момент я довольно заблудился и не знаю, как это исправить. Любые предложения приветствуются.

Примеры кода:

CustomerDocumentModel - это элемент данных, который я передаю через интерфейс WCF с потоком для чтения файла на стороне клиента:

[DataContract]
[KnownType(typeof(System.IO.FileStream))]
public class CustomerDocumentModel : IDisposable
{
    public CustomerDocumentModel()
    {
    }

    public CustomerDocumentModel(string documentName, string path)
    {
        DocumentName = documentName;
        Path = path;
    }

    [DataMember]
    public string DocumentName;

    [DataMember]
    public string Path;

    [DataMember]
    public System.IO.Stream FileByteStream;

    public void Dispose()
    { 
        if (FileByteStream != null)
        {
            FileByteStream.Close();
            FileByteStream = null;
        }
    }
}

IBillingService - это определение интерфейса для моей службы WCF:

[ServiceContract]
public interface IBillingService
{
    // other methods redacted...

    [OperationContract]
    void UploadCustomerDocument(CustomerDocumentModel model);
}

Класс BillingService реализует службу WCF:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class BillingService : IBillingService
{
    // Other methods redacted ...

    public void UploadCustomerDocument(CustomerDocumentModel model)
    {
        string path = HttpContext.Current.Server.MapPath(
            String.Format("/Documents/{1}",
                model.DocumentName));

        using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            const int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];

            int size = 0;
            try
            {
                // The following Read() fails with a NullReferenceException
                while ((size = model.FileByteStream.Read(buffer, 0, bufferSize)) > 0)
                {
                    stream.Write(buffer, 0, size);
                }
            }
            catch
            {
                throw;
            }
            finally
            {
            stream.Close();
            model.FileByteStream.Close();
            }
        }
    }
}

Несколько важных битов из файла web.config на моем веб-сервере WCF:

<system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="2097151" useFullyQualifiedRedirectUrl="true" executionTimeout="360"/>
</system.web>

<system.serviceModel>
    <serviceHostingEnvironment
        aspNetCompatibilityEnabled="true"
        multipleSiteBindingsEnabled="true" />
    <bindings>
        <basicHttpBinding>
            <binding name="userHttps" transferMode="Streamed" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
                <security mode="None" />
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="">
                <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Клиент - это приложение WPF / MVVM, которое создает модель CustomerDocumentModel, использует OpenFileDialog для открытия () потока файлов и затем передает модель в метод UploadCustomerDocument в службе WCF.

Если мне не хватает какой-либо информации, пожалуйста, спросите.

Ответы [ 2 ]

4 голосов
/ 30 марта 2012

Я знаю этот довольно поздний ответ на ваш вопрос, и я уверен, что вы, должно быть, также решили свою проблему.Это может быть полезно для кого-то еще: -)

Использовать Messagecontract поверх Datacontract и только один MessageBodyMember с типом данных Stream, а все остальные параметры - это MessageHeader.Вот пример:

[MessageContract]

    public class CustomerDocumentModel : IDisposable
    {

        public CustomerDocumentModel(string documentName, string path)
        {
            DocumentName = documentName;
            Path = path;
        }

        [MessageHeader]
        public string DocumentName{get;set;}

        [MessageHeader]
        public string Path{get;set;}

        [MessageBodyMember]
        public System.IO.Stream FileByteStream{get;set;}

        public void Dispose()
        { 
            if (FileByteStream != null)
            {
                FileByteStream.Close();
                FileByteStream = null;
            }
        }
    }

Примечание : убедитесь, что в вашем режиме передачи конфигурации установлен StreamedResponse, также вы можете изменить MessageEncoding на MTOM для повышения производительности.

public void UploadCustomerDocument(CustomerDocumentModel model)
{
        var filename = //your file name and path;
        using (var fs = new FileStream(filename, FileMode.Create))

        {
               model.FileByteStream.CopyTo(fs);
        }
}
2 голосов
/ 03 октября 2011

Ваш тип данных - то, что заставляет потоковую передачу терпеть неудачу.Это задокументировано в MSDN здесь: http://msdn.microsoft.com/en-us/library/ms731913.aspx Соответствующий отрывок:

Ограничения на потоковые передачи

Использование режима потоковой передачи приводит к тому, что во время выполнения устанавливаются дополнительные ограничения.

Операции, выполняемые через потоковый транспорт, могут иметь контракт не более чем с одним входным или выходным параметром.Этот параметр соответствует всему телу сообщения и должен быть Message, производным типом Stream или реализацией IXmlSerializable.Возвращаемое значение для операции эквивалентно выходному параметру.

Некоторые функции WCF, такие как надежный обмен сообщениями, транзакции и защита на уровне сообщений SOAP, полагаются на буферизацию сообщений для передач.Использование этих функций может снизить или исключить преимущества в производительности, полученные благодаря потоковой передаче.Для защиты потокового транспорта используйте только безопасность транспортного уровня или безопасность транспортного уровня плюс защиту сообщений только для аутентификации.

Заголовки SOAP всегда буферизуются, даже если для режима передачи установлено потоковое состояние.Заголовки сообщения не должны превышать размер транспортной квоты MaxBufferSize.Для получения дополнительной информации об этом параметре см. Транспортные квоты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...