none
POSTing to an API with Biztalk 2013 WCF-WebHttp Adapter RRS feed

  • Question

  • Hello, 

    I currently have a need to interface with a RESTful API with my Biztalk application to create new users via a POST method. The first step in doing so, is to authenticate an administrator account that my Biztalk app is using and obtaining a sessionID to be used in subsequent API calls. I am attempting to pass the credentials in a Biztalk message as follows:

    Schema:

    - <xs:complexType>
    - <xs:sequence>
           <xs:element name="Username" type="xs:string" />
           <xs:element name="Password" type="xs:string" />
     </xs:sequence>
     </xs:complexType>



    Webhttp binding and mapping:

    <BtsHttpUrlMapping>
    <Operation Name="Operation_1" Method="POST" Url="/login?username={username}&amp;password={password}"/>
    </BtsHttpUrlMapping>



    When I turn on my send port in the admin console, I get the following error:



    The adapter failed to transmit message going to send port "sprt_WF_Get_SessionID" with URL "<www.fakeapi.com>". It will be retransmitted after the retry interval specified for this Send Port. Details:"System.Net.WebException: The remote server returned an unexpected response: (400) Bad Request.
    {"error":{"class":"java.lang.IllegalArgumentException","message":"Login requests must use the POST method"}}".


    Which suggests my binding is trying to do something other than POST, despite having specified POST as the method in my mapping. Anyone know how to get the WCF-webhttp adapter to send it's data as a POST request?



    Any help would be appreciated.

    Alright, so the answer for this was 2 fold:

    1) I wasn't using a property schema to set my URL parameters. I created a property schema with the URL parameters I needed and then linked to that from my Request schema. Using that import, I then marked the fields I needed as URL parameters as properties via Right Click --> Show Promotions --> Properties tab --> Import property schema and then set property fields(similar to how you would promote fields). 

    2) My API calls were failing because my API is setup to require HTTPS. I was only using HTTP. Unfortunately BT returns a 302 status code in Fiddler and makes it look like it's sending a GET request, which led me down a bit of a rabbit hole. You can specify using HTTPS in the WCF-Webhttp send port binding by changing the Security Type setting on the Security tab to 'Transport'. The binding will then require your host address to use https, whereas before it required http. 

    Hope this helps someone else.



    • Edited by TomP623453 Friday, February 2, 2018 2:34 AM
    Wednesday, January 31, 2018 7:51 PM

Answers

  • Ok, that seems to be the problem... ;)

    The variable mapping is from Context Properties to the URL places.  Since it's context properties, the Variable Mapping table uses that paradigm, so...

    Property Name is the field name but the Property Namespace is the XML Namespace of the property Schema, not the .Net Type namespace.

    Similar to how BTS.Operation = Operation + http://schemas.microsoft.com/BizTalk/2003/system-properties

    Do you have a Property Schema already?  If not, you do need to create one for this, then set those Context Properties also in the Orchestration.  They don't need to be Promoted.

    • Edited by Johns-305MVP Thursday, February 1, 2018 3:12 PM
    • Marked as answer by TomP623453 Thursday, February 1, 2018 3:58 PM
    • Unmarked as answer by TomP623453 Thursday, February 1, 2018 3:58 PM
    • Marked as answer by TomP623453 Friday, February 2, 2018 2:27 AM
    Thursday, February 1, 2018 3:10 PM

All replies

  • Receive Location?  You mean Send Port?

    Either way, my first thought is IllegalArgumentException is more meaningful than the POST error.

    Also, are you setting WCF.Operation before the message hits the Adapter?

    Wednesday, January 31, 2018 8:04 PM
  • The IllegalArgumentException is feedback from hitting my /login/ endpoint with correct credentials as a GET request. If I hit my API with a valid POST request in Postman, and then change the request type to GET, this is the error it responds with. 

    As for WCF.Operation, I am not. Didn't know it existed until you mentioned it. If it has a default it would probably be a GET request, which makes sense given the above. Do you have any links I could read up on it's use with BTS2013 for REST APIs? Or where I would set this in BTS or BTS Admin Console?


    • Edited by TomP623453 Wednesday, January 31, 2018 8:13 PM
    Wednesday, January 31, 2018 8:11 PM
  • You can only set BTS.Operation in an Orchestration or Pipeline Component.

    So, use an Orchestration for now to see if that't the problem.

    Wednesday, January 31, 2018 10:34 PM
  • I have an Orchestration at the moment which is where I'm constructing my messages to send over to this WCF-Webhttp port. Do you know where in the Orchestration I can set this property? I was looking at work earlier today but I wasn't seeing anything.
    Thursday, February 1, 2018 6:12 AM

  • Webhttp binding and mapping:

    <BtsHttpUrlMapping>
    <Operation Name="Operation_1" Method="POST" Url="/login?username={username}&amp;password={password}"/>
    </BtsHttpUrlMapping>

    Hmmm. that's interesting. There is nothing wrong with the mapping and it should work.

    Can you please try to monitor traffic using Fiddler.

    Refer:

    http://mitchvanhelden.blogspot.co.uk/2013/09/using-fiddler-for-viewing-exchanged.html

    http://biztalktechie.blogspot.co.uk/2017/12/use-fiddler-with-biztalk-adapters-to.html


    Rachit Sikroria (Microsoft Azure MVP)

    Thursday, February 1, 2018 12:21 PM
    Moderator
  • Ok, if you're using an Orchestration, then BTS.Operation is automatically set to the Operation name of the operation of the Send Port.

    It may still be Operation_1 since that is a default.  But, if you properly named the Port and Operation, you will have to update the mapping to match.

    Thursday, February 1, 2018 1:34 PM
  • I'll take a look with Fiddler and post my findings. 

    As for BTS.Operation, I've been leaving my Operation names as Operation_1, but I've included that in the binding:

    <BtsHttpUrlMapping>
    <Operation Name="Operation_1" Method="POST" Url="/login?username={username}&amp;password={password}"/>
    </BtsHttpUrlMapping>

    You can see I've given it the name Operation_1, which matches my orchestration operation name. Is it a requirement to give unique operation names?

    Edit: Took a look with Fiddler, it seems my username and password URL parameters aren't being mapped correctly, though it is sending it as a POST request. Fiddler request:

    POST /fakeapi/login?username=&password= HTTP/1.1

    The message that I'm passing to my send port:

    "1.0" encoding="utf-8"?><ns0:Login_SessionID_Request xmlns:ns0="http://Company.Login_SessionID_Request">
      <Username>username@company.com</Username>
      <Password>company456</Password>
    </ns0:Login_SessionID_Request>

    Shouldn't the variable mapping in my binding insert the username/password into their respective locations in the URL? I.e. Biztalk should be creating the request URL as:

    /login?username=username@company.com&amp;password=company456


    • Edited by TomP623453 Thursday, February 1, 2018 2:33 PM
    Thursday, February 1, 2018 2:24 PM
  • Hi,

    You have specify variables for the HTTP Method URL Mapping. The variable maps normally to a promoted field in a message.

    You'll have to create a property schema in the correct namespace to capture those properties for use in routing/in your orchestration. You'll also have to use an XML Receive pipeline to make sure those properties are promoted properly.

    Refer: http://www.ithero.nl/post/2014/02/15/Using-Variable-Mapping-in-a-WCF-WebHttp-Send-Port-without-using-promoted-properties.aspx



    Rachit Sikroria (Microsoft Azure MVP)

    Thursday, February 1, 2018 2:41 PM
    Moderator
  • Did you complete the Variable Mapping configuration in the Send Port?

    Thursday, February 1, 2018 2:41 PM
  • Below is a screenshot of my variable mapping. The property namespace corresponds to the target namespace of my Login_Session_ID_Request schema in my BT orchestration. Not sure why the forum lets me post a link, but not upload a screen cap, sorry about that. 

    https://imgur.com/a/4g7Gp

    I'll try and work through Rachit's suggestion and see if that works. Rachit, would I still need a property schema if I'm promoting these 2 fields in my Login_SessionID_Request schema?



    • Edited by TomP623453 Thursday, February 1, 2018 2:52 PM
    Thursday, February 1, 2018 2:51 PM
  • Ok, that seems to be the problem... ;)

    The variable mapping is from Context Properties to the URL places.  Since it's context properties, the Variable Mapping table uses that paradigm, so...

    Property Name is the field name but the Property Namespace is the XML Namespace of the property Schema, not the .Net Type namespace.

    Similar to how BTS.Operation = Operation + http://schemas.microsoft.com/BizTalk/2003/system-properties

    Do you have a Property Schema already?  If not, you do need to create one for this, then set those Context Properties also in the Orchestration.  They don't need to be Promoted.

    • Edited by Johns-305MVP Thursday, February 1, 2018 3:12 PM
    • Marked as answer by TomP623453 Thursday, February 1, 2018 3:58 PM
    • Unmarked as answer by TomP623453 Thursday, February 1, 2018 3:58 PM
    • Marked as answer by TomP623453 Friday, February 2, 2018 2:27 AM
    Thursday, February 1, 2018 3:10 PM
  • For the Property Schema, should my Login_SessionID_Request message be using the property schema? Or should I be taking my normal schema and then linking the schema/nodes to the property schema via Promote --> Show Promotions --> Property Fields --> Add/Remove properties. 

    Should the request schema have it's own corresponding fields or just the imported property fields?

    Thursday, February 1, 2018 3:17 PM
  • The Property Schema is totally separate from your message schema.

    You add a Property Schema to your Project, then set the message Context Properties in the Orchestrations.

    MyOutgoingMessage(MyPropNS.MyPssword) = MyPasswordVariable;

    or some such.


    Thursday, February 1, 2018 3:25 PM
  • Sorry, I'm unfamiliar with message context properties, where do you access this in an orchestration?
    Thursday, February 1, 2018 3:40 PM
  • Instead of creating your own Property Schema, it's perfectly fine to reuse built in one.

    In this case, you can just use WCF.UserName and WCF.Password. **

    In the Orchestration, you can use the above syntax to set the values:

    MyOutgoingMessage(WCF.UserName) = "admin";

    Then the Variable Mapping would use:

    UserName & http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties

    **There might be one small complication with these, I just don't remember...try first, if there is a problem there is a workaround.

    Thursday, February 1, 2018 4:03 PM
  • Sorry, I'm unfamiliar with message context properties, where do you access this in an orchestration?

    Refer to the link shared in my previous post. That explain all.

    You have set it to the outgoing message before actually sending it.


    Rachit Sikroria (Microsoft Azure MVP)

    Thursday, February 1, 2018 4:07 PM
    Moderator
  • Ok. Got the property mapping sorted out, my Fiddler request is now coming out as:

    POST /fakeapi/login?username=user%40company.com&password=company456 HTTP/1.1

    However the response I'm getting from my API, even with this URL, is still the following: 

    The adapter failed to transmit message going to send port "sprt_WF_Get_SessionID" with URL "http://fakeapi.com". It will be retransmitted after the retry interval specified for this Send Port. Details:"System.Net.WebException: The remote server returned an unexpected response: (400) Bad Request.
    {"error":{"class":"java.lang.IllegalArgumentException","message":"Login requests must use the POST method"}}".

    Which leaves me a bit stumped. If Fiddler is showing the request as a POST, why is the API responding as if it were a GET request? I don't think it's necessarily an issue with the API I'm connecting to as using Postman it responds correctly to POST requests. 

    Thursday, February 1, 2018 4:28 PM
  • Well, I'd believe Fiddler over the other endpoint... :)

    Can you ask them to check the log?

    Thursday, February 1, 2018 4:31 PM
  • I can submit a support ticket to the 3rd party API (as this is a cloud based application that my company pays to access). 

    When I look the response in Fiddler, it's returning a 302 code. According to google, this response code is caused by the resource the request is looking for to be temporarily moved to the URL found in the 'Location' value in the response header. For my response, it seems like this redirect is still pointing at the same location:

    Response:

    HTTP/1.0 302 Found
    Location: https:fakeapi.com/login?username=user%40company.com&password=company456
    Server: server
    Connection: Keep-Alive
    Content-Length: 0

    Request:

    POST http://fakeapi/login?username=user%40company.com&password=company456 HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    Host: fakeapi.com
    Content-Length: 262
    Expect: 100-continue
    Accept-Encoding: gzip, deflate
    Connection: Keep-Alive

    <?xml version="1.0" encoding="utf-8"?><ns0:Login_SessionID_Request xmlns:ns0="http://Company.Login_SessionID_Request">
      <Username>user%40company.com</Username>
      <Password>company456</Password>
    </ns0:Login_SessionID_Request>

    Still scratching my head a bit. I noticed the response used https and the request is using http. Not sure if that matters or not. It seems like the 302 response code indicates a redirect that Biztalk is having problems following?


    • Edited by TomP623453 Thursday, February 1, 2018 7:18 PM
    Thursday, February 1, 2018 6:46 PM
  • How is possibile to bind the value in schema to value in send port inside an orchestration?

    EZ BizTalk Specialist

    Friday, May 24, 2019 7:24 AM