1

I have an ASP.NET MVC 3 controller action. That action is defined as follows:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string parameter1, HttpPostedFileBase uploadFile)
{
  if (parameter1 == null)
    return Json(new { status = "Error" }, JsonRequestBehavior.AllowGet);

  if (uploadFile.ContentLength == 0)
    return Json(new { status = "Error" }, JsonRequestBehavior.AllowGet);

  return Json(new { status = "Success" }, JsonRequestBehavior.AllowGet);
}

I need to upload to this endpoint via a C# app. Currently, I'm using the following:

public void Upload()
{
  WebRequest request = HttpWebRequest.Create("http://www.mydomain.com/myendpoint");
  request.Method = "POST";
  request.ContentType = "multipart/form-data";
  request.BeginGetRequestStream(new AsyncCallback(UploadBeginGetRequestStreamCallBack), request);
}

private void UploadBeginGetRequestStreamCallBack(IAsyncResult ar)
{
  string json = "{\"parameter1\":\"test\"}";

  HttpWebRequest webRequest = (HttpWebRequest)(ar.AsyncState);
  using (Stream postStream = webRequest.EndGetRequestStream(ar))
  {
    byte[] byteArray = Encoding.UTF8.GetBytes(json);
    postStream.Write(byteArray, 0, byteArray.Length);
    postStream.Close();
  }
  webRequest.BeginGetResponse(new AsyncCallback(Upload_Completed), webRequest);
}

private void Upload_Completed(IAsyncResult result)
{
  WebRequest request = (WebRequest)(result.AsyncState);
  WebResponse response = request.EndGetResponse(result);
  // Parse response
}

While I get a 200, the status is always "Error". After digging further, I noticed that parameter1 is always null. I'm slightly confused. Can somebody please tell me how to programmatically send data for parameter1 as well as a file from code via a WebRequest?

Thank you!

JavaScript Developer
  • 3,968
  • 11
  • 41
  • 46

1 Answers1

3

Dude, this one was difficult!

I really tried to find a way to programmatically upload files to a MVC action, but I couldn't, I'm sorry. The solution I found converts the file to a byte array and serializes it into a string.

Here, take a look.

This is your controller action:

    [AcceptVerbs(HttpVerbs.Post)]
            public ActionResult uploadFile(string fileName, string fileBytes)
            {
                if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(fileBytes))
                    return Json(new { status = "Error" }, JsonRequestBehavior.AllowGet);
    
                string[] byteToConvert = fileBytes.Split('.');
                List<byte> fileBytesList = new List<byte>();
    byteToConvert.ToList<string>()
            .Where(x => !string.IsNullOrEmpty(x))
            .ToList<string>()
            .ForEach(x => fileBytesList.Add(Convert.ToByte(x)));
    
                //Now you can save the bytes list to a file
                
                return Json(new { status = "Success" }, JsonRequestBehavior.AllowGet);
            }

And this is the client code (who posts the file):

public void Upload()
        {
            WebRequest request = HttpWebRequest.Create("http://localhost:7267/Search/uploadFile");
            request.Method = "POST";
            //This is important, MVC uses the content-type to discover the action parameters
            request.ContentType = "application/x-www-form-urlencoded";

            byte[] fileBytes = System.IO.File.ReadAllBytes(@"C:\myFile.jpg");

            StringBuilder serializedBytes = new StringBuilder();
            
            //Let's serialize the bytes of your file
            fileBytes.ToList<byte>().ForEach(x => serializedBytes.AppendFormat("{0}.", Convert.ToUInt32(x)));

            string postParameters = String.Format("fileName={0}&fileBytes={1}", "myFile.jpg", serializedBytes.ToString());

            byte[] postData = Encoding.UTF8.GetBytes(postParameters);
            
            using (Stream postStream = request.GetRequestStream())
            {
                postStream.Write(postData, 0, postData.Length);
                postStream.Close();
            }

            request.BeginGetResponse(new AsyncCallback(Upload_Completed), request);
        }

        private void Upload_Completed(IAsyncResult result)
        {
            WebRequest request = (WebRequest)(result.AsyncState);
            WebResponse response = request.EndGetResponse(result);
            // Parse response
        }

Hanselman has a good post regarding file upload from a web interface, which is not your case.

If you need help to convert the byte array back to a file, check this thread: Can a Byte[] Array be written to a file in C#?

Hope this helps.

If anyone has a better solution, I'd like to take a look at it.

Regards, Calil

Community
  • 1
  • 1
Andre Calil
  • 7,652
  • 34
  • 41
  • Thank you so much for trying. Oddly, in the controller action when I get to byteToConvert.ToList().ForEach(x => fileBytesList.Add(Convert.ToByte(x))); I get a "System.FormatException Input string was not in a correct format." – JavaScript Developer Jun 28 '12 at 03:42
  • Dude, I'm so sorry. There were 2 errors (not checking if x is empty and calling string.Concat not string.Format). Both code snippets have been updated. – Andre Calil Jun 28 '12 at 04:04
  • Man, thank you so much for your help and your persistence. Its working now. I'm not sure if I would have ever got it done without your help. – JavaScript Developer Jun 28 '12 at 11:39