Please translate Old Code to new WebAPI code.

Topics: Web Api
Sep 28, 2011 at 4:38 AM

I can't seem to get this translated.  Could one of you on the team help me out?

Old Code:\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

WebRequest request = WebRequest.Create(new Uri("my targe website"));
request.Method = "POST";
request.Credentials = new NetworkCredential("un", "pw");
request.PreAuthenticate = true;
request.ContentType = "application/x-www-form-urlencoded"; //very important, can't get this to work in new api.

byte [] bytes = Encoding.UTF8.GetBytes(string.Format("amount={0}&currency={1}&card={2}&description={3}", 25425, "usd", stripeToken, "Test Charge for: " + DateTime.Now.ToString()));
request.ContentLength = bytes.Length;

using (Stream st = request.GetRequestStream() )
{
    st.Write (bytes, 0, bytes.Length);
}

WebResponse response = request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string qqqq = sr.ReadToEnd();

New Code does not work.////////////////////////////////////////////////////////////

HttpRequestMessage m = new HttpRequestMessage();
m.RequestUri = new Uri("https://my target site");
m.Method = HttpMethod.Post;
m.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", this.Get64("my cred"));

SMessage sm = new SMessage();
sm.amount = 25020;
sm.card = sToken;
sm.description = "Test from TPS1";
sm.currency = "usd";

//tried this, no workie.
ObjectContent<SMessage> content = new ObjectContent<SMessage>(sm, new MediaTypeHeaderValue("application/x-www-form-urlencoded"));

//tried this, no workie.
ObjectContent<string> content = new ObjectContent<string>(sm.ToString(), new MediaTypeHeaderValue("application/x-www-form-urlencoded"));

string urle = Server.UrlEncode(sm.ToString());
m.Content = new StringContent(urle);
HttpClient client = new HttpClient();
HttpResponseMessage response = client.Send(m);
string qqq = response.Content.ReadAsString();

Thanks for your help.

Terrence

 


Sep 28, 2011 at 5:39 AM
Edited Sep 28, 2011 at 6:02 PM
Hi Terrence,

Following is some quick and dirty translation...please note that this code does not have obvious validation checks in many places...hope this works for you...

//client side code
        public void SendMessage()
        {
            HttpClientHandler clientHandler = new HttpClientHandler();
            clientHandler.Credentials = new NetworkCredential("un", "pwd");
            clientHandler.PreAuthenticate = true;

            HttpClient client = new HttpClient(clientHandler);

            HttpRequestMessage request = new HttpRequestMessage();
            request.Method = HttpMethod.Post;
            SMessage msg1 = new SMessage() { Amount = 32.50, Card = "Visa", Currency = "USD", Description = "payment" };
            ObjectContent<SMessage> reqContent = new ObjectContent<SMessage>(msg1, "application/x-www-form-urlencoded");
            reqContent.Formatters.Add(new MyFormUrlEncodedFormatter()); // do this step so that the object is serialized in your form url encoded format
            request.Content = reqContent;

            //send request
            HttpResponseMessage response = client.Send(request);

            //for reading response having your form url encoded format
            SMessage msg2 = response.Content.ReadAs<SMessage>(new List<MediaTypeFormatter>() { new MyFormUrlEncodedFormatter() });
        }

public class SMessage
    {
        public double Amount { get; set; }
        public string Card { get; set; }
        public string Description { get; set; }
        public string Currency { get; set; }
    }

    public class MyFormUrlEncodedFormatter : MediaTypeFormatter
    {
        public MyFormUrlEncodedFormatter()
        {
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/x-www-form-urlencoded"));
        }

        protected override object OnReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders)
        {
            SMessage message = null;
            using (var reader = new StreamReader(stream))
            {
                string requestContent = reader.ReadToEnd();
                string[] formFields = requestContent.Split('&');
                message = new SMessage();

                foreach (string formField in formFields)
                {
                    string[] nameValuePair = formField.Split('=');
                    switch(nameValuePair[0].ToLower())
                    {
                        case "amount":
                            message.Amount = Convert.ToDouble(nameValuePair[1]);
                            break;
                        case "currency":
                            message.Currency = nameValuePair[1];
                            break;
                        case "card":
                            message.Card = nameValuePair[1];
                            break;
                        case "description":
                            message.Description = nameValuePair[1];
                            break;
                    }
                }
            }
            return message;
        }

        protected override void OnWriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
        {
            SMessage message = value as SMessage;
            if (message != null)
            {
                string content = string.Format("amount={0}&currency={1}&card={2}&description={3}", message.Amount, message.Currency, message.Card, message.Description);

               var writer = new StreamWriter(stream);
 writer.Write(content);
writer.Flush();
  } } }
Thanks,
Kiran
Sep 28, 2011 at 11:41 AM

Wow, thank you Kiran, I will give it a try tomorrow morning. 

Thank you again for your great code sample.

Terrence

Sep 28, 2011 at 4:46 PM

Kiran, I am getting an error:

When I hit this line:

HttpResponseMessage response = client.Send(request);

It steps into and out of the

protected override void OnWriteToStream
without error and then crashes.

Cannot access a closed Stream.

Any help would be appreciated.

Sep 28, 2011 at 6:06 PM

Terrence,

I was closing the stream after writing in the media type formatter (in the formatter's OnWriteToStream method)...

I have now updated the method in my previous post...

thanks,

Kiran

Coordinator
Sep 28, 2011 at 7:18 PM

Terrance

We actually have a form url encoded formatter included in our enhancements nuget package. If you download webapi.all / webapi.enhancements you will get.

Web api enhancements includes an extension method called MapServiceRoute which creates a custom configuration called WebApiConfiguration. It registers a form url encoded formatter if you use it. 

You can also just add the formatter directly and register it if you are not using the MapServiceRoute method.

Sep 28, 2011 at 7:46 PM

Kiran, thank  you for your update.

Glen, my service provider is telling me that I am submitting an xml message when I use the code that kiran submitted above, dispite using "application/x-www-form-urlencoded".  Will the extension method fix this issue?

Are you aware of any bugs that would cause the payload to not be converted into that format?

Thank you.

Terrence

Coordinator
Sep 28, 2011 at 8:00 PM

Terrence, are you trying to return form url encoded content, or send it?

Thanks

Glenn

Sep 28, 2011 at 8:02 PM

Glenn, I am posting data (with the above code) to the service in my Controller.

Coordinator
Sep 28, 2011 at 8:21 PM

Can you send me a repro? gblock@microsoft.com?

Thanks

Glenn