Condividi tramite


Passaggio 3d: Abilitazione di BizTalk Server per inviare e ricevere messaggi da Salesforce

Durante l'invio di messaggi è necessario eseguire l'autenticazione con Salesforce utilizzando l'interfaccia REST. I metodi di autenticazione per le chiamate REST supportate da Salesforce non sono disponibili per impostazione predefinita con l'adapter WCF-WebHttp che verrà utilizzato per richiamare l'interfaccia REST di Salesforce. Pertanto, verrà creato un comportamento dell'endpoint WCF personalizzato che verrà allegato all'adapter di invio e configurato per richiamare l'interfaccia REST di Salesforce.

In modo analogo, la risposta XML ricevuta da Salesforce non conterrà alcun spazio dei nomi. Affinché BizTalk Server elaborare il messaggio di risposta rispetto allo schema di risposta, il messaggio di risposta deve includere lo spazio dei nomi di destinazione. Verrà quindi creata una pipeline personalizzata usando Microsoft BizTalk ESB Toolkit per aggiungere uno spazio dei nomi al messaggio di risposta. Questa pipeline personalizzata verrà quindi utilizzata come pipeline di ricezione per la porta di invio WCF-WebHttp richiesta-risposta.

Aggiunta di un comportamento WCF personalizzato per l'autenticazione in Salesforce

Salesforce fornisce diverse opzioni per l'autenticazione delle applicazioni client. Verranno usati i termini salesforce come flusso username-password . Sul lato client WCF consente di creare controlli messaggio per modificare i messaggi prima che vengano inviati o ricevuti . Un controllo messaggi è un'estensione del runtime del client che viene configurata come comportamento. Un comportamento, a sua volta, viene aggiunto a un elemento dell'estensione del comportamento. Questo elemento viene registrato in machine.config con un nome di elemento, che lo rende disponibile per essere configurato come comportamento personalizzato su una porta WCF. Per altre informazioni, vedere Estensione di WCF con comportamenti personalizzati. Verrà utilizzato questo approccio per incorporare il flusso nomeutente-autenticazione per l'autenticazione con Salesforce. È necessario completare i seguenti passaggi di base:

  • Creazione di un controllo messaggi che esegue una chiamata HTTP POST all'endpoint di autenticazione Salesforce e che riceve un token di accesso. Il controllo messaggi aggiunge il token di autenticazione come valore dell'instestazione Authorization del messaggio della query da inviare a Salesforce. Il controllo messaggi aggiunge inoltre un'intestazione Accept al messaggio di richiesta affinché la risposta ricevuta sia in un formato XML. In caso contrario, Salesforce invia il messaggio nel formato JSON predefinito.

  • Creazione di un comportamento dell'endpoint per applicare il controllo messaggi all'endpoint client.

  • Creazione di un elemento di estensione del comportamento per consentire la configurazione del comportamento dell'endpoint.

Per creare un controllo messaggi

  1. Come parte della soluzione BtsSalesforceIntegration in Visual Studio, creare una libreria di classi C#. Denominarlo Microsoft.BizTalk.Adapter.Behaviors e aggiungere gli spazi dei nomi seguenti:

    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Channels;
    using System.Xml;
    using System.Net;
    using System.IO;
    using System.ServiceModel.Configuration;
    using System.Configuration;
    using System.Web.Script.Serialization;
    
  2. Dal Esplora soluzioni aggiungere riferimenti a System.ServiceModel, System.Web.Extensionse System.Configuration.

  3. Aggiungere una classe SalesforceOAuthToken con le proprietà seguenti. Questa classe rappresenta il token di autenticazione che viene ricevuto da Salesforce.

    public class SalesforceOAuthToken
    {
        public string id { get; set; }
        public string issued_at { get; set; }
        public string refresh_token { get; set; }
        public string instance_url { get; set; }
        public string signature { get; set; }
        public string access_token { get; set; }
    }
    
  4. Aggiungere una classe SalesforceRESTSecurityBehavior che implementa IClientMessageInspector e .IEndpointBehavior Questa classe include i HttpPost() metodi e FetchOAuthToken() che eseguono una chiamata HTTP POST all'endpoint di autenticazione salesforce per recuperare il token di autorizzazione.

    Poiché la SalesforceRESTSecurityBehavior classe implementa l'interfaccia IClientMessageInspector , deve implementare i due metodi e BeforeSendRequest()AfterReceiveReply() . Per questo scenario non è necessario eseguire alcuna operazione come parte del AfterReceiverReply() metodo . Tuttavia, il BeforeSendRequest() metodo richiama il FetchOAuthToken() metodo , che a sua volta chiama il HttpPost() metodo . Il BeforeSendRequest() metodo aggiunge quindi il token di autorizzazione come parte dell'intestazione del messaggio. Aggiunge anche l'intestazione Accept per assicurarsi che la risposta ricevuta da Salesforce sia in formato XML.

    L'implementazione IEndpointBehavior aggiunge semplicemente la classe message inspector al comportamento dell'endpoint client.

    public class SalesforceRESTSecurityBehavior : IClientMessageInspector, IEndpointBehavior
    {
        // Some constants
        private static string SalesforceAuthEndpoint = "https://login.salesforce.com/services/oauth2/token";
    
        // Configuration Properties
        private string username_;
        private string password_;
        private string consumerKey_;
        private string consumerSecret_;
        private int sessionTimeout_;
    
        // Private Properties
        private SalesforceOAuthToken token_;
        private DateTime tokenExpiryTime_;
    
        public SalesforceRESTSecurityBehavior(
            string username,
            string password,
            string consumerKey,
            string consumerSecret,
            int sessionTimeout)
        {
            this.username_ = username;
            this.password_ = password;
            this.consumerKey_ = consumerKey;
            this.consumerSecret_ = consumerSecret;
            this.sessionTimeout_ = sessionTimeout;
        }
    
        private void FetchOAuthToken()
        {
            if ((tokenExpiryTime_ == null) || (tokenExpiryTime_.CompareTo(DateTime.Now) <= 0))
            {
                StringBuilder body = new StringBuilder();
                body.Append("grant_type=password&")
                    .Append("client_id=" + consumerKey_ + "&")
                    .Append("client_secret=" + consumerSecret_ + "&")
                    .Append("username=" + username_ + "&")
                    .Append("password=" + password_);
    
                string result;
    
                try
                {
                    result = HttpPost(SalesforceAuthEndpoint, body.ToString());
                }
                catch (WebException)
                {
                    // do something
                    return;
                }
    
                // Convert the JSON response into a token object
                JavaScriptSerializer ser = new JavaScriptSerializer();
                this.token_ = ser.Deserialize<SalesforceOAuthToken>(result);
                this.tokenExpiryTime_ = DateTime.Now.AddSeconds(this.sessionTimeout_);
            }
        }
    
        public string HttpPost(string URI, string Parameters)
        {
            WebRequest req = WebRequest.Create(URI);
            req.ContentType = "application/x-www-form-urlencoded";
            req.Method = "POST";
    
            // Add parameters to post
            byte[] data = Encoding.ASCII.GetBytes(Parameters);
            req.ContentLength = data.Length;
            System.IO.Stream os = req.GetRequestStream();
            os.Write(data, 0, data.Length);
            os.Close();
    
            // Do the post and get the response.
            System.Net.WebResponse resp = null;
            resp = req.GetResponse();
    
            StreamReader sr = new StreamReader(resp.GetResponseStream());
            return sr.ReadToEnd().Trim();
        }
        #region IClientMessageInspector
    
        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            // do nothing
        }
        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            // We are going to send a request to Salesforce
            // Overview:
            // This behavior will do the following:
            // (1) Fetch Token from Salesforce, if required
            // (2) Add the token to the message
            // (3) Insert an Http Accept header so we get XML data in response, instead of JSON, which is default
            // Reference: http://www.salesforce.com/us/developer/docs/api_rest/index.htm
            //
            // (1) Authentication with Salesforce
            // (2) The token is added to the HTTP Authorization Header
            // (3) Add the Accept Header
            //
    
            HttpRequestMessageProperty httpRequest = null;
    
            if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name))
            {
                httpRequest = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
            }
    
            if (httpRequest == null)
            {
                // NOTE: Ideally, we shouldn’t get here for WebHttp
                httpRequest = new HttpRequestMessageProperty()
                {
                    Method = "GET",
                    SuppressEntityBody = true
                };
                request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest);
            }
    
            WebHeaderCollection headers = httpRequest.Headers;
            FetchOAuthToken();
    
            headers.Add(HttpRequestHeader.Authorization, "OAuth " + this.token_.access_token);
            headers.Add(HttpRequestHeader.Accept, "application/xml");
    
            return null;
        }
    
        #endregion IClientMessageInspector
    
        #region IEndpointBehavior
    
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            // do nothing
        }
    
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(this);
        }
    
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            // do nothing
        }
    
        public void Validate(ServiceEndpoint endpoint)
        {
            // do nothing
        }
    
        #endregion IEndpointBehavior
    }
    
  5. Nel passaggio precedente è stata creata una classe del comportamento che applica il controllo messaggi all'endpoint client. È ora necessario rendere questo comportamento disponibile per la configurazione dell'adapter WCF-WebHttp che invierà il messaggio di richiesta a Salesforce. Per rendere questo comportamento disponibile per la configurazione è necessario completare due operazioni:

    • Creare una classe che derivi da BehaviorExtensionElement

    • Registrare il behavaiorExtensionElement nell'elemento <extensions>\<behaviorExtensions> nel machine.config usando un nome di elemento.

      Inoltre, verranno aggiunte le proprietà di configurazione a questa classe affinché siano disponibili dall'interfaccia utente di configurazione dell'adapter WCF-WebHttp.

    public class SalesforceRESTBehaviorElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(SalesforceRESTSecurityBehavior); }
        }
    
        protected override object CreateBehavior()
        {
            return new SalesforceRESTSecurityBehavior(Username, Password, ConsumerKey, ConsumerSecret, SessionTimeout);
        }
    
        [ConfigurationProperty("username", IsRequired = true)]
        public string Username
        {
            get { return (string)this["username"]; }
            set { this["username"] = value; }
        }
    
        [ConfigurationProperty("password", IsRequired = true)]
        public string Password
        {
            get { return (string)this["password"]; }
            set { this["password"] = value; }
        }
    
        [ConfigurationProperty("consumerKey", IsRequired = true)]
        public string ConsumerKey
        {
            get { return (string)this["consumerKey"]; }
            set { this["consumerKey"] = value; }
        }
    
        [ConfigurationProperty("consumerSecret", IsRequired = true)]
        public string ConsumerSecret
        {
            get { return (string)this["consumerSecret"]; }
            set { this["consumerSecret"] = value; }
        }
    
        [ConfigurationProperty("sessionTimeout", IsRequired = false, DefaultValue = 300)]
        public int SessionTimeout
        {
            get { return (int)this["sessionTimeout"]; }
            set { this["sessionTimeout"] = value; }
        }
    }
    
  6. Aggiungere un file della chiave con nome sicuro al progetto e creare il progetto. Dopo la compilazione del progetto, aggiungere l'assembly Microsoft.BizTalk.Adapter.Behaviors alla GAC.

  7. Aggiungere la seguente voce a machine.config in System.ServiceModel\Extensions\BehaviorExtensions.

    <add name="Microsoft.BizTalk.Adapter.Behaviors.Demo.Salesforce" type="Microsoft.BizTalk.Adapter.Behaviors.SalesforceRESTBehaviorElement, Microsoft.BizTalk.Adapter.Behaviors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=45bd7fe67ef032db"/>
    

    È possibile creare il token della chiave pubblica per l'assembly dal GAC. Inoltre, se si sta creando questa applicazione su un computer a 64 bit, è necessario aggiungere questa voce sia alle versioni a 32 bit che a quelle a 64 bit di machine.config.

Aggiunta di una pipeline personalizzata per aggiungere lo spazio dei nomi alla risposta di Salesforce

La risposta ricevuta da Salesforce non include uno spazio dei nomi. Tuttavia, per elaborare il messaggio di risposta confrontandolo con lo schema di risposta (QueryResult.xsd) è necessario includere lo spazio dei nomi nella risposta di Salesforce. In questa sezione viene creata una pipeline personalizzata e viene usato un componente della pipeline personalizzato fornito con Microsoft BizTalk ESB Toolkit per aggiungere uno spazio dei nomi al messaggio di risposta. Questa pipeline personalizzata viene distribuita con l'applicazione BizTalk Server e verrà usata come pipeline di ricezione durante la configurazione dell'adattatore WCF-WebHttp.

Prima di eseguire i passaggi di questa procedura, assicurarsi che Microsoft BizTalk ESB Toolkit sia installato e configurato nel computer in cui si sta creando l'applicazione.

Per aggiungere una pipeline personalizzata

  1. All'interno della soluzione BtsSalesforceIntegration creare un nuovo progetto di BizTalk Server. Assegnare al progetto il nome CustomPipeline.

  2. All'interno del progetto CustomPipeline aggiungere una nuova pipeline di ricezione. Assegnare alla pipeline AddNamespace.btpil nome .

  3. Nella fase Decodifica della pipeline trascinare e rilasciare il componente della pipeline Aggiungi spazio dei nomi ESB dalla casella degli strumenti. Nella fase Disassemble trascinare e rilasciare il componente della pipeline del disassembler XML .

    Nota

    Se il componente della pipeline Aggiungi spazio dei nomi ESB non è elencato nella casella degli strumenti, è possibile aggiungerlo. Fare clic con il pulsante destro del mouse sulla scheda Componenti della pipeline BizTalk e quindi scegliere Scegli elementi. Nella finestra di dialogo Scegli elementi della casella degli strumenti fare clic sulla scheda Componenti della pipeline BizTalk , selezionare la casella di controllo per Componente Aggiungi spazio dei nomi ESB e quindi fare clic su OK.

  4. Aggiungere al progetto un file della chiave con nome sicuro e salvare il progetto.

  5. Fare clic con il pulsante destro del mouse sul progetto CustomPipeline e scegliere Proprietà. Nella scheda Distribuzione immettere SalesforceIntegrationin Nome applicazione .

  6. Salvare le modifiche apportate al progetto.

    In questo argomento è stato aggiunto un comportamento predefinito per l'autenticazione con Salesforce e una pipeline personalizzata per inserire uno spazio dei nomi nella risposta Salesforce. Questi componenti personalizzati verranno usati durante la configurazione delle porte fisiche nella console di amministrazione di BizTalk Server.

Vedere anche

Passaggio 3: Creare la soluzione BizTalk Server in Visual Studio