Using parameters from a x-www-form-urlencoded

I’m debugging a payment provider (PayEx.com) and using RunScope to intercept their callbacks, they send this request:

Headers

Connection: close
Content-Length: 200
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: <our_host>

Body
transactionRef=d68cafc5d6c8472a893eb0763efca625&transactionNumber=10526728&orderRef=c7853c2513fd45758b80b95a2dbaf9fa&orderId=50043628&accountNumber=50250954&zzzz=must+be+here+to+get+http+post+to+work&

And, I created a simple route to handle this:

[Route("/pspcallback/{ShopId}")]
[Api("Payment provider callback handling service for callbacks")]
public class PostPspCallbackData : IReturn<PostPspCallbackDataResponse>
{
    public int? ShopId { get; set; }
}

public class PostPspCallbackDataResponse
{
    public string Message { get; set; }
}

and

public class PspCallbackService : ServiceStack.Service
{
    public PostPspCallbackDataResponse Any(PostPspCallbackData request)
    {
         ...
    }
}

my issue is that, and using Postman to simulate the request I get the service to I get an error when trying to decode HttpContext.Current.Request.Params as it only contains 1 parameter and it’s content is

Params: {------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name=%22+transactionRef%22%0d%0a%0d%0ad68cafc5d6c8472a893eb0763efca625%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name%3d%22transactionNumber%22%0d%0a%0d%0a10526728%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name%3d%22orderRef%22%0d%0a%0d%0ac7853c2513fd45758b80b95a2dbaf9fa%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name%3d%22orderId%22%0d%0a%0d%0a50043628%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name%3d%22accountNumber%22%0d%0a%0d%0a50250954%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh%0d%0aContent-Disposition%3a+form-data%3b+name%3d%22zzzz%22%0d%0a%0d%0amust+be+here+to+get+http+post+to+work&%0d%0a------WebKitFormBoundaryLUgWgp27eXoSV1Xh–%0d%0a&ss-id=CtBaW4WeLaz3XMzLG6jc&ss-pid=BkvkCPapsRWNYe6xOjl1&ALL_HTTP=HTTP_CACHE_CONTROL%3ano-cache%0d%
0aHTTP_CONNECTION%3akeep-alive%0d%0aHTTP_CONTENT_LENGTH%3a756%0d%0aHTTP_CONTENT_TYPE%3aapplication%2fx-www-form-urlencoded%3b+charset%3dutf-8%0d%0aHTTP_ACCEPT%3a*%2f*%0d%0aHTTP_ACCEPT_ENCODING%3agzip%2c+deflate%0d%0aHTTP_ACCEPT_LANGUAGE%3aen-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d0.4%2cda%3bq%3d0.2%0d%0aHTTP_COOKIE%3ass-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1%0d%0aHTTP_HOST%3alocalhost%3a54461%0d%0aHTTP_USER_AGENT%3aMozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36%0d%0aHTTP_ORIGIN%3achrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop%0d%0aHTTP_POSTMAN_TOKEN%3a3d6e9765-751e-616f-4f4f-b3ba186c5be4%0d%0a&ALL_RAW=Cache-Control%3a+no-cache%0d%0aConnection%3a+keep-alive%0d%0aContent-Length%3a+756%0d%0aContent-Type%3a+application%2fx-www-form-urlencoded%3b+charset%3dutf-8%0d%0aAccept%3a+%2f%0d%0aAccept-Encoding%3a+gzip%2c+deflate%0d%0aAccept-Language%3a+en-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d
0.4%2cda%3bq%3d0.2%0d%0aCookie%3a+ss-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1%0d%0aHost%3a+localhost%3a54461%0d%0aUser-Agent%3a+Mozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36%0d%0aOrigin%3a+chrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop%0d%0aPostman-Token%3a+3d6e9765-751e-616f-4f4f-b3ba186c5be4%0d%0a&APPL_MD_PATH=%2fLM%2fW3SVC%2f5%2fROOT&APPL_PHYSICAL_PATH=D%3a%5cGavekortet%5csystem%5ccode%5crestapi.internal.webhost%5c&AUTH_TYPE=&AUTH_USER=&AUTH_PASSWORD=&LOGON_USER=&REMOTE_USER=&CERT_COOKIE=&CERT_FLAGS=&CERT_ISSUER=&CERT_KEYSIZE=&CERT_SECRETKEYSIZE=&CERT_SERIALNUMBER=&CERT_SERVER_ISSUER=&CERT_SERVER_SUBJECT=&CERT_SUBJECT=&CONTENT_LENGTH=756&CONTENT_TYPE=application%2fx-www-form-urlencoded%3b+charset%3dutf-8&GATEWAY_INTERFACE=CGI%2f1.1&HTTPS=off&HTTPS_KEYSIZE=&HTTPS_SECRETKEYSIZE=&HTTPS_SERVER_ISSUER=&HTTPS_SERVER_SUBJECT=&INSTANCE_ID=5&INSTANCE_META_PATH=%2fLM%2fW3SVC%2f5&LOCAL_ADDR=%3a%3a1&PATH_INF
O=%2fpspcallback%2f1&PATH_TRANSLATED=D%3a%5cGavekortet%5csystem%5ccode%5crestapi.internal.webhost%5cpspcallback%5c1&QUERY_STRING=&REMOTE_ADDR=%3a%3a1&REMOTE_HOST=%3a%3a1&REMOTE_PORT=4227&REQUEST_METHOD=POST&SCRIPT_NAME=%2fpspcallback%2f1&SERVER_NAME=localhost&SERVER_PORT=54461&SERVER_PORT_SECURE=0&SERVER_PROTOCOL=HTTP%2f1.1&SERVER_SOFTWARE=Microsoft-IIS%2f10.0&URL=%2fpspcallback%2f1&HTTP_CACHE_CONTROL=no-cache&HTTP_CONNECTION=keep-alive&HTTP_CONTENT_LENGTH=756&HTTP_CONTENT_TYPE=application%2fx-www-form-urlencoded%3b+charset%3dutf-8&HTTP_ACCEPT=%2f&HTTP_ACCEPT_ENCODING=gzip%2c+deflate&HTTP_ACCEPT_LANGUAGE=en-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d0.4%2cda%3bq%3d0.2&HTTP_COOKIE=ss-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1&HTTP_HOST=localhost%3a54461&HTTP_USER_AGENT=Mozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36&HTTP_ORIGIN=chrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop&HTTP_POSTMAN_TOKEN=3d6e9
765-751e-616f-4f4f-b3ba186c5be4}

but, from Postman, if I remove the Content-Type I get the normal data as:

Params: {+transactionRef=d68cafc5d6c8472a893eb0763efca625&transactionNumber=10526728&orderRef=c7853c2513fd45758b80b95a2dbaf9fa&orderId=50043628&accountNumber=50250954&zzzz=must%2bbe%2bhere%2bto%2bget%2bhttp%2bpost%2bto%2bwork%26&ss-id=CtBaW4WeLaz3XMzLG6jc&ss-pid=BkvkCPapsRWNYe6xOjl1&ALL_HTTP=HTTP_CACHE_CONTROL%3ano-cache%0d%0aHTTP_CONNECTION%3akeep-alive%0d%0aHTTP_CONTENT_LENGTH%3a756%0d%0aHTTP_CONTENT_TYPE%3amultipart%2fform-data%3b+boundary%3d----WebKitFormBoundaryZPyea00QR5DAo01e%0d%0aHTTP_ACCEPT%3a*%2f*%0d%0aHTTP_ACCEPT_ENCODING%3agzip%2c+deflate%0d%0aHTTP_ACCEPT_LANGUAGE%3aen-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d0.4%2cda%3bq%3d0.2%0d%0aHTTP_COOKIE%3ass-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1%0d%0aHTTP_HOST%3alocalhost%3a54461%0d%0aHTTP_USER_AGENT%3aMozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36%0d%0aHTTP_ORIGIN%3achrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop%0d%0aHTTP_POSTMAN_TOK
EN%3aaf30fee2-bac4-65a0-70bc-03808bf5c9a8%0d%0a&ALL_RAW=Cache-Control%3a+no-cache%0d%0aConnection%3a+keep-alive%0d%0aContent-Length%3a+756%0d%0aContent-Type%3a+multipart%2fform-data%3b+boundary%3d----WebKitFormBoundaryZPyea00QR5DAo01e%0d%0aAccept%3a+%2f%0d%0aAccept-Encoding%3a+gzip%2c+deflate%0d%0aAccept-Language%3a+en-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d0.4%2cda%3bq%3d0.2%0d%0aCookie%3a+ss-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1%0d%0aHost%3a+localhost%3a54461%0d%0aUser-Agent%3a+Mozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36%0d%0aOrigin%3a+chrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop%0d%0aPostman-Token%3a+af30fee2-bac4-65a0-70bc-03808bf5c9a8%0d%0a&APPL_MD_PATH=%2fLM%2fW3SVC%2f5%2fROOT&APPL_PHYSICAL_PATH=D%3a%5cGavekortet%5csystem%5ccode%5crestapi.internal.webhost%5c&AUTH_TYPE=&AUTH_USER=&AUTH_PASSWORD=&LOGON_USER=&REMOTE_USER=&CERT_COOKIE=&CERT_FLAGS=&CERT_ISSUER=&CERT_KEYSIZE=&CERT_S
ECRETKEYSIZE=&CERT_SERIALNUMBER=&CERT_SERVER_ISSUER=&CERT_SERVER_SUBJECT=&CERT_SUBJECT=&CONTENT_LENGTH=756&CONTENT_TYPE=multipart%2fform-data%3b+boundary%3d----WebKitFormBoundaryZPyea00QR5DAo01e&GATEWAY_INTERFACE=CGI%2f1.1&HTTPS=off&HTTPS_KEYSIZE=&HTTPS_SECRETKEYSIZE=&HTTPS_SERVER_ISSUER=&HTTPS_SERVER_SUBJECT=&INSTANCE_ID=5&INSTANCE_META_PATH=%2fLM%2fW3SVC%2f5&LOCAL_ADDR=%3a%3a1&PATH_INFO=%2fpspcallback%2f1&PATH_TRANSLATED=D%3a%5cGavekortet%5csystem%5ccode%5crestapi.internal.webhost%5cpspcallback%5c1&QUERY_STRING=&REMOTE_ADDR=%3a%3a1&REMOTE_HOST=%3a%3a1&REMOTE_PORT=4227&REQUEST_METHOD=POST&SCRIPT_NAME=%2fpspcallback%2f1&SERVER_NAME=localhost&SERVER_PORT=54461&SERVER_PORT_SECURE=0&SERVER_PROTOCOL=HTTP%2f1.1&SERVER_SOFTWARE=Microsoft-IIS%2f10.0&URL=%2fpspcallback%2f1&HTTP_CACHE_CONTROL=no-cache&HTTP_CONNECTION=keep-alive&HTTP_CONTENT_LENGTH=756&HTTP_CONTENT_TYPE=multipart%2fform-data%3b+boundary%3d----WebKitFormBoundaryZPyea00QR5DAo01e&HTTP_ACCEPT=%2f&HTTP_ACCEPT_ENCODING=gzip%2c+deflate&HTTP_ACCEPT_LANGUAGE=e
n-US%2cen%3bq%3d0.8%2cpt-PT%3bq%3d0.6%2cpt%3bq%3d0.4%2cda%3bq%3d0.2&HTTP_COOKIE=ss-id%3dCtBaW4WeLaz3XMzLG6jc%3b+ss-pid%3dBkvkCPapsRWNYe6xOjl1&HTTP_HOST=localhost%3a54461&HTTP_USER_AGENT=Mozilla%2f5.0+(Windows+NT+10.0%3b+Win64%3b+x64)+AppleWebKit%2f537.36+(KHTML%2c+like+Gecko)+Chrome%2f51.0.2704.103+Safari%2f537.36&HTTP_ORIGIN=chrome-extension%3a%2f%2ffhbjgbiflinjbdggehcddcbncdddomop&HTTP_POSTMAN_TOKEN=af30fee2-bac4-65a0-70bc-03808bf5c9a8}

so, if I don’t set the content type, I can access the correct data, but I can’t using application/x-www-form-urlencoded; charset=utf-8

is there a way to have access to the context data using the provider content type? What am I missing?

I did manage to get it work with some very-nasty code :frowning:

Could you provide a small stand-alone example which reproduces the issue? I created following DTO:

[Route("/pspcallback/{ShopId}")]
[Api("Payment provider callback handling service for callbacks")]
public class PostPspCallbackData : IReturn<PostPspCallbackDataResponse>
{
    public int? ShopId { get; set; }

    public string TransactionRef { get; set; }

    public int TransactionNumber { get; set; }

    public string OrderRef { get; set; }

    public int OrderId { get; set; }

    public int AccountNumber { get; set; }

    public string Zzzz { get; set; }
}

public class PostPspCallbackDataResponse
{
    public string Message { get; set; }
}

And then in postman make a post with the headers:

Connection:close
Content-Length:200
Content-Type:application/x-www-form-urlencoded; charset=utf-8

and body

transactionRef=d68cafc5d6c8472a893eb0763efca625&transactionNumber=10526728&orderRef=c7853c2513fd45758b80b95a2dbaf9fa&orderId=50043628&accountNumber=50250954&zzzz=must+be+here+to+get+http+post+to+work&

I choose raw radio button in postman when set body content.

The service is called correctly there were no errors, all data are filled by the values from the body.

Hi Bruno,

Can you post the raw HTTP Request / Response instead as the object variable dump isn’t sufficient to show what’s really happening. The most important part about the Content-Type Header is that it exactly matches what’s sent in the Request Body so sending application/x-www-form-urlencoded; charset=utf-8 is only valid if your Request body is sending Form Urlencoded string, e.g. foo=bar&baz=qux from your variable dump I’m seeing ------WebKitFormBoundary which is an indication that the Content-Type is multipart/form-data instead, see this StackOverflow Answer for an explanation between the two.