title: How can I simultaneously pass args and upload a file to a Web API Controller Method?
body: <p>I decided that my question <a href="https://stackoverflow.com/questions/21995828/how-to-send-xml-in-a-uri-for-posting-to-a-web-api-app">here</a> isn't really what I want to do - the XML I need to send is a lot longer, potentially, than I really want to send in a URI.</p>
  
  <p>It didn't "feel" right doing that, and <a href="https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers">this</a> unsealed the deal.</p>
  
  <p>I need to send both a couple of args AND a file to my Web API app from a client (handheld/CF) app.</p>
  
  <p>I may have found the code for receiving that, from here [
  <a href="http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2]" rel="nofollow noreferrer">http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2]</a></p>
  
  <p>Specifically, Wasson's Controller code here looks like it very well might work:</p>
  
  <pre><code>public async Task&lt;HttpResponseMessage&gt; PostFile()
  {
      // Check if the request contains multipart/form-data.
      if (!Request.Content.IsMimeMultipartContent())
      {
          throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
      }
  
      string root = HttpContext.Current.Server.MapPath("~/App_Data");
      var provider = new MultipartFormDataStreamProvider(root);
  
      try
      {
          StringBuilder sb = new StringBuilder(); // Holds the response body
  
          // Read the form data and return an async task.
          await Request.Content.ReadAsMultipartAsync(provider);
  
          // This illustrates how to get the form data.
          foreach (var key in provider.FormData.AllKeys)
          {
              foreach (var val in provider.FormData.GetValues(key))
              {
                  sb.Append(string.Format("{0}: {1}\n", key, val));
              }
          }
  
          // This illustrates how to get the file names for uploaded files.
          foreach (var file in provider.FileData)
          {
              FileInfo fileInfo = new FileInfo(file.LocalFileName);
              sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
          }
          return new HttpResponseMessage()
          {
              Content = new StringContent(sb.ToString())
          };
      }
      catch (System.Exception e)
      {
          return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
      }
  }
  </code></pre>
  
  <p>...but now I need to know how to send it; other calls from the client are of the form:</p>
  
  <pre><code>http://&lt;IPAddress&gt;:&lt;portNum&gt;/api/&lt;ControllerName&gt;?arg1=Bla&amp;arg2=Blee
  </code></pre>
  
  <p>but how does the file I need to send/attach get passed along? It is a XML file, but I don't want to append the whole thing to the URI, as it can be quite large, and doing so would be horrendously weird.</p>
  
  <p>Does anybody know how to accomplish this?</p>
  
  <h2>UPDATE</h2>
  
  <p>Following the crumbs tvanfosson dropped below, I found code <a href="http://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/" rel="nofollow noreferrer">here</a> which I think I can adapt to work on the client:</p>
  
  <pre><code>var message = new HttpRequestMessage();
  var content = new MultipartFormDataContent();
  
  foreach (var file in files)
  {
      var filestream = new FileStream(file, FileMode.Open);
      var fileName = System.IO.Path.GetFileName(file);
      content.Add(new StreamContent(filestream), "file", fileName);
  }
  
  message.Method = HttpMethod.Post;
  message.Content = content;
  message.RequestUri = new Uri("http://localhost:3128/api/uploading/");
  
  var client = new HttpClient();
  client.SendAsync(message).ContinueWith(task =&gt;
  {
      if (task.Result.IsSuccessStatusCode)
      { 
          //do something with response
      }
  });    
  </code></pre>
  
  <p>...but that depends on whether the <a href="https://stackoverflow.com/questions/22024479/how-can-i-determine-which-net-features-the-compact-framework-has">Compact Framework supports MultipartFormDataContent</a></p>
  
  <h2>UPDATE 2</h2>
  
  <p>Which it doesn't, according to <a href="https://stackoverflow.com/questions/22024479/how-can-i-determine-which-net-features-the-compact-framework-has/22024502?noredirect=1#comment33387529_22024502">How can i determine which .Net features the compact framework has?</a></p>
  
  <h2>UPDATE 3</h2>
  
  <p>Using the Bing Search Code for C# extension, I mashed "h", chose "How do I", entered "send file via http" and got this:</p>
  
  <pre><code>WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx ");
  request.Method = "POST";
  string postData = "This is a test that posts this string to a Web server.";
  byte[] byteArray = Encoding.UTF8.GetBytes(postData);
  request.ContentType = "application/x-www-form-urlencoded";
  request.ContentLength = byteArray.Length;
  Stream dataStream = request.GetRequestStream();
  dataStream.Write(byteArray, 0, byteArray.Length);
  dataStream.Close();
  WebResponse response = request.GetResponse();
  Console.WriteLine(((HttpWebResponse)response).StatusDescription);
  dataStream = response.GetResponseStream();
  StreamReader reader = new StreamReader(dataStream);
  string responseFromServer = reader.ReadToEnd();
  Console.WriteLine(responseFromServer);
  reader.Close();
  dataStream.Close();
  response.Close();
  </code></pre>
  
  <p>As I need to add a couple of string args in addition to the file (which I assume I can add via the postData byte array), can I do that by adding more calls to dataStream.Write()? IOW, is this sensible (first and third lines differ):</p>
  
  <pre><code>WebRequest request = WebRequest.Create("http://MachineName:NNNN/api/Bla?str1=Blee&amp;str2=Bloo");
  request.Method = "POST";
  string postData = //open the HTML file and assign its contents to this, or make it File postData instead of string postData?
  // the rest is the same
  </code></pre>
  
  <p>?</p>
  
  <h2>UPDATE 4</h2>
  
  <p>Progress: This, such as it is, is working:</p>
  
  <p>Server code:</p>
  
  <pre><code>public string PostArgsAndFile([FromBody] string value, string serialNum, string siteNum)
  {
      string s = string.Format("{0}-{1}-{2}", value, serialNum, siteNum);
      return s;
  }
  </code></pre>
  
  <p>Client code (from Darin Dimitrov in <a href="https://stackoverflow.com/questions/13771032/post-string-to-asp-net-web-api-application-returns-null">this post</a>):</p>
  
  <pre><code>private void ProcessRESTPostFileData(string uri)
  {
      using (var client = new WebClient())
      {
          client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
          var data = "=Short test...";
          var result = client.UploadString(uri, "POST", data);
          //try this: var result = client.UploadFile(uri, "bla.txt");
          //var result = client.UploadData()
          MessageBox.Show(result);
      }
  }
  </code></pre>
  
  <p>Now I need to get it sending a file instead of a string in the [FromBody] arg.</p>