次の方法で共有


WCF LOB アダプター SDK を使用した開発のベスト プラクティス

このトピックのベスト プラクティスを使用して、アプリケーションとアダプターを改善できます。

チャネル例外で閉じる前に中止を呼び出す

WCF チャネル モデルを使用するアプリケーションを作成するときは、ChannelFactory.Closeを呼び出す前にIRequestChannel.Abortを呼び出す必要があります。 そうしないと、 ChannelFactory.Close は例外をスローします。

次の例では、try/catch ブロック内でチャネル操作が試行されます。 例外が発生した場合、チャネルは中止されます。

ChannelFactory<IRequestChannel> cf = new  ChannelFactory<IRequestChannel>();  
IRequestChannel channel = null;  
try  
{  
  cf.Open();  
  channel = cf.CreateChannel();  
  channel.Open();  
  channel.Request();// This causes the channel to go into a faulted state.  
  channel.Close();  
}  
catch (Exception e)  
{  
  // Abort the channel if we have one  
  if(channel != null)  
    channel.Abort();  
}  
finally  
{  
  if (cf.State == CommunicationState.Opened)  
  {  
    cf.Close(); // It throws an exception that the channel is in a faulted state.  
  }  
}  

非同期ハンドラーと同期ハンドラーの両方を実装する

可能であれば、アダプターに非同期ハンドラーと同期ハンドラーの両方を実装します。 アダプターが同期呼び出しのみを実装している場合は、大量のメッセージを処理するとき、またはアダプターがマルチスレッド環境で使用されている場合に、ブロックの問題が発生する可能性があります。

接続プールの使用

WCF LOB アダプター SDK では、既定で接続プールがサポートされています。 ただし、バインディング プロパティとして公開する接続プーリング プロパティを決定するのは、アダプター開発者が行う必要があります。 使用可能な接続プールの設定は、 Microsoft.ServiceModel.Channels.Common.ConnectionPoolSettings内で定義されます。

アダプター接続プロパティとしてこれらのプロパティを簡単に公開するためのオプションは、アダプターサービスアドイン内にありません。 アダプター開発者は、アダプターの実装でプロパティを手動で定義する必要があります。

public CustomAdapter(): base()  
{  
   this.Settings.ConnectionPool.EnablePooling = true;  
   this.Settings.ConnectionPool.HandlersShareSameConnection = true;  
   this.Settings.ConnectionPool.MaxConnectionsPerSystem = 50;  
   this.Settings.ConnectionPool.MaxAvailableConnections = 5;  
}  

アダプターが Two-Way 操作をサポートしていることを確認する

BizTalk Server からアダプターを呼び出す場合、戻り値が void であっても、双方向の操作をサポートする必要があります。 これは、BizTalk Server が送信リクエストに対して返される応答を期待しており、アダプターが一方向操作のみを実装する場合には例外をスローするためです。

void を返す要求/応答コントラクトの例を次に示します。

[ServiceContract(Namespace=”Http:Microsoft.BizTalk.Samples.WCFAdapterSample”)]  
public interface ICalculator  
{  
   [OperationContract]  
   void Add(double n1, double n2);  
}  

トレースの実装

開発サイクル中は、コードをステップ実行して問題をデバッグできるため、アダプターにトレースを追加することは重要ではないようです。 ただし、アダプターが運用環境にインストールされると、実行時デバッグを使用して問題を特定できない場合があります。 アダプター全体でトレースを有効にしている場合は、エラーが発生している場所を特定するために使用できます。

詳細については、「 WCF LOB アダプター SDK を使用してアダプターをトレース する」を参照してください。

頻繁に変更される設定に URI プロパティを使用する

カスタム プロパティをバインドプロパティまたは URI プロパティとして公開するかどうかを決定するときは、値が頻繁に変更される場合は URI プロパティを使用することをお勧めします。 バインディング プロパティは、ほとんど変更されない値用に予約する必要があります。

バインディング プロパティの例は、すべての接続で使用されるデータベース サーバー名です。 URI プロパティの例は、その特定の接続で使用される特定のテーブルまたはストアド プロシージャです。

URI にユーザー名またはパスワードの値を渡さない

アダプターで呼び出し元の資格情報が必要な場合は、クライアント資格情報を URI の一部として渡す代わりに 、ClientCredentials クラスを使用して資格情報の値を取得することをお勧めします。 ClientCredentials クラスは WCF の標準機能であり、クライアントからサービスに資格情報をより安全に渡すことを目的としています。 URI 文字列の一部としてユーザー情報を渡すと、転送中にユーザー情報が公開される可能性があります。

資格情報を渡すための推奨される方法を次の表に示します。

メソッド 説明
設計時 アダプター サービス参照の追加プラグインを使用する場合は、アダプターがサポートするクライアント資格情報の種類を指定できます。
実行時 生成された .NET CLR プロキシを使用する場合は、クライアント資格情報をプログラムで設定できます。

static void Main(string[] args) { EchoServiceClient client = new EchoServiceClient(); client.ClientCredentials.UserName.UserName = "TestUser"; client.ClientCredentials.UserName.Password = "TestPassword"; string response=client.EchoString("Test String"); }

または、チャネルを直接操作する必要がある場合は、WCF チャネル モデルを使用して、チャネル ファクトリの作成時にクライアント資格情報を指定できます。

EchoAdapterBinding binding = new EchoAdapterBinding(); binding.Count = 3; ClientCredentials clientCredentials = new ClientCredentials(); clientCredentials.UserName.UserName = "TestUser"; clientCredentials.UserName.Password = "TestPassword"; BindingParameterCollection bindingParms = new BindingParameterCollection(); bindingParms.Add(clientCredentials); EndpointAddress address = new EndpointAddress("echo://"); IChannelFactory<IRequestChannel> requestChannelFactory = binding.BuildChannelFactory<IRequestChannel>(bindingParms); requestChannelFactory.Open();
WCF の構成 クライアント構成ファイルで、<clientCredentials> を含む <endpointBehaviors> 要素を追加します。

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> . . . . . <behaviors> <endpointBehaviors> <behavior name="clientEndpointCredential"> <clientCredentials> <windows allowNtlm="false" allowedImpersonationLevel="Delegation" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
BizTalk の使用 WCF アダプターを使用してアダプターを使用する場合は、[動作] タブに clientCredentials 動作拡張機能を追加できます。これが追加されたら、エンドポイントの動作で目的のクライアント資格情報を設定できます。

StrongDataSetType と WeakDataSetType の両方を返さない

アダプターが DataSetを返す場合は、 Microsoft.ServiceModel.Channels.Common.QualifiedType.StrongDataSetType%2A または Microsoft.ServiceModel.Channels.Common.QualifiedType.WeakDataSetType%2Aを使用しますが、両方を同時に使用しないでください。 両方の型によって生成されるルート ノード名と名前空間は同一であり、WSDL 内に同時に存在することはできません。

WeakDataSetTypeStrongDataSetTypeはどちらもSystem.Data.DataSetを表しますが、生成されたプロキシはSystem.Data.Datasetとして表示されるため、.NET アプリケーションではStrongDataSetTypeを使用する方が簡単です。 WeakDataSetTypeによって生成されるプロキシはXmlElement[]であり、.NET アプリケーションでは使用するのが難しくなります。 BizTalk Server は、 StrongDataSetから返されたスキーマを使用できませんが、 WeakDataSetTypeを使用できます。

StrongDataSetType WeakDataSetTypeは、クライアント アプリケーションがアダプターによって渡される XML メッセージを解釈する方法のみを制御します。 XML メッセージは、指定された型に関係なく同じです。

StrongDataSetTypeを返すときは、Microsoft.ServiceModel.Channels.Common.MetadataSettings.CompileWsdl%2Afalse に設定する必要があります。 trueに設定すると、既定のXmlSchemaSet::Compileがアダプター内で呼び出され、WSDL にエラーが発生しないようにしますが、StrongDataSetTypeによって生成されたスキーマでは、XmlSchemaSetで例外が生成されます。

CompileWsdlfalse に設定すると、アダプター内の WSDL スキーマ検証がバイパスされ、プロキシの生成中に検証が行われます。 svcutil.exe などのユーティリティは、 StrongDataSetTypeWeakDataSetTypeの両方のプロキシを生成できます。

BizTalk 環境と .NET 環境の両方を操作するには、環境によって指示される 2 つの戻り値の型を切り替えるバインディング プロパティを実装することを検討してください。

internal static QualifiedType GetDataSetQualifiedType(MyAdapterBindingProperties bindingProperties)  
{  
   if (bindingProperties.EnableBizTalkCompatibility)  
      return QualifiedType.WeakDataSetType;  
   else  
      return QualifiedType.StrongDataSetType;  
}  

BizTalk Server で意味のある XSD スキーマ名を作成する

アダプター サービス BizTalk プロジェクト アドインのデザイン時ツールを使用する場合、BizTalk プロジェクトで生成される XSD スキーマの名前は、 DefaultXsdFileNamePrefix プロパティ、WSDL の fileNameHint 注釈、および必要に応じて一意の整数値を使用して作成されます。

たとえば、 DefaultXsdFileNamePrefix が "MyAdapter" に設定され、 fileNameHint 注釈が "Stream" に設定されている場合、作成される XSD スキーマの名前は MyAdapterStream.xsd になります。

<xs:schema elementFormDefault='qualified' targetNamespace='http://schemas.microsoft.com/Message' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:tns='http://schemas.microsoft.com/Message'>  
<xs:annotation>  
<xs:appinfo>  
<fileNameHint xmlns='http://schemas.microsoft.com/servicemodel/adapters/metadata/xsd'>Stream</fileNameHint>  
</xs:appinfo>  
</xs:annotation>  
<xs:simpleType name='StreamBody'>  
<xs:restriction base='xs:base64Binary' />  
</xs:simpleType>  
</xs:schema>  

DefaultXsdFileNamePrefixの既定値は、バインドの名前です。 別の値を指定するには、Microsoft.ServiceModel.Channels.Common.AdapterBindingから派生した Adapter クラスのDefaultXsdFileNamePrefixをオーバーライドします。

スキーマに fileNameHint 注釈を追加するには、エクスポートのオーバーライドという 2 つの方法があります。OperationMetadata\TypeMetadata のスキーマ メソッド、またはアダプターの IWsdlRetrieval 実装をオーバーライドします。 どちらのメソッドでも、基本実装を呼び出し、スキーマ コレクション内のスキーマに注釈を追加できます。

エクスポートをオーバーライドする場合...スキーマ メソッドでは、同じスキーマに複数の操作/型定義が存在する可能性があります。アダプターは、同じスキーマ内の fileNameHints 注釈が複数回出現して競合しないようにする必要があります。 スキーマ内でfileNameHintが複数回発生した場合、アダプター サービス アドインは最初の出現を使用します。

次の例では、IWsdlRetrieval を使用して、 fileNameHint 注釈を WSDL に追加します。

sealed class MyAdapterWsdlRetrieval : IWsdlRetrieval  
{  
   IWsdlRetrieval mBaseWsdlRetrieval;  
   public MyAdapterWsdlRetrieval(IWsdlRetrieval baseWsdlRetrieval)  
   {  
      mBaseWsdlRetrieval = baseWsdlRetrieval;  
   }  

   ServiceDescription IWsdlRetrieval.GetWsdl(Microsoft.ServiceModel.Channels.MetadataRetrievalNode[] nodes, Uri uri, TimeSpan timeout)  
   {  
      ServiceDescription baseDesc = mBaseWsdlRetrieval.GetWsdl(nodes, uri, timeout);  
      foreach (XmlSchema schema in baseDesc.Types.Schemas)  
      {  
         CreateFileNameHint(schema);  
      }  
      return baseDesc;  
   }  

   void CreateFileNameHint(XmlSchema schema)  
   {  
      string targetNamespace = schema.TargetNamespace;  
      if (string.IsNullOrEmpty(targetNamespace))  
         return;  
      string fileNameHint = null;  
      //determine the filename based on namespace  
      if (targetNamespace.StartsWith("myadapter:// adapters.samples.myadaptpter/HelloWorld"))  
      {  
         fileNameHint = "HelloWorld";  
      }  
      if (targetNamespace.StartsWith("myadapter:// adapters.samples.myadapter/Hello"))  
      {  
         fileNameHint = "Hello";  
      }  
      //create the annotation and populate it with fileNameHint  
      XmlSchemaAnnotation annotation = new XmlSchemaAnnotation();  
      XmlSchemaAppInfo appInfo = new XmlSchemaAppInfo();  
      XmlDocument doc = new XmlDocument();  
      XmlNode[] fileNameHintNodes = new XmlNode[1];  
      fileNameHintNodes[0] = doc.CreateElement(null, "fileNameHint", "http://schemas.microsoft.com/servicemodel/adapters/metadata/xsd");  
      fileNameHintNodes[0].AppendChild(doc.CreateTextNode(fileNameHint));  
      appInfo.Markup = fileNameHintNodes;  
      annotation.Items.Add(appInfo);  
      schema.Items.Insert(0, annotation);  
   }  

処理中に AdapterEnvironmentSettings を変更しない

アダプターは、アダプターの初期化中に AdapterEnvironmentSettingsConnectionPoolManagerConnectionPoolCommonCacheSize のみを設定し、実行中のインスタンスの値の変更を試みないようにする必要があります。

現在実行中のアダプター インスタンスでこれらの設定が変更されると、現在実行中の接続の構成設定が新しい接続によって上書きされる可能性があります。

こちらもご覧ください

WCF LOB アダプター SDK を使用した開発のベスト プラクティス