ASP.NET Web API 'sinde HTML form verileri gönderme: dosya yükleme ve çok parçalı MIMESending HTML Form Data in ASP.NET Web API: File Upload and Multipart MIME

, Mike te sonby Mike Wasson

Bölüm 2: dosya yükleme ve çok parçalı MIMEPart 2: File Upload and Multipart MIME

Bu öğreticide, bir Web API 'sine dosya yükleme işleminin nasıl yapılacağı gösterilmektedir.This tutorial shows how to upload files to a web API. Ayrıca, çok parçalı MIME verilerinin nasıl işlenmesi açıklanmaktadır.It also describes how to process multipart MIME data.

Bir dosyayı karşıya yüklemek için bir HTML formu örneği aşağıda verilmiştir:Here is an example of an HTML form for uploading a file:

<form name="form1" method="post" enctype="multipart/form-data" action="api/upload">
    <div>
        <label for="caption">Image Caption</label>
        <input name="caption" type="text" />
    </div>
    <div>
        <label for="image1">Image File</label>
        <input name="image1" type="file" />
    </div>
    <div>
        <input type="submit" value="Submit" />
    </div>
</form>

Bu form bir metin girişi denetimi ve bir dosya girişi denetimi içerir.This form contains a text input control and a file input control. Form bir dosya girişi denetimi içerdiğinde, Enctype özniteliği her zaman "multipart/form-Data"olmalıdır ve bu, formun çok PARÇALı bir MIME iletisi olarak gönderileceğini belirtir.When a form contains a file input control, the enctype attribute should always be "multipart/form-data", which specifies that the form will be sent as a multipart MIME message.

Bir çok parçalı MIME iletisinin biçimi, örnek bir isteğe bakarak anlaşılması en kolay yoldur:The format of a multipart MIME message is easiest to understand by looking at an example request:

POST http://localhost:50460/api/values/1 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------41184676334
Content-Length: 29278

-----------------------------41184676334
Content-Disposition: form-data; name="caption"

Summer vacation
-----------------------------41184676334
Content-Disposition: form-data; name="image1"; filename="GrandCanyon.jpg"
Content-Type: image/jpeg

(Binary data not shown)
-----------------------------41184676334--

Bu ileti, her form denetimi için bir tane olmak üzere iki parçayabölünür.This message is divided into two parts, one for each form control. Bölüm sınırları, tireler ile başlayan satırlar ile belirtilir.Part boundaries are indicated by the lines that start with dashes.

Note

Bölüm sınırı, sınır dizesinin yanlışlıkla bir ileti bölümü içinde görünmemesini sağlamak için rastgele bir bileşen ("41184676334") içerir.The part boundary includes a random component ("41184676334") to ensure that the boundary string does not accidentally appear inside a message part.

Her ileti parçası bir veya daha fazla üst bilgi içerir ve ardından bölüm içerikleri gelir.Each message part contains one or more headers, followed by the part contents.

  • Content-Disposition üst bilgisi, denetimin adını içerir.The Content-Disposition header includes the name of the control. Dosyalar için dosya adını da içerir.For files, it also contains the file name.
  • Content-Type üst bilgisi, bölümündeki verileri tanımlar.The Content-Type header describes the data in the part. Bu üst bilgi atlanırsa, varsayılan metin/düz ' dır.If this header is omitted, the default is text/plain.

Önceki örnekte, Kullanıcı, Type Image/JPEG; içerik türü ile birlikte bir dosya olarak belirtilen bir dosyayı karşıya yükledi. ve metin girişinin değeri "yaz tatili".In the previous example, the user uploaded a file named GrandCanyon.jpg, with content type image/jpeg; and the value of the text input was "Summer Vacation".

Karşıya dosya yüklemeFile Upload

Şimdi çok parçalı bir MIME iletisinden dosyaları okuyan bir Web API denetleyicisine göz atalım.Now let's look at a Web API controller that reads files from a multipart MIME message. Denetleyici dosyaları zaman uyumsuz olarak okur.The controller will read the files asynchronously. Web API 'SI, görev tabanlı programlama modelinikullanarak zaman uyumsuz eylemleri destekler.Web API supports asynchronous actions using the task-based programming model. İlk olarak, Async ve await anahtar sözcüklerini destekleyen .NET Framework 4,5 ' i hedefliyorsanız, bu kod aşağıda verilmiştir.First, here is the code if you are targeting .NET Framework 4.5, which supports the async and await keywords.

using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

public class UploadController : ApiController
{
    public async Task<HttpResponseMessage> PostFormData()
    {
        // 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
        {
            // Read the form data.
            await Request.Content.ReadAsMultipartAsync(provider);

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        catch (System.Exception e)
        {
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
        }
    }

}

Denetleyici eyleminin hiçbir parametre almaz.Notice that the controller action does not take any parameters. Bunun nedeni, bir medya türü biçimlendirici çağırmadan, işlem içindeki istek gövdesini işletireceğiz.That's because we process the request body inside the action, without invoking a media-type formatter.

Imultipartcontent yöntemi, isteğin çok PARÇALı bir MIME iletisi içerip içermediğini denetler.The IsMultipartContent method checks whether the request contains a multipart MIME message. Aksi takdirde, denetleyici HTTP durum kodu 415 (desteklenmeyen medya türü) döndürür.If not, the controller returns HTTP status code 415 (Unsupported Media Type).

Multipartformdatastreamprovider sınıfı, karşıya yüklenen dosyalar için dosya akışlarını ayıran bir yardımcı nesnedir.The MultipartFormDataStreamProvider class is a helper object that allocates file streams for uploaded files. Çok parçalı MIME iletisini okumak için, Readasmultipartasync yöntemini çağırın.To read the multipart MIME message, call the ReadAsMultipartAsync method. Bu yöntem, tüm ileti parçalarını ayıklar ve bunları Multipartformdatastreamprovidertarafından sunulan akışlara yazar.This method extracts all of the message parts and writes them into the streams provided by the MultipartFormDataStreamProvider.

Yöntem tamamlandığında, çok partfiledata nesnelerinin bir koleksiyonu olan Filedata özelliğinden dosyalar hakkında bilgi alabilirsiniz.When the method completes, you can get information about the files from the FileData property, which is a collection of MultipartFileData objects.

  • Multipartfiledata. FileName , sunucuda dosyanın kaydedildiği yerel dosya adıdır.MultipartFileData.FileName is the local file name on the server, where the file was saved.
  • Multipartfiledata. Headers , bölüm üst bilgisini (istek üst bilgisinideğil ) içerir.MultipartFileData.Headers contains the part header (not the request header). Bunu, Içerik_eğilimi ve Içerik türü üst bilgilerine erişmek için kullanabilirsiniz.You can use this to access the Content_Disposition and Content-Type headers.

Adından da anlaşılacağı gibi, Readasmultipartasync zaman uyumsuz bir yöntemdir.As the name suggests, ReadAsMultipartAsync is an asynchronous method. Yöntem tamamlandıktan sonra iş gerçekleştirmek için bir devamlılık görevi (.NET 4,0) veya await anahtar sözcüğünü (.NET 4,5) kullanın.To perform work after the method completes, use a continuation task (.NET 4.0) or the await keyword (.NET 4.5).

Önceki kodun .NET Framework 4,0 sürümü aşağıda verilmiştir:Here is the .NET Framework 4.0 version of the previous code:

public Task<HttpResponseMessage> PostFormData()
{
    // 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);

    // Read the form data and return an async task.
    var task = Request.Content.ReadAsMultipartAsync(provider).
        ContinueWith<HttpResponseMessage>(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
            {
                Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
            }

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        });

    return task;
}

Form denetimi verilerini okumaReading Form Control Data

Daha önce gösterilen HTML formu metin girişi denetimine sahipti.The HTML form that I showed earlier had a text input control.

<div>
        <label for="caption">Image Caption</label>
        <input name="caption" type="text" />
    </div>

Multipartformdatastreamprovider'ın FormData özelliğinden denetimin değerini alabilirsiniz.You can get the value of the control from the FormData property of the MultipartFormDataStreamProvider.

public async Task<HttpResponseMessage> PostFormData()
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    string root = HttpContext.Current.Server.MapPath("~/App_Data");
    var provider = new MultipartFormDataStreamProvider(root);

    try
    {
        await Request.Content.ReadAsMultipartAsync(provider);

        // Show all the key-value pairs.
        foreach (var key in provider.FormData.AllKeys)
        {
            foreach (var val in provider.FormData.GetValues(key))
            {
                Trace.WriteLine(string.Format("{0}: {1}", key, val));
            }
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }
    catch (System.Exception e)
    {
        return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
    }
}

FormData , form denetimleri için ad/değer çiftlerini Içeren bir NameValueCollection .FormData is a NameValueCollection that contains name/value pairs for the form controls. Koleksiyonda yinelenen anahtarlar bulunabilir.The collection can contain duplicate keys. Şu formu göz önünde bulundurun:Consider this form:

<form name="trip_search" method="post" enctype="multipart/form-data" action="api/upload">
    <div>
        <input type="radio" name="trip" value="round-trip"/>
        Round-Trip
    </div>
    <div>
        <input type="radio" name="trip" value="one-way"/>
        One-Way
    </div>

    <div>
        <input type="checkbox" name="options" value="nonstop" />
        Only show non-stop flights
    </div>
    <div>
        <input type="checkbox" name="options" value="airports" />
        Compare nearby airports
    </div>
    <div>
        <input type="checkbox" name="options" value="dates" />
        My travel dates are flexible
    </div>

    <div>
        <label for="seat">Seating Preference</label>
        <select name="seat">
            <option value="aisle">Aisle</option>
            <option value="window">Window</option>
            <option value="center">Center</option>
            <option value="none">No Preference</option>
        </select>
    </div>
</form>

İstek gövdesi şöyle görünebilir:The request body might look like this:

-----------------------------7dc1d13623304d6
Content-Disposition: form-data; name="trip"

round-trip
-----------------------------7dc1d13623304d6
Content-Disposition: form-data; name="options"

nonstop
-----------------------------7dc1d13623304d6
Content-Disposition: form-data; name="options"

dates
-----------------------------7dc1d13623304d6
Content-Disposition: form-data; name="seat"

window
-----------------------------7dc1d13623304d6--

Bu durumda, FormData koleksiyonu aşağıdaki anahtar/değer çiftlerini içerir:In that case, the FormData collection would contain the following key/value pairs:

  • seyahat: gidiş dönüştrip: round-trip
  • Seçenekler: nonstopoptions: nonstop
  • Seçenekler: tarihleroptions: dates
  • koltuk: pencereseat: window