Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Del 2: Filuppladdning och MIME för flera delar
Den här handledningen visar hur du laddar upp filer till ett webb-API. Den beskriver också hur du bearbetar MIME-data för flera delar.
Anmärkning
Här är ett exempel på ett HTML-formulär för att ladda upp en fil:
<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>
Det här formuläret innehåller en textinmatningskontroll och en filinmatningskontroll. När ett formulär innehåller en filinmatningskontroll ska attributet enctype alltid vara "multipart/form-data", som anger att formuläret ska skickas som ett MIME-meddelande för flera delar.
Formatet för ett MIME-meddelande för flera delar är enklast att förstå genom att titta på en exempelbegäran:
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--
Det här meddelandet är indelat i två delar, en för varje formulärkontroll. Delgränser indikeras av de linjer som börjar med bindestreck.
Anmärkning
Delgränsen innehåller en slumpmässig komponent ("41184676334") för att säkerställa att gränssträngen inte visas av misstag i en meddelandedel.
Varje meddelandedel innehåller en eller flera rubriker följt av delinnehållet.
- Rubriken Content-Disposition innehåller namnet på kontrollen. För filer innehåller den även filnamnet.
- Rubriken Innehållstyp beskriver data i delen. Om den här rubriken utelämnas är standardvärdet text/oformaterad.
I föregående exempel laddade användaren upp en fil med namnet GrandCanyon.jpg, med innehållstypsbild/jpeg; och värdet för textinmatningen var "Sommarsemester".
Filöverföring
Nu ska vi titta på en webb-API-kontrollant som läser filer från ett MIME-meddelande för flera delar. Styrenheten läser filerna asynkront. Webb-API stöder asynkrona åtgärder med hjälp av den aktivitetsbaserade programmeringsmodellen. Först är här koden om du riktar in dig på .NET Framework 4.5, som stöder asynkrona och väntar på nyckelord.
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);
}
}
}
Observera att kontrollantåtgärden inte tar några parametrar. Det beror på att vi bearbetar begärandetexten i åtgärden, utan att anropa en mediatypformaterare.
Metoden IsMultipartContent kontrollerar om begäran innehåller ett MIME-meddelande för flera delar. Annars returnerar kontrollanten HTTP-statuskod 415 (medietyp som inte stöds).
Klassen MultipartFormDataStreamProvider är ett hjälpobjekt som allokerar filströmmar för uppladdade filer. Om du vill läsa MIME-meddelandet för flera delar anropar du metoden ReadAsMultipartAsync . Den här metoden extraherar alla meddelandedelar och skriver dem till strömmarna som tillhandahålls av MultipartFormDataStreamProvider.
När metoden är klar kan du få information om filerna från egenskapen FileData , som är en samling MultipartFileData-objekt .
- MultipartFileData.FileName är det lokala filnamnet på servern där filen sparades.
- MultipartFileData.Headers innehåller delrubriken (inte begärandehuvudet). Du kan använda detta för att komma åt rubrikerna Content_Disposition och Innehållstyp.
Som namnet antyder är ReadAsMultipartAsync en asynkron metod. Om du vill utföra arbete när metoden har slutförts använder du en fortsättningsaktivitet (.NET 4.0) eller nyckelordet await (.NET 4.5).
Här är .NET Framework 4.0-versionen av föregående kod:
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;
}
Läsa formulärkontrolldata
HTML-formuläret som jag visade tidigare hade en textinmatningskontroll.
<div>
<label for="caption">Image Caption</label>
<input name="caption" type="text" />
</div>
Du kan hämta värdet för kontrollen från egenskapen FormData för 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 är ett NameValueCollection som innehåller namn/värde-par för formulärkontrollerna. Samlingen kan innehålla dubblettnycklar. Tänk på det här formuläret:
<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>
Begärandetexten kan se ut så här:
-----------------------------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--
I så fall skulle FormData-samlingen innehålla följande nyckel/värde-par:
- resa: tur och retur
- alternativ: nonstop
- alternativ: datum
- sittplats: fönster