WCF/.NET で DataTable を返す
-
08-06-2019 - |
質問
DataTable を返したい WCF サービスがあります。DataTable を返すことが良い習慣であるかどうかに関して、これはよく議論されるトピックであることは承知しています。それはちょっと横に置いておきましょう。
以下のように、DataTable を最初から作成する場合は、まったく問題ありません。テーブルが作成され、データが設定されてクライアントに返され、すべてが正常に行われます。
[DataContract]
public DataTable GetTbl()
{
DataTable tbl = new DataTable("testTbl");
for(int i=0;i<100;i++)
{
tbl.Columns.Add(i);
tbl.Rows.Add(new string[]{"testValue"});
}
return tbl;
}
ただし、以下のようにテーブルを作成するためにデータベースにアクセスするとすぐに、CommunicationException「基になる接続が閉じられました:」が発生します。接続が予期せず閉じられました。」
[DataContract]
public DataTable GetTbl()
{
DataTable tbl = new DataTable("testTbl");
//Populate table with SQL query
return tbl;
}
テーブルはサーバー側で正しく設定されています。これは、ループして返したテスト テーブルよりも大幅に小さく、クエリは小さくて高速です。タイムアウトや大規模なデータ転送の問題はありません。まったく同じ関数と DataContracts/ServiceContracts/BehaviorContracts が使用されています。
テーブルへのデータの取り込み方法が、テーブルが正常に返されるかどうかに影響を与えるのはなぜでしょうか?
解決
同様の問題を抱えている人のために、私は問題を解決しました。それは数倍でした。
- Darren が提案し、Paul がバックアップしたように、構成内の Max..Size プロパティを拡大する必要がありました。SvcTraceViewer ユーティリティはこれを判断するのに役立ちましたが、常に最も役立つエラー メッセージを表示するとは限りません。
- また、クライアント側でサービス参照が更新されると、設定が正しく更新されない場合があるようです (例:サーバー上で設定値を変更しても、クライアント上で適切に更新されるとは限りません。デバッグ中にクライアント側とサーバー側の両方で Max..Size プロパティを複数回変更する必要がありました)
DataTable をシリアル化可能にするには、名前を付ける必要があります。デフォルトのコンストラクターではテーブルに名前が付けられないため、次のようになります。
return new DataTable();
次の場合はシリアル化できません。
return new DataTable("someName");
パラメータとして渡されたテーブルに名前を付けます。
テーブルに文字列を割り当てることで、いつでもテーブルに名前を付けることができることに注意してください。
TableName
DataTable のプロパティ。var table = new DataTable(); table.TableName = "someName";
それが誰かの役に立つことを願っています。
他のヒント
この種の WCF エラー (実際には多くのことを意味しないエラー) を診断する最良の方法は、トレースを有効にすることです。web.config ファイルに次の内容を追加します。
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information"
propagateActivity="true">
<listeners>
<add name="ServiceModelTraceListener"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
initializeData="wcf-traces.svclog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
その後、.NET Framework SDK (または Visual Studio) に付属する SvcTraceViewer.exe ユーティリティで、結果のファイルを開くことができます。私のマシンでは、%PROGRAMFILES%\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe にあります。
エラー メッセージ (赤の太字) を探すだけで、問題が何であるかを具体的に知ることができます。
Dataable をデータセットに追加し、次のようにテーブルを返しました。
DataTable result = new DataTable("result");
//linq to populate the table
Dataset ds = new DataSet();
ds.Tables.Add(result);
return ds.Tables[0];
それが役に立てば幸い :)
すべてのバインディング属性の最大値を設定すること以外。
Web サービスから渡したり返したりする各テーブルにテーブル名が必要であることを確認してください。 table.tablename
プロパティを空白にすることはできません。
必要な属性は、OperationContract (インターフェイス上) / Operation Behavior (メソッド上) です。
[ServiceContract]
public interface ITableProvider
{
[OperationContract]
DataTable GetTbl();
}
[OperationBehavior]
public DataTable GetTbl(){
DataTable tbl = new DataTable("testTbl");
//Populate table with SQL query
return tbl;
}
また、...サービス構成だと思います...エラーを送信できるように指定したいとします。メッセージのサイズが大きすぎるなどのエラーが発生する可能性があります。読者の割り当てなどをいじることでそれを修正できます。
デフォルトでは、wsHttpBinding の受信サイズ割り当ては 65 KB 程度なので、シリアル化されたデータ テーブルの XML がそれを超えると、エラーがスローされます(データ テーブルがデータを含むと 65 KB を超えると 95% 確信しています) )。
リーダーの割り当てなどの設定は、 web.config
/ app.config
または、コード内のバインディング インスタンスに設定することもできます。しかし、デフォルトで変更していない場合、おそらくそれが問題です。
WSHttpBindingBase メンバー - ReaderQuotas プロパティと MaxReceivedMessageSize プロパティを確認します。
おそらくクォータを超過した可能性があります。データテーブルが、接続で許可されている最大パケット サイズを超えています。
おそらく設定する必要があります MaxReceivedMessageSize そして 最大バッファサイズ 接続上の値をより高くします。
戻り値の型が失敗する理由は 3 つあります。 datatable
WCF サービス内
次のようにデータテーブル名を指定する必要があります。
MyTable=new DataTable("tableName");
WCF サービスのクライアント側に参照を追加する場合は、再利用可能な DLL を選択します
system.data
属性を指定してください
datatable
のようなメンバー変数[DataMember] public DataTable MyTable{ get; set; }
Darren の考えはおそらく正しいと思います。WCF に提供されているデフォルト値は笑えるほど小さいので、これらの値に遭遇すると追跡が難しいエラーが発生することになります。これらは、単純なテスト ケース以上のことを実行しようとするとすぐに表示されるようです。デバッグの問題は、クライアントとサーバーの両方のさまざまな構成 (サイズ) 設定に関連していることが判明し、認めたくないほど多くの時間を無駄にしました。結局、それらのほとんどすべてを変更したと思います。MaxBufferPoolSize、MaxBufferSize、MaxConnections、MaxReceivedMessageSize など。
そうは言っても、前述した SvcTraceViewer ユーティリティも優れています。期待していたほど役に立たなかったケースもいくつかありましたが、全体的には通信フローとエラーを分析するための優れたツールです。