6

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  }
            );
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Nick
  • 19,198
  • 51
  • 185
  • 312
  • What is the data structure your MVC action expecting? Could you not just post all the data in xml, as opposed to query string? – Jay Jun 07 '11 at 20:24
  • The controller action is expecting 4 strings: interchangeXml, hwid, localization, and label. No.. the xml does not and will not contain the other values I am attempting to post. – Nick Jun 07 '11 at 20:37
  • Have you tried using a tool like Fiddler or Firebug to see exactly what your client is sending to the server? It may not be coming out correctly. – Tridus Jun 07 '11 at 20:39
  • I am making the httprequest from a thik client using c#. The request is not coming from a browser so I don't think firebug or fiddler is applicable – Nick Jun 07 '11 at 21:06
  • I think what @Tridus means is accessing the site through it's web interface and fiddle the requests to see if you can match it. Even if you have four different values, one of them being xml, you could compose the entire post using xml, or json and MVC should be smart enough to put the objects together. I know at least MVC 3 will do this. – Jay Jun 07 '11 at 21:12
  • It's still sending a HTTP request no matter where it's coming from, so Fiddler is relevant here (Firebug not so much). You need to make sure that it's being sent in the correct format to the server, and Fiddler can tell you that. Fiddler would also let you compose another request to see if that one works. If it does, then you'll know where to look. – Tridus Jun 07 '11 at 21:26
  • @tridus see what you mean.. Ill check the request using fiddler – Nick Jun 07 '11 at 21:28
  • I can't seem to view any traffic but the traffic created by the web browser using fiddler. – Nick Jun 07 '11 at 21:46
  • Try using "Charles Proxie" just google it – The_asMan Jun 07 '11 at 22:10

3 Answers3

12

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.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Thank you for the through solution. I am going to try using the WebClient object to simplify things. You said I was not encoding the xml.. string interchangeXml = HttpUtility.UrlEncode(stringWriter.GetStringBuilder().ToString()); Is this not the correct way to encode xml? – Nick Jun 07 '11 at 22:48
  • 1
    The WebClient just recieves a 500 without hitting the action. How should the route look now that the action is expecting a viewModel. I created a viewModel just like the one you suggested. – Nick Jun 08 '11 at 00:17
  • @Darin The status in my catch block reports a 'Protocol Error'. "The remote server returned an error: (500) Internal Server Error" – Nick Jun 08 '11 at 12:21
  • @Nick, look at the inner exception. It should be an HttpException from which you would be able to extract the exact response message from the server. Or have your server application log errors so that you could further narrow down the problem. I am afraid that from the information you provide (application throws 500 status code) I cannot do much to help you. – Darin Dimitrov Jun 08 '11 at 12:23
  • @Darin Unfortunately there is no inner exception and the exception does not provide me with anything less vague. – Nick Jun 08 '11 at 16:52
  • Darin, is there a way to solve this **WITHOUT** the [WebClient](https://msdn.microsoft.com/en-us/library/system.net.webclient.aspx)? It is not part of the .NET Compact Framework's *System.Net* namespace, which I currently need a solution for. –  Nov 23 '15 at 16:38
1

I'm wrestling the same beast over here: Trying to set up a controller action as Xml endpoint

You may be getting the internal server error because either you have page validation on (solution: addotate with ValidateInput(false)), or you're not sending an Accept-Encoding header with your request. I would very much like to hear how I can get MVC to accept posted input without the Accept-Encoding HTTP header...

Community
  • 1
  • 1
SanderS
  • 93
  • 1
  • 6
0

I just found that you can call a controller, even a dependency injected one, even from a Web Forms code behind using the "T4MVC" Nuget package:

https://github.com/T4MVC/T4MVC

Brian Ogden
  • 18,439
  • 10
  • 97
  • 176