2

WPF デスクトップ クライアントがファイルをサーバーにアップロードできるようにする WCF サービスを構築しようとしています。

The Code Project ( WCF Streaming: Upload/Download Files Over HTTP )のコード サンプルを採用し、SO の投稿もいくつか見ましたが、うまくいかないようです。

コードを実行すると、サーバーがインターフェイスを介して渡されたストリームを読み取ろうとした時点で null 参照例外が発生して失敗します。

この時点で、私はかなり迷っており、これを修正する方法がわかりません。任意の提案をいただければ幸いです。

コード サンプルは次のとおりです。

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();
            }
        }
    }
}

私の WCF Web サーバーの web.config からのいくつかの関連ビット:

<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>

クライアントは、CustomerDocumentModel モデルを作成し、OpenFileDialog を使用してファイル ストリームを Open() し、モデルを WCF サービスの UploadCustomerDocument メソッドに渡す WPF/MVVM アプリです。

関連する詳細が不足している場合は、お問い合わせください。

4

2 に答える 2

4

あなたの質問への返信が非常に遅くなったことは承知しており、あなたも問題を解決したに違いないと確信しています。これは他の誰かに役立つかもしれません:-)

Datacontract よりも Messagecontract を使用し、データ型が Stream の MessageBodyMember を 1 つだけ使用し、残りのすべてのパラメーターは 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);
        }
}
于 2012-03-30T19:28:01.513 に答える
2

あなたのデータ型は、ストリーミングが失敗する原因です。これは MSDN で文書化されています: http://msdn.microsoft.com/en-us/library/ms731913.aspx 関連する文章は次のとおりです。

ストリーミング転送の制限

ストリーミング転送モードを使用すると、ランタイムによって追加の制限が適用されます。

ストリーミングされたトランスポート全体で発生する操作は、最大で 1 つの入力または出力パラメーターとのコントラクトを持つことができます。そのパラメーターは、メッセージの本文全体に対応し、Message、Stream の派生型、または IXmlSerializable 実装である必要があります。操作の戻り値を持つことは、出力パラメーターを持つことと同じです。

信頼できるメッセージング、トランザクション、SOAP メッセージ レベルのセキュリティなどの一部の WCF 機能は、送信のためにメッセージのバッファリングに依存しています。これらの機能を使用すると、ストリーミングを使用することによって得られるパフォーマンス上の利点が減少または消失する可能性があります。ストリーミング トランスポートをセキュリティで保護するには、トランスポート レベルのセキュリティのみを使用するか、トランスポート レベルのセキュリティと認証のみのメッセージ セキュリティを使用します。

転送モードがストリーミングに設定されている場合でも、SOAP ヘッダーは常にバッファリングされます。メッセージのヘッダーは、MaxBufferSize トランスポート クォータのサイズを超えてはなりません。この設定の詳細については、「トランスポート クォータ」を参照してください。

于 2011-10-03T14:54:43.860 に答える