ここの例 (http://stackoverflow.com/questions/835839/client-configuration-to-consume-wcf-json-web-service) は単純明快です。単純なオブジェクトの配列を返す WCF RESTFUL JSON サービスを作成しました。JavaScript では、返されたものを問題なく処理できるため、Web クライアントは問題なく動作します。
このサービスを Web または C# クライアントから呼び出せるようにして、データを取得するコードを複製することなく、公開されたデータを複数のコンテキストで使用できるようにしたいと考えています。
私の C# コードには、プロキシ クライアント、インターフェイス コントラクト、構成ベースのバインディング定義があります。C# サービスと C# クライアント (テスト検証ハーネスとして使用する単純なコンソール アプリ) の間でインターフェイスとデータ コード モジュールを共有します。
C# クライアントでは、配列形式ではないデータが正常に返されます。サービスがオブジェクトの配列をそのまま返すか、単純なオブジェクトのラップされたプロパティとして返すとすぐに、クライアント側のシリアライザーはサイレントに失敗し、空の配列を返します。
トップレベルのクライアントコードは次のとおりです
// for managed code to call our Ajax/Json incident service, we need to reuse the interface contract,
// and use the ServiceModel.Channels infra to hand-code a proxy client.
public class IncidentClient : ClientBase<IIncidentServices.IGetActiveIncidents>, IIncidentServices.IGetActiveIncidents
{
public incidents GetActiveIncidents(string environmentAbbreviation)
{
return base.Channel.GetActiveIncidents(environmentAbbreviation);
}
}
class Program
{
static void Main(string[] args)
{
IncidentClient client = new IncidentClient();
incidents data = client.GetActiveIncidents("prod");
Console.Write("Call to GetActiveIncidents returned ");
if (null == data)
{
Console.WriteLine("no data (null)");
}
else
{
Console.WriteLine(data.incidentList.Count.ToString() + " rows of incident data.");
}
Console.WriteLine("\nPress any key to continue...");
Console.ReadLine();
}
}
}
コードを実行すると、行がゼロであることが常に通知され、デバッガーは空の配列が返されることを示します。ログをアクティブにすることで、WCF トレース ツールと交換されているメッセージをトレースしました。データが戻ってくるのを確認できます (配列内の 100 要素)。
トリッキーな部分は、シリアライザーが静かにデータを破棄することです。そのため、WCF clientBase ベースのプロキシを放棄して生の HTTP get を使用し、別の JSON パーサーを使用してデータを処理する必要があるのではないかと考えています。
私のデータ コントラクトは次のようになります。
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Dan.Test.Incident.Data
{
[DataContract(Name="incidents", Namespace="Dan.Test.Incident.Data")]
public class incidents
{
public incidents()
{
data = new List<incidentData>();
}
[DataMember(Name="incidentList")]
private List<incidentData> data;
[IgnoreDataMember]
public List<incidentData> incidentList
{
get {
if (null == data)
{
data = new List<incidentData>();
}
return data;
}
}
}
[DataContract(Name="incidentData", Namespace="Dan.Test.Incident.Data")]
[Serializable]
public class incidentData
{
// define incident members and accessors for read-only get operations
[DataMember(Name = "irNumber")]
private string m_irNumber = null; // the incident identifier as IR12345, etc.
[DataMember(Name = "title")]
private string m_title = null; // the title of the incident
[DataMember(Name = "devname")]
private string m_devname = null; // list of team members who were engaged
[DataMember(Name = "description")]
private string m_description = null; // description of the incident
[DataMember(Name = "startdate")]
private DateTime m_startdate;
[DataMember(Name = "priority")]
private int m_priority = 0;
[DataMember(Name = "environmentID")]
private int m_environmentID = 0;
[DataMember(Name = "status")]
private string m_status;
[DataMember(Name = "enddate")]
private DateTime m_enddate;
public incidentData()
{
}
}
}
私のインターフェース定義は
using Dan.Test.Incident.Data;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace IIncidentServices
{
[ServiceContract(Namespace = "Dan.Test.Incident.Data")]
public interface IGetActiveIncidents
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
incidents GetActiveIncidents(string environmentAbbreviation);
}
}
私の設定は次のように簡単です:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Error,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
<source propagateActivity="true" name="System.ServiceModel" switchValue="Verbose,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="c:\users\danro\documents\visual studio 2012\projects\gadgetactiveincidentservice\consoleapplication1\app_messages.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add initializeData="c:\users\danro\documents\visual studio 2012\projects\gadgetactiveincidentservice\consoleapplication1\app_tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true"
maxMessagesToLog="3000" maxSizeOfMessageToLog="100000" />
<endToEndTracing messageFlowTracing="true" />
</diagnostics>
<bindings>
<webHttpBinding>
<binding name="NewBinding2" openTimeout="00:05:00" receiveTimeout="00:50:00"
sendTimeout="00:05:00" hostNameComparisonMode="WeakWildcard"
maxBufferSize="2000000" maxBufferPoolSize="2000000" maxReceivedMessageSize="2000000"
useDefaultWebProxy="false" contentTypeMapper="">
<readerQuotas maxDepth="32" maxStringContentLength="100000" maxArrayLength="10000"
maxBytesPerRead="2000000" maxNameTableCharCount="100000" />
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webwcf">
<webHttp defaultBodyStyle="WrappedRequest" defaultOutgoingResponseFormat="Json"
automaticFormatSelectionEnabled="true" faultExceptionEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost/GadgetActiveIncidentService/ActiveIncidentService.svc"
behaviorConfiguration="webwcf" binding="webHttpBinding" bindingConfiguration="NewBinding2"
contract="IIncidentServices.IGetActiveIncidents" name="ActiveIncidentService" />
</client>
</system.serviceModel>
</configuration>
私のデータを見ると、これは戻ってきたものの短いスニペットです-そして、奇妙に見える唯一のものは、データの [d] __type 行です....
{"d":[{"__type":"incidentData:Dan.Test.Incident.Data",
"description":"My description","devname":"",
"enddate":"\/Date(1357995120000-0800)\/",
"environmentID":10,"irNumber":"IR742989","priority":1,
"startdate":"\/Date(1357973873643-0800)\/",
"status":"closed","title":"A subset of users "},
{"__type":"incidentData:Dan.Test.Incident.Data","description":"second description.",
"devname":"","enddate":"\/Date(1352871180000-0800)\/",
"environmentID":10,"irNumber":"IR595320","priority":2,
"startdate":"\/Date(1352758680000-0800)\/",
"status":"This incident has been downgraded.",
"title":"Users will be unable to upgrade"}]}
ここの誰かが、これを機能させるために私が何をする必要があるかを明らかにしてくれることを願っています:)
前もって感謝します
ダン