私のユースケース:
- 既に ASP.NET アプリケーションが動作しています
- そのアプリケーションの一部として新しい Web サービスを実装したい
- ASP.NET Web サービス (*.asmx)ではなく、WCF サービス (*.svc) を使用することになっています。
GetInterface()
サービスには、インターフェイスのインスタンスを返す1 つの操作が必要です。このインスタンスはサーバー上に存在する必要があり、クライアントにシリアライズされません。そのインターフェイスで呼び出されるメソッドは、サーバー上で実行する必要があります。
これが私が試したことです(どこが間違っていたか教えてください):
これをテストするために、新しいASP.NET Web アプリケーションプロジェクトを作成しました
ServiceSide
。そのプロジェクト内で、「追加→新しい項目」を使用してWCF サービスを追加しました。私はそれを呼んだ
MainService
。これにより、MainService
クラスとIMainService
インターフェイスの両方が作成されました。ここで、クライアントとサーバー間で共有されるインターフェイス宣言のみを含む、新しいクラス ライブラリプロジェクトを作成しました。
ServiceWorkLibrary
[ServiceContract] public interface IWorkInterface { [OperationContract] int GetInt(); }
に戻って、クラスでの実装だけでなくインターフェイス
ServiceSide
のデフォルトDoWork()
メソッドも置き換え、共有の単純な実装も追加しました。それらは次のようになります。IMainService
MainService
IWorkInterface
[ServiceContract] public interface IMainService { [OperationContract] IWorkInterface GetInterface(); } public class MainService : IMainService { public IWorkInterface GetInterface() { return new WorkInterfaceImpl(); } } public class WorkInterfaceImpl : MarshalByRefObject, IWorkInterface { public int GetInt() { return 47; } }
このアプリケーションを実行すると、ブラウザに次のようなデフォルトの Web サービス ページが表示されるという意味で「動作」します。
サービスを作成しました。
このサービスをテストするには、クライアントを作成し、それを使用してサービスを呼び出す必要があります。これは、コマンド ラインから次の構文で svcutil.exe ツールを使用して行うことができます。
svcutil.exe http://localhost:59958/MainService.svc?wsdl
これにより、クライアント クラスを含む構成ファイルとコード ファイルが生成されます。2 つのファイルをクライアント アプリケーションに追加し、生成されたクライアント クラスを使用してサービスを呼び出します。例えば:
それではクライアントに。別の Visual Studio で、新しいソリューションで呼び出される新しいコンソール アプリケーションプロジェクトを作成しました。プロジェクトを追加し、からの参照を追加しまし
ClientSide
た。ServiceWorkLibrary
ClientSide
次に、上記の
svcutil.exe
呼び出しを実行しました。これにより と が生成さMainService.cs
れoutput.config
、プロジェクトに追加しましたClientSide
。最後に、次のコードを
Main
メソッドに追加しました。using (var client = new MainServiceClient()) { var workInterface = client.GetInterface(); Console.WriteLine(workInterface.GetType().FullName); }
これは、コンストラクター呼び出しで不可解な例外で既に失敗しています。
output.config
に名前を変更することで、これを修正できましたApp.config
。の戻り値の型がではなく
GetInterface()
isであることに気付きました。理由を知っている人はいますか?しかし、先に進みましょう...object
IWorkInterface
これを実行すると
CommunicationException
、呼び出し時に次のようになりGetInterface()
ます。基になる接続が閉じられました: 接続が予期せず閉じられました。
これを修正して、IWorkInterface
期待どおりの透過プロキシを取得するにはどうすればよいですか?
私が試したこと
[KnownType(typeof(WorkInterfaceImpl))]
の宣言に追加してみましたWorkInterfaceImpl
。これを行うと、同じ場所で別の例外が発生します。これはNetDispatcherFaultException
、次のメッセージ付きです。メッセージを逆シリアル化しようとしているときにフォーマッタが例外をスローしました: パラメータhttp://tempuri.org/:GetInterfaceResultを逆シリアル化しようとしているときにエラーが発生しました。InnerException メッセージは、「行 1 位置 491 のエラーです。要素 'http://tempuri.org/:GetInterfaceResult' には、名前 'http://schemas.datacontract.org/2004/07/ にマップされる型からのデータが含まれています。 ServiceSide:WorkInterfaceImpl'. デシリアライザーは、この名前にマップされる型を認識しません。DataContractResolver の使用を検討するか、'WorkInterfaceImpl' に対応する型を既知の型のリストに追加します。たとえば、KnownTypeAttribute 属性を使用するか、DataContractSerializer に渡される既知の型のリストに追加します。詳細については、InnerException を参照してください。
InnerException
言及されたのSerializationException
はメッセージ付きです:行 1 位置 491 のエラー。要素 'http://tempuri.org/:GetInterfaceResult' には、名前 'http://schemas.datacontract.org/2004/07/ServiceSide:WorkInterfaceImpl' にマップされるタイプのデータが含まれています。デシリアライザーは、この名前にマップされる型を認識しません。DataContractResolver の使用を検討するか、'WorkInterfaceImpl' に対応する型を既知の型のリストに追加します。たとえば、KnownTypeAttribute 属性を使用するか、DataContractSerializer に渡される既知の型のリストに追加します。
これは、システムが型をシリアル化しようとしていることを示しているように見えることに注目してください。そうすべきではありません。代わりに透過プロキシを生成することになっています。シリアル化の試行を停止するにはどうすればよいですか?
クラス
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
に属性 を追加してみました。WorkInterfaceImpl
無効。インターフェイスの属性(共有ライブラリで宣言されている) を に
[ServiceContract]
変更してみました。また効果なし。IWorkInterface
ServiceWorkLibrary
[ServiceContract(SessionMode = SessionMode.Required)]
system.diagnostics
また、次の魔法の要素をWeb.config
in に追加してみましたServerSide
:<system.diagnostics> <!-- This logging is great when WCF does not work. --> <sources> <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> <listeners> <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\traces.svclog" /> </listeners> </source> </sources> </system.diagnostics>
これにより、約束どおりにファイルが生成され
c:\traces.svclog
ますが、その内容を理解できるかどうかはわかりません。生成されたファイルを Pastebin here に投稿しました。を使用すると、この情報をより使いやすい UI で表示できますsvctraceviewer.exe
。私はそうしましたが、率直に言って、それらすべてが私に何も教えてくれません...
私は何を間違っていますか?