如何通过自定义行为在Biztalk 2013中使用D365 Web服务?

问题描述

我确实有一种情况,我必须使用Web服务将一些数据发送到D365。我已经看过https://docs.microsoft.com/en-us/biztalk/core/step-3d-enabling-biztalk-server-to-send-and-receive-messages-from-salesforce教程,了解如何使用具有OAuth安全功能的Web服务。基于此,我为WCF-Web-Http适配器开发了自定义行为。虽然出现以下错误

System.NullReferenceException:对象引用未设置为对象的实例。 服务器堆栈跟踪: 在D365.BizTalk.Adapter.Behaviors.D365RESTSecurityBehavior.BeforeSendRequest(消息和请求,IClientChannel通道)处 在System.ServiceModel.dispatcher.ImmutableClientRuntime.BeforeSendRequest(ProxyRpc&rpc) 在System.ServiceModel.Channels.ServiceChannel.PrepareCall(ProxyOperationRuntime操作,布尔单向,ProxyRpc&rpc) 在System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.Begin() 在System.ServiceModel.Channels.ServiceChannel.BeginCall处(字符串操作,布尔单向,ProxyOperationRuntime操作,Object [] ins,TimeSpan超时,AsyncCallback回调,Object asyncState) 在System.ServiceModel.Channels.ServiceChannel.BeginRequest(消息,TimeSpan超时,AsyncCallback回调,对象状态) 在System.ServiceModel.Channels.ServiceChannel.BeginRequest(消息,AsyncCallback回调,对象状态) 异常重新抛出为[0]: 在System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg) 在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgData,Int32类型) 在System.ServiceModel.Channels.IRequestChannel.BeginRequest(消息,AsyncCallback回调,对象状态) 在Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient 2.SendRequestMessage(IBaseMessage bizTalkMessage,IRequestChannel channel) at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient 2.SendMessage(IBaseMessage bizTalkMessage)中

我的自定义行为代码如下:


 - class D365OAuthToken

namespace D365.BizTalk.Adapter.Behaviors
{

public class D365OAuthToken
    {

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

}
 - class D365RESTSecurityBehavior

namespace D365.BizTalk.Adapter.Behaviors
{
    public class D365RESTSecurityBehavior : IClientMessageInspector,IEndpointBehavior
    {
         // Some constants
        private static string D365AuthEndpoint = "https://login.microsoftonline.com/*****/oauth2/token";

    // Configuration Properties
        private string client_id_;
        private string client_secret_;
        private string grant_type_;
        private string resource_;
        private int sessionTimeout_;

    

    // Private Properties
    private D365OAuthToken token_;
    private DateTime tokenExpiryTime_;

    public D365RESTSecurityBehavior(
        string client_id,string client_secret,string grant_type,string resource,int sessiontimeout)
    {
        this.client_id_ = client_id;
        this.client_secret_ = client_secret;
        this.grant_type_ = grant_type;
        this.resource_ = resource;
        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=" + client_id_ + "&")
                   .Append("client_secret=" + client_secret_);

            string result;

            try
            {
                result = HttpPost(D365AuthEndpoint,body.ToString());
            }
            catch (WebException)
            {
                // do something
                return;
            }

            // Convert the JSON response into a token object
            JavaScriptSerializer ser = new JavaScriptSerializer();
            this.token_ = ser.Deserialize<D365OAuthToken>(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,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)
    {
      
        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
    }
}

 - class D365RESTBehaviorElement

namespace D365.BizTalk.Adapter.Behaviors
{
    public class D365RESTBehaviorElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(D365RESTSecurityBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new D365RESTSecurityBehavior(ClientID,ClientSecret,GrantType,Resource,Sessiontimeout);
        }

        [ConfigurationProperty("client_id",Isrequired = true)]
        public string ClientID
        {
            get { return (string)this["client_id"]; }
            set { this["client_id"] = value; }
        }

        [ConfigurationProperty("client_secret",Isrequired = true)]
        public string ClientSecret
        {
            get { return (string)this["client_secret"]; }
            set { this["client_secret"] = value; }
        }

        [ConfigurationProperty("grant_type",Isrequired = true)]
        public string GrantType
        {
            get { return (string)this["grant_type"]; }
            set { this["grant_type"] = value; }
        }

        [ConfigurationProperty("resource",Isrequired = true)]
        public string Resource
        {
            get { return (string)this["resource"]; }
            set { this["resource"] = value; }
        }

        [ConfigurationProperty("sessiontimeout",Isrequired = false,DefaultValue = 300)]
        public int Sessiontimeout
        {
            get { return (int)this["sessiontimeout"]; }
            set { this["sessiontimeout"] = value; }
        }
    }
}

Configured WCF-WebHttp custom behavior

可能是我遗漏了某些东西或做错了。任何帮助或指导将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)