使用 WCF LOB 配接器 SDK 的開發最佳做法
您可以使用本主題中的最佳做法來改善您的應用程式和配接器。
在通道例外狀況關閉之前呼叫中止
當您撰寫使用 WCF 通道模型的應用程式時,您應該先呼叫 IRequestChannel.Abort
,再呼叫 ChannelFactory.Close
。 如果沒有, 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 中傳遞使用者名稱或密碼值
如果您的配接器需要呼叫端的認證,建議您使用 ClientCredentials 類別來擷取認證值,而不是將用戶端認證當做 URI 的一部分傳遞。 ClientCredentials類別是 WCF 的標準功能,旨在以更安全的方式將認證資訊從用戶端傳遞至服務。 將使用者資訊當做 URI 字串的一部分傳遞,可能會在傳輸時公開使用者資訊。
下表顯示傳遞認證的建議方法。
方法 | Description |
---|---|
設計階段 | 使用 [新增配接器服務參考外掛程式] 時,您可以指定配接器支援的用戶端認證類型。 |
執行階段 | 使用產生的 .NET CLR Proxy 時,您可以透過程式設計方式設定用戶端認證。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
, StrongDataSetType
但較容易在 .NET 應用程式中使用,因為產生的 Proxy 會顯示為 System.Data.Dataset
。 所產生的 WeakDataSetType
Proxy 是 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 架構驗證,並在 Proxy 產生期間進行驗證。 svcutil.exe 之類的公用程式能夠同時產生 和 WeakDataSetType
的 StrongDataSetType
Proxy。
若要同時使用 BizTalk 和 .NET 環境,請考慮實作系結屬性,以允許切換環境所指定的兩個傳回型別。
internal static QualifiedType GetDataSetQualifiedType(MyAdapterBindingProperties bindingProperties)
{
if (bindingProperties.EnableBizTalkCompatibility)
return QualifiedType.WeakDataSetType;
else
return QualifiedType.StrongDataSetType;
}
在 BizTalk Server 中建立有意義的 XSD 架構名稱
使用取用配接器服務 BizTalk 專案增益集設計階段工具時,會使用 DefaultXsdFileNamePrefix
屬性建立 BizTalk 專案中產生的 XSD 架構名稱、 fileNameHint
WSDL 中的批註,並視需要建立唯一的整數值。
例如,如果 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
至架構:覆寫匯出...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 ,而且不應該嘗試修改執行中實例的值。
如果在目前正在執行的配接器實例上修改這些設定,這可能會導致新的連線覆寫目前執行連線的組態設定。