Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I post data to MVC Controller using HttpWebRequest?

Tags:

c#

asp.net-mvc

I am trying to post data to MVC controller action but have been unsuccessful so far.

Here is the structure of the post data:

private string makeHttpPostString(XmlDocument interchangeFile)
    {
        string postDataString = "uid={0}&localization={1}&label={2}&interchangeDocument={3}";

        InterchangeDocument interchangeDocument =  new InterchangeDocument(interchangeFile);
        using (var stringWriter = new StringWriter())
        using (var xmlTextWriter = XmlWriter.Create(stringWriter))
        {
            interchangeFile.WriteTo(xmlTextWriter);
            string interchangeXml = HttpUtility.UrlEncode(stringWriter.GetStringBuilder().ToString());
            string hwid = interchangeDocument.DocumentKey.Hwid;
            string localization = interchangeDocument.DocumentKey.Localization.ToString();
            string label = ConfigurationManager.AppSettings["PreviewLabel"];

            return (string.Format(postDataString, hwid, localization, label, interchangeXml));
        }

    }

Here is the request:

 HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(controllerUrl);

        webRequest.Method = "POST";
      //  webRequest.ContentType = "application/x-www-form-urlencoded";

        string postData = makeHttpPostString(interchangeFile);
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        webRequest.ContentLength = byteArray.Length;

        using (Stream dataStream = webRequest.GetRequestStream())
        {
            dataStream.Write(byteArray, 0, byteArray.Length);
        }

        HttpWebResponse webresponse = (HttpWebResponse) webRequest.GetResponse();

When I set the contenttype of the request to "application/x-www-form-urlencoded" GetReponse() fails with server error code 500. When I comment that out and only httpencode the xml data, "interchangeXml", the post is sent but only the 3rd parameter, "label" reaches the controller. The others are null.

What is the correct way to post values to a controller action when one of those values is xml data?

Thanks!

Update

I am send all the parameter with the exception of the XML via the query string. However, the problem now is that I do not know how to access the posted data in the controller action. Can someone tell me how I access the xml from the HttpRequest from with my Controller Action?

Update

I have refactored the above code to use the suggests made to me by Darin. I am recieveing an internal server error (500) using the WebClient UploadValues().

Action:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult BuildPreview(PreviewViewModel model)
        {
            ...
        }

Request:

private string PostToSxController(XmlDocument interchangeFile, string controllerUrl)
        {
            var xmlInterchange = new InterchangeDocument(interchangeFile);
            using (var client = new WebClient())
            {
                var values = new NameValueCollection()
                                 {
                                     {"uid", xmlInterchange.DocumentKey.Hwid},
                                     {"localization", xmlInterchange.DocumentKey.Localization.ToString()},
                                     {"label", ConfigurationManager.AppSettings["PreviewLabel"]},
                                     {"interchangeDocument", interchangeFile.OuterXml }
                                 };

                 byte[] result = null;

                try
                {
                    result = client.UploadValues(controllerUrl, values);
                }
                catch(WebException ex)
                {
                    var errorResponse = ex.Response;
                    var errorMessage = ex.Message;
                }

                Encoding encoding = Encoding.UTF8;
               return encoding.GetString(result);


            }
        }

Route:

routes.MapRoute(
                "BuildPreview",
                "SymptomTopics/BuildPreview/{model}",
                new { controller = "SymptomTopics", action = "BuildPreview", model = UrlParameter.Optional  }
            );
like image 654
Nick Avatar asked Jun 07 '11 19:06

Nick


1 Answers

Too complicated and unsafe your client code with all those requests and responses. You are not encoding any of your request parameters, not to mention this XML which is probably gonna break everything if you don't encode it properly.

For this reason I would simplify and leave the plumbing code about encoding, etc... to the .NET framework:

using (var client = new WebClient())
{
    var values = new NameValueCollection
    {
        { "uid", hwid },
        { "localization", localization },
        { "label", label },
        { "interchangeDocument", interchangeFile.OuterXml },
    };
    var result = client.UploadValues(controllerUrl, values);
    // TODO: do something with the results returned by the controller action
}

As far as the server side is concerned, as every properly architected ASP.NET MVC application, it would obviously use a view model:

public class MyViewModel
{
    public string Uid { get; set; }
    public string Localization { get; set; }
    public string Label { get; set; }
    public string InterchangeDocument { get; set; }
}

with:

[HttpPost]
public ActionResult Foo(MyViewModel model)
{
    // TODO: do something with the values here
    ...
}

Obviously this could be taken a step further by writing a view model reflecting the structure of your XML document:

public class Foo
{
    public string Bar { get; set; }
    public string Baz { get; set; }
}

and then your view model will become:

public class MyViewModel
{
    public string Uid { get; set; }
    public string Localization { get; set; }
    public string Label { get; set; }
    public Foo InterchangeDocument { get; set; }
}

and the last part would be to write a custom model binder for the Foo type that will use a XML serializer (or whatever) to deserialize back the InterchangeDocument POSTed value into a Foo instance. Now that's serious business.

like image 183
Darin Dimitrov Avatar answered Nov 14 '22 23:11

Darin Dimitrov