7

I'd like to post a file to my webapi. It's not the problem but:

  1. I don't want to use javascript
  2. The file must be received and saved synchronously
  3. I would like my action to look like this:

    public void Post(byte[] file)
    {
    
    }
    

    or:

    public void Post(Stream stream)
    {
    
    }
    
  4. I want to post file from code similiar to this (of course, now it doesn't work):

    <form id="postFile" enctype="multipart/form-data" method="post">
    
        <input type="file" name="file" />
    
        <button value="post" type="submit" form="postFile"  formmethod="post" formaction="<%= Url.RouteUrl("WebApi", new { @httpRoute = "" }) %>" />
    
    </form>
    

Any suggestions will be appreciated

Fuffu
  • 73
  • 1
  • 1
  • 5

2 Answers2

13

The simplest example would be something like this

[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> Post()
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    var provider = new MultipartFormDataStreamProvider(HostingEnvironment.MapPath("~/App_Data"));

    var files = await Request.Content.ReadAsMultipartAsync(provider);

    // Do something with the files if required, like saving in the DB the paths or whatever
    await DoStuff(files);

    return Request.CreateResponse(HttpStatusCode.OK);;
}

There is no synchronous version of ReadAsMultipartAsync so you are better off playing along.

UPDATE:

If you are using IIS server hosting, you can try the traditional way:

public HttpResponseMessage Post()
{
    var httpRequest = HttpContext.Current.Request;
    if (httpRequest.Files.Count > 0)
    {
        foreach (string fileName in httpRequest.Files.Keys)
        {
            var file = httpRequest.Files[fileName];
            var filePath = HttpContext.Current.Server.MapPath("~/" + file.FileName);
            file.SaveAs(filePath);
        }

        return Request.CreateResponse(HttpStatusCode.Created);
    }

    return Request.CreateResponse(HttpStatusCode.BadRequest);
}
Phoenix
  • 1,045
  • 1
  • 14
  • 22
vtortola
  • 34,709
  • 29
  • 161
  • 263
  • Thanks for the answer, but I've found this solution before. It's not satisfactorily for me. I really need to do it synchronously. – Fuffu Oct 28 '15 at 11:07
  • May I ask why? I am curious. – vtortola Oct 28 '15 at 11:11
  • This application will use many different cultures. Every new thread is started in default culture and it's not expected behavior for me. I can't use CultureInfo.DefaultThreadCurrentCulture too because it's not supported in .NET 4.0 yet. – Fuffu Oct 28 '15 at 11:19
  • I see. Have you considered this workaround? http://stackoverflow.com/questions/20601578/async-webapi-thread-currentculture – vtortola Oct 28 '15 at 11:26
  • That looks pretty nice for me, but I'm still curious if it's possible to do it synchronously – Fuffu Oct 28 '15 at 11:36
  • After consideration I have to said I can't use this solution cuz it requires .NET 4.5. Any other suggestions? – Fuffu Oct 28 '15 at 12:21
  • But the title states that you are using Web API 2, that needs .NET 4.5 as far as I know. http://stackoverflow.com/questions/20411029/asp-net-mvc-5-and-web-api-2-net-requirement – vtortola Oct 28 '15 at 13:21
  • I updated with one example using the traditional way extracted from here http://stackoverflow.com/a/20356591/307976 – vtortola Oct 28 '15 at 13:28
  • @vtortola how to do it with other form values for example saving name,address,image in single request in an object.using webapi – Dragon Apr 14 '17 at 12:28
-2

I think action should be like

[HttpPost]
    public ActionResult post(HttpPostedFileBase file)
    {
        // Verify that the user selected a file
        if (file != null && file.ContentLength > 0) 
        {
            // extract only the filename
            var fileName = Path.GetFileName(file.FileName);
            // store the file inside ~/App_Data/uploads folder
            var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
            file.SaveAs(path);
        }
        // redirect back to the index action to show the form once again
        return RedirectToAction("Index");        
    }
jalil
  • 85
  • 10