none
ServiceHost側へのアイテム数の多いオブジェクトを引き渡す場合の問題 RRS feed

  • 質問

  • 以前投稿した問題もフィックスしておりませんが、更に問題が...


    WCFにより引き渡すパラメータオブジェクトのアイテム数(MaxItemsInObjectGraph)のデフォルト値が 65535
    となっており、大きな配列のデータをやり取りする際に

    ※クライアント ← サービスホスト(サービスホスト側からデータを受信する)の場合は

    Web.Config内の
        <behaviors>
          <serviceBehaviors>
            <behavior name="hogehoge.ServiceBehavior">
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="true" />
              <dataContractSerializer maxItemsInObjectGraph="2147483647" />  ← ココで値を設定
            </behavior>
          </serviceBehaviors>
        </behaviors>

    といのは承知していて、実動作でも問題なくクライアント側で受信できているのですが

    問題は、クライアント → サービスホスト(サービスホスト側にデータを送りつける)場合において
    App.configを使用している場合はWeb.Configと同様な設定を行うことで可能なのだと思うのですが
    ServiceChannelProxyをコード内で直書きしている際のコーディングについてです。
    現在下記のようなコーディングを行っていますが、クライアント → サービスホストへの大きな配列の
    送信には対応できているのでしょうか?



    ################################################################################
        Dim wshBind = New System.ServiceModel.WSHttpBinding()

        With wshBind

            '#### バインド関連設定 ####
            '名称設定
            .Name = "wsHttpBinding_RcsWcfServerService"
            '全般設定
            .AllowCookies = False
            .BypassProxyOnLocal = False
            .CloseTimeout = New TimeSpan(0, 30, 0)
            .HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard
            .MaxBufferPoolSize = Convert.ToInt64(Int32.MaxValue) * Convert.ToInt64(16)
            .MaxReceivedMessageSize = Convert.ToInt64(Int32.MaxValue) * Convert.ToInt64(1)
            .MessageEncoding = System.ServiceModel.WSMessageEncoding.Mtom
            .OpenTimeout = New TimeSpan(0, 30, 0)
            .ProxyAddress = Nothing
            .ReceiveTimeout = New TimeSpan(0, 30, 0)
            .SendTimeout = New TimeSpan(0, 30, 0)
            .TextEncoding = Text.Encoding.UTF8
            .TransactionFlow = False
            .UseDefaultWebProxy = False
            'ReaderQuotasプロパティ設定
            .ReaderQuotas.MaxArrayLength = 2147483647
            .ReaderQuotas.MaxBytesPerRead = 2147483647
            .ReaderQuotas.MaxDepth = 2147483647
            .ReaderQuotas.MaxNameTableCharCount = 2147483647
            .ReaderQuotas.MaxStringContentLength = 2147483647
            'ReliableSessionプロパティ設定
            .ReliableSession.Enabled = False
            .ReliableSession.InactivityTimeout = New TimeSpan(0, 30, 0)
            .ReliableSession.Ordered = True


            '#### セキュリティ関連設定 ####
            'セキュリティモード設定
            .Security.Mode = System.ServiceModel.SecurityMode.None
            'MessageSecurityプロパティ設定
            .Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic256
            .Security.Message.EstablishSecurityContext = True
            .Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows
            .Security.Message.NegotiateServiceCredential = True
            'TransportSecurityプロパティ設定
            .Security.Transport.ProxyCredentialType = System.ServiceModel.HttpProxyCredentialType.None
            .Security.Transport.Realm = ""
            .Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows

        End With
       

        'WCFサービスホスト側の参照アドレスをXMLファイルから取得しエンドポイント作成
        Dim endpointAddr As System.ServiceModel.EndpointAddress
        Dim szPath As System.String = ServiceFolderName & "/" & svcFileName
        Dim epURI As New System.UriBuilder("http", ServiceHostName, 80, szPath)
        endpointAddr = New System.ServiceModel.EndpointAddress(epURI.Uri.ToString)
        epURI = Nothing
       

        'WCFクライアントチャネル生成
        Dim cf As System.ServiceModel.ChannelFactory
        cf = New System.ServiceModel.ChannelFactory(Of Wcf.Client.IWcfClientChannel)(wshBind, endpointAddr)

        'シリアル化されるオブジェクトで許可される項目の最大数のカスタマイズ(配列の要素数など)
        For Each od As System.ServiceModel.Description.OperationDescription In cf.Endpoint.Contract.Operations
            Dim dataContractBehavior As System.ServiceModel.Description.DataContractSerializerOperationBehavior
            dataContractBehavior = od.Behaviors.Find(Of System.ServiceModel.Description.DataContractSerializerOperationBehavior)()
            If Not dataContractBehavior Is Nothing Then
                dataContractBehavior.MaxItemsInObjectGraph = 2147483647      '2G(defualt:65k)
            End If
        Next

        'WCFサービスリファレンスのチャネル生成
        Dim svcch As Wcf.Client.IWcfClientChannel
        svcch = cf.CreateChannel()

        svcch.Open()
       
       
       
        Dim buf(655350) As Byte
        svcch.updata(buf)         ←←←←←←←←← ここで以下の例外発生。
           
    ################################################################################


    %%%%%%%%%%%%%%%% 発生した例外 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    System.ServiceModel.CommunicationException
    Message:
    http://ServiceHost.hoge.co.jp/WcfService/Wcf.Server.Host.Service.svc に対する HTTP 応答の受信中にエラーが発生しました。
    この原因としては、サービス エンドポイント バインドが HTTP プロトコルを使用していないことが考えられます。
    また別の原因として、HTTP 要求コンテキストがサーバーによって中止された可能性もあります
    (サーバーがシャットダウンした場合など)。詳細についてはサーバー ログを参照してください。

           
    Server stack trace:        
       場所 System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
       場所 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       場所 System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
       場所 System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
       場所 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       場所 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

    Exception rethrown at [0]:
       場所 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       場所 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       場所 Wcf.Server.IService.uodata(Byte[] buf)
           
           
    InnerException Message:
    [基礎になる接続が閉じられました: 受信時に予期しないエラーが発生しました]
           
    InnerException StackTrace:
       場所 System.Net.HttpWebRequest.GetResponse()
       場所 System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
           
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
           

     

    但しこれは、当初クライアント ← サービスホスト(サービスホスト側からデータを受信する)処理において
    maxItemsInObjectGraphを設定していなかった際に、ServiceHost側で同様の例外が発生していたため、勝手に今回は
    逆側の問題かと解釈したわけですが、そもそもこの解釈が誤っているのかも???



    2011年5月13日 10:53

回答

  • 自己レスです。

    MSサポートへの問い合わせにより、解決しました。

    ASP.NET環境では良く起きる現象のようで...メジャーな事象らしいです(´ヘ`;)ハァ

    では、問題の解消方法を記します。

    全開このフォーラムに掲載したExceptionの内容ですが、見落としていたのですが
    InnerExceptionに関しては、実はもう2段階層化されているInnerExceptionがありました

    System.Web.HttpException: 要求の長さの最大値を超えました。
       場所 System.Web.HttpRequest.GetEntireRawContent()
       場所 System.Web.HttpRequest.get_InputStream()
       場所 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.GetInputStream()

    このExceptionは、ASP.NET において、リクエストのサイズが maxRequestLength という設定値
    (既定値は 4096KB) を越えた時に発生する例外だそうです。
    この値を調整するには、サーバー側のアプリケーションの web.config の httpRuntime 属性 の
    maxRequestLengthで指定可能のようです。

    httpRuntime 要素 (ASP.NET 設定スキーマ)
    http://msdn.microsoft.com/ja-jp/library/e1f13641

    HttpRuntimeSection.MaxRequestLength プロパティ
    http://msdn.microsoft.com/ja-jp/library/system.web.configuration.httpruntimesection.maxrequestlength

    <system.web>要素内に下記の <httpRuntime> 要素を追加しました。
    <httpRuntime maxRequestLength="2097151" />
    ※当該プロパティ値はInt32型ですが、実際Int32.MaxValueを指定すると、2097151以上は指定できないと怒られます。



    この問題の解決後、さらに大きなオブジェクトを送信しようとした場合に、送信に失敗する可能性があります。
    もう一つ IIS や ASP.NET の観点での調整する設定値として、要求フィルターのコンテンツ長の制限があるようです。
    これはデフォルトで30,000,000 バイト(28.6MB 程度) の制限値となります。
    こちらは、下記のリンク先に示すようにIIS上での設定値調整が必要のようです。

    要求制限 <requestLimits>
    http://technet.microsoft.com/ja-jp/library/ee431638.aspx



    これらの、対応により、当該問題はクリアされました。
    • 回答としてマーク RNC-COM 2011年6月1日 10:33
    2011年6月1日 10:32

すべての返信

  • 自己レスです

     

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

    にもありますが、"MaxItemsInObjectGraph "の設定手順に関しては上記のコーディングでほぼ正解のようですねぇ~

    ということは、例外発生の問題は、"MaxItemsInObjectGraph "にまつわる問題ではないのかもしれません

     

    もう少し、調べてみます。

     

     

    2011年5月16日 1:47
  • 自己レスです。

    MSサポートへの問い合わせにより、解決しました。

    ASP.NET環境では良く起きる現象のようで...メジャーな事象らしいです(´ヘ`;)ハァ

    では、問題の解消方法を記します。

    全開このフォーラムに掲載したExceptionの内容ですが、見落としていたのですが
    InnerExceptionに関しては、実はもう2段階層化されているInnerExceptionがありました

    System.Web.HttpException: 要求の長さの最大値を超えました。
       場所 System.Web.HttpRequest.GetEntireRawContent()
       場所 System.Web.HttpRequest.get_InputStream()
       場所 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.GetInputStream()

    このExceptionは、ASP.NET において、リクエストのサイズが maxRequestLength という設定値
    (既定値は 4096KB) を越えた時に発生する例外だそうです。
    この値を調整するには、サーバー側のアプリケーションの web.config の httpRuntime 属性 の
    maxRequestLengthで指定可能のようです。

    httpRuntime 要素 (ASP.NET 設定スキーマ)
    http://msdn.microsoft.com/ja-jp/library/e1f13641

    HttpRuntimeSection.MaxRequestLength プロパティ
    http://msdn.microsoft.com/ja-jp/library/system.web.configuration.httpruntimesection.maxrequestlength

    <system.web>要素内に下記の <httpRuntime> 要素を追加しました。
    <httpRuntime maxRequestLength="2097151" />
    ※当該プロパティ値はInt32型ですが、実際Int32.MaxValueを指定すると、2097151以上は指定できないと怒られます。



    この問題の解決後、さらに大きなオブジェクトを送信しようとした場合に、送信に失敗する可能性があります。
    もう一つ IIS や ASP.NET の観点での調整する設定値として、要求フィルターのコンテンツ長の制限があるようです。
    これはデフォルトで30,000,000 バイト(28.6MB 程度) の制限値となります。
    こちらは、下記のリンク先に示すようにIIS上での設定値調整が必要のようです。

    要求制限 <requestLimits>
    http://technet.microsoft.com/ja-jp/library/ee431638.aspx



    これらの、対応により、当該問題はクリアされました。
    • 回答としてマーク RNC-COM 2011年6月1日 10:33
    2011年6月1日 10:32