Condividi tramite


Procedure consigliate per lo sviluppo con WCF LOB Adapter SDK

È possibile usare le procedure consigliate in questo argomento per migliorare le applicazioni e gli adattatori.

Call Abort Before Close on Channel Exception

Quando si scrive un'applicazione che usa il modello di canale WCF, è necessario chiamare prima di chiamare IRequestChannel.AbortChannelFactory.Close. In caso contrario, ChannelFactory.Close genera un'eccezione.

Nell'esempio seguente, le operazioni del canale vengono tentate all'interno di un blocco try/catch. Se si verifica un'eccezione, il canale viene interrotto.

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.  
  }  
}  

Implementare gestori asincroni e sincroni

Se possibile, implementare gestori sia asincroni che sincroni nell'adapter. Se l'adattatore implementa solo chiamate sincrone, è possibile che si verifichino problemi di blocco durante l'elaborazione di un volume elevato di messaggi o quando l'adapter viene usato in un ambiente multithreading.

Utilizzare il pool di connessioni

WCF LOB Adapter SDK supporta il pool di connessioni per impostazione predefinita. Tuttavia, spetta allo sviluppatore dell'adattatore determinare quali proprietà di pool di connessioni esporre come proprietà di associazione. Le impostazioni del pool di connessioni disponibili sono definite all'interno Microsoft.ServiceModel.Channels.Common.ConnectionPoolSettingsdi .

Non sono disponibili opzioni all'interno del componente aggiuntivo Consume Adapter Service per esporre facilmente queste proprietà come proprietà di connessione dell'adapter. Lo sviluppatore dell'adattatore deve definire manualmente le proprietà nell'implementazione dell'adapter.

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

Assicurarsi che l'adapter supporti le operazioni di Two-Way

Se l'adattatore viene chiamato da BizTalk Server, deve supportare operazioni bidirezionali, anche se il valore restituito è void. Ciò è dovuto al fatto che BizTalk Server prevede una risposta restituita da qualsiasi richiesta in uscita e genera un'eccezione se l'adattatore implementa solo operazioni unidirezionale.

Di seguito è riportato un esempio di contratto di richiesta-risposta che restituisce void.

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

Implementare la traccia

Durante il ciclo di sviluppo, potrebbe non sembrare importante aggiungere traccia all'adattatore, perché è possibile eseguire il codice ed eseguire il debug di eventuali problemi. Tuttavia, dopo aver installato l'adattatore in un ambiente di produzione, potrebbe non essere possibile usare il debug in fase di esecuzione per isolare i problemi. Se è stata abilitata la traccia in tutta la scheda, può essere usata per isolare dove si verificano errori.

Per altri dettagli, vedere Tracciare un adattatore con WCF LOB Adapter SDK .

Usare le proprietà URI per le impostazioni modificate di frequente

Quando si decide se esporre una proprietà personalizzata come proprietà di associazione o URI, è consigliabile usare una proprietà URI se il valore cambia spesso. Le proprietà di associazione devono essere riservate per i valori che raramente cambiano.

Una proprietà di associazione di esempio è un nome del server di database utilizzato da tutte le connessioni. Una proprietà URI di esempio è una tabella o una stored procedure specifica da utilizzare da tale connessione specifica.

Non passare valori di nome utente o password nell'URI

Se l'adattatore richiede le credenziali del chiamante, è consigliabile usare la classe ClientCredentials per recuperare i valori delle credenziali anziché passare le credenziali client come parte dell'URI. La classe ClientCredentials è una funzionalità standard di WCF destinata al passaggio di informazioni sulle credenziali dal client al servizio in modo più sicuro. Il passaggio delle informazioni utente come parte della stringa URI può esporre le informazioni utente durante il transito.

I metodi consigliati per il passaggio delle credenziali sono illustrati nella tabella seguente.

Metodo Descrizione
Fase di progettazione Quando si usa il plug-in Aggiungi riferimento al servizio adapter, è possibile specificare i tipi di credenziali client supportati dall'adattatore.
Fase di esecuzione Quando si usa un proxy CLR .NET generato, è possibile impostare a livello di codice le credenziali client.

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"); }

In alternativa, se è necessario interagire direttamente con il canale, è possibile usare il modello di canale WCF per specificare le credenziali client durante la creazione di una channel factory.

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();
Configurazione WCF Nel file di configurazione del client aggiungere un <elemento endpointBehaviors> che include <clientCredentials>.

<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>
Uso di BizTalk Quando si usa l'adattatore WCF per utilizzare l'adapter, è possibile aggiungere l'estensione del comportamento clientCredentials nella scheda Comportamento . Dopo l'aggiunta, è possibile impostare le credenziali client desiderate nel comportamento dell'endpoint.

Non restituire sia StrongDataSetType che WeakDataSetType

Se l'adattatore restituisce un DataSetoggetto , usare Microsoft.ServiceModel.Channels.Common.QualifiedType.StrongDataSetType%2A o , Microsoft.ServiceModel.Channels.Common.QualifiedType.WeakDataSetType%2Ama non usare entrambi contemporaneamente. Il nome del nodo radice e lo spazio dei nomi prodotti da entrambi i tipi sono identici e non possono esistere contemporaneamente in un WSDL.

Mentre WeakDataSetType e StrongDataSetType entrambi rappresentano un System.Data.DataSet, StrongDataSetType è più facile da usare nelle applicazioni .NET, poiché il proxy generato viene visualizzato come System.Data.Dataset. Il proxy generato da WeakDataSetType è XmlElement[], che è più difficile da usare in un'applicazione .NET. BizTalk Server non può utilizzare lo schema restituito da StrongDataSet, ma è in grado di utilizzare WeakDataSetType.

Nota

StrongDataSetType e WeakDataSetType controllano solo il modo in cui l'applicazione client interpreta i messaggi XML passati dall'adapter. Il messaggio XML è lo stesso indipendentemente dal tipo specificato.

Nota

Quando si restituisce StrongDataSetType, è necessario impostare su Microsoft.ServiceModel.Channels.Common.MetadataSettings.CompileWsdl%2Afalse. Se impostato su true, il valore predefinito, XmlSchemaSet::Compile viene chiamato all'interno dell'adapter per assicurarsi che non siano presenti errori nel linguaggio WSDL, ma lo schema generato da StrongDataSetType genera un'eccezione in XmlSchemaSet.

L'impostazione CompileWsdl per false ignorare la convalida dello schema WSDL all'interno dell'adattatore e la convalida avviene durante la generazione del proxy. Le utilità, ad esempio svcutil.exe, possono generare un proxy sia per che StrongDataSetTypeWeakDataSetTypeper .

Per usare sia gli ambienti BizTalk che .NET, è consigliabile implementare una proprietà di associazione che consenta il passaggio tra i due tipi restituiti come determinato dall'ambiente.

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

Creare nomi di schemi XSD significativi in BizTalk Server

Quando si usa lo strumento di progettazione del componente aggiuntivo Del progetto BizTalk del servizio adapter, il nome dello schema XSD generato nel progetto BizTalk viene creato usando la DefaultXsdFileNamePrefix proprietà , l'annotazione fileNameHint nel linguaggio WSDL e, se necessario, un valore intero univoco.

Ad esempio, se DefaultXsdFileNamePrefix è impostato su "MyAdapter" e l'annotazione fileNameHint è impostata su "Stream", lo schema XSD creato è denominato 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>  

Nota

Il valore predefinito di DefaultXsdFileNamePrefix è il nome dell'associazione. Per specificare un valore diverso, eseguire l'override DefaultXsdFileNamePrefix nella classe Adapter derivata da Microsoft.ServiceModel.Channels.Common.AdapterBinding.

Esistono due metodi possibili per aggiungere l'annotazione fileNameHint allo schema: eseguire l'override dell'esportazione... Metodi dello schema in OperationMetadata\TypeMetadata o eseguono l'override dell'implementazione IWsdlRetrieval dell'adapter. Per entrambi i metodi, è possibile chiamare l'implementazione di base e quindi aggiungere l'annotazione agli schemi nella raccolta di schemi.

Nota

Quando si esegue l'override dell'esportazione... I metodi dello schema, possono essere presenti più definizioni di operazione/tipo nello stesso schema; l'adattatore deve assicurarsi che più occorrenze dell'annotazione fileNameHints nello stesso schema non siano in conflitto. Il componente aggiuntivo Consume Adapter Service usa la prima occorrenza di se si verifica più volte all'interno di fileNameHint uno schema.

Nell'esempio seguente, IWsdlRetrieval viene usato per aggiungere l'annotazione fileNameHint a 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);  
   }  

Non modificare adapterEnvironmentSettings durante l'elaborazione

L'adattatore deve impostare solo AdapterEnvironmentSettings, ConnectionPoolManager, ConnectionPool e CommonCacheSize durante l'inizializzazione dell'adapter e non deve tentare di modificare i valori per un'istanza in esecuzione.

Se queste impostazioni vengono modificate in un'istanza dell'adattatore attualmente in esecuzione, è possibile che le nuove connessioni sovrascrivano le impostazioni di configurazione per le connessioni attualmente in esecuzione.

Vedere anche

Procedure consigliate per lo sviluppo con WCF LOB Adapter SDK