asp.net web api - the - API web: cómo acceder a los valores de formulario multiparte al usar MultipartMemoryStreamProvider?
upload file web api 2 c# (1)
Actualizado el 28/04/2015
Puede crear un proveedor personalizado basado en MultipartFormDataRemoteStreamProvider
.
Ejemplo:
public class CustomMultipartFormDataProvider : MultipartFormDataRemoteStreamProvider
{
public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers)
{
return new RemoteStreamInfo(
remoteStream: new MemoryStream(),
location: string.Empty,
fileName: string.Empty);
}
}
Actualizado
Custom In-Memory MultiaprtFormDataStreamProvider:
public class InMemoryMultipartFormDataStreamProvider : MultipartStreamProvider
{
private NameValueCollection _formData = new NameValueCollection();
private List<HttpContent> _fileContents = new List<HttpContent>();
// Set of indexes of which HttpContents we designate as form data
private Collection<bool> _isFormData = new Collection<bool>();
/// <summary>
/// Gets a <see cref="NameValueCollection"/> of form data passed as part of the multipart form data.
/// </summary>
public NameValueCollection FormData
{
get { return _formData; }
}
/// <summary>
/// Gets list of <see cref="HttpContent"/>s which contain uploaded files as in-memory representation.
/// </summary>
public List<HttpContent> Files
{
get { return _fileContents; }
}
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
// For form data, Content-Disposition header is a requirement
ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition;
if (contentDisposition != null)
{
// We will post process this as form data
_isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));
return new MemoryStream();
}
// If no Content-Disposition header was present.
throw new InvalidOperationException(string.Format("Did not find required ''{0}'' header field in MIME multipart body part..", "Content-Disposition"));
}
/// <summary>
/// Read the non-file contents as form data.
/// </summary>
/// <returns></returns>
public override async Task ExecutePostProcessingAsync()
{
// Find instances of non-file HttpContents and read them asynchronously
// to get the string content and then add that as form data
for (int index = 0; index < Contents.Count; index++)
{
if (_isFormData[index])
{
HttpContent formContent = Contents[index];
// Extract name from Content-Disposition header. We know from earlier that the header is present.
ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition;
string formFieldName = UnquoteToken(contentDisposition.Name) ?? String.Empty;
// Read the contents as string data and add to form data
string formFieldValue = await formContent.ReadAsStringAsync();
FormData.Add(formFieldName, formFieldValue);
}
else
{
_fileContents.Add(Contents[index]);
}
}
}
/// <summary>
/// Remove bounding quotes on a token if present
/// </summary>
/// <param name="token">Token to unquote.</param>
/// <returns>Unquoted token.</returns>
private static string UnquoteToken(string token)
{
if (String.IsNullOrWhiteSpace(token))
{
return token;
}
if (token.StartsWith("/"", StringComparison.Ordinal) && token.EndsWith("/"", StringComparison.Ordinal) && token.Length > 1)
{
return token.Substring(1, token.Length - 2);
}
return token;
}
}
Uso :
public async Task Post()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartFormDataStreamProvider>(new InMemoryMultipartFormDataStreamProvider());
//access form data
NameValueCollection formData = provider.FormData;
//access files
IList<HttpContent> files = provider.Files;
//Example: reading a file''s stream like below
HttpContent file1 = files[0];
Stream file1Stream = await file1.ReadAsStreamAsync();
}
Solía usar MultipartFormDataStreamProvider para procesar solicitudes de varias partes. Como quiero que el archivo cargado se almacene en la memoria, en lugar de un archivo de disco, he cambiado mi código para usar MultipartMemoryStreamProvider. Parece que la carga del archivo funciona bien, pero ya no puedo acceder a otros valores de formulario que estaban disponibles a través de provider.FormData
en MultipartFormDataStreamProvider. ¿Podría alguien mostrarme cómo hacer esto?
La solicitud sin procesar capturada por Fiddler:
POST http://myserver.com/QCCSvcHost/MIME/RealtimeTrans/ HTTP/1.1
Content-Type: multipart/form-data; boundary="XbCY"
Host: na-w-lxu3
Content-Length: 1470
Expect: 100-continue
Connection: Keep-Alive
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=PayloadType
X12_270_Request_005010X279A1
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=ProcessingMode
RealTime
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=PayloadID
e51d4fae-7dec-11d0-a765-00a0c91e6fa6
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=TimeStamp
2007-08-30T10:20:34Z
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=SenderID
HospitalA
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=ReceiverID
PayerB
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=CORERuleVersion
2.2.0
--XbCY
Content-Disposition: form-data; name=Payload; filename=276_5010.edi
ISA*00*~SE*16*0001~GE*1*1~IEA*1*191543498~
--XbCY--
Mi código de controlador:
string payload = null;
NameValueCollection nvc = null;
string fname = null;
StringBuilder sb = new StringBuilder();
sb.AppendLine();
foreach (StreamContent item in provider.Contents)
{
fname = item.Headers.ContentDisposition.FileName;
if (!String.IsNullOrWhiteSpace(fname))
{
payload = item.ReadAsStringAsync().Result;
}
else
{
nvc = item.ReadAsFormDataAsync().Result;
}
}