このトピックのベスト プラクティスを使用して、アプリケーションとアダプターを改善できます。
チャネル例外で閉じる前に中止を呼び出す
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 内に同時に存在することはできません。
WeakDataSetType
とStrongDataSetType
はどちらも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%2A
を false
に設定する必要があります。
true
に設定すると、既定のXmlSchemaSet::Compile
がアダプター内で呼び出され、WSDL にエラーが発生しないようにしますが、StrongDataSetType
によって生成されたスキーマでは、XmlSchemaSet
で例外が生成されます。
CompileWsdl
を false
に設定すると、アダプター内の WSDL スキーマ検証がバイパスされ、プロキシの生成中に検証が行われます。 svcutil.exe などのユーティリティは、 StrongDataSetType
と WeakDataSetType
の両方のプロキシを生成できます。
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 を変更しない
アダプターは、アダプターの初期化中に AdapterEnvironmentSettings、 ConnectionPoolManager、 ConnectionPool、 CommonCacheSize のみを設定し、実行中のインスタンスの値の変更を試みないようにする必要があります。
現在実行中のアダプター インスタンスでこれらの設定が変更されると、現在実行中の接続の構成設定が新しい接続によって上書きされる可能性があります。