MultipartFormDataStreamProvider用于ASP.NET的Core 2
问题描述:
我从ASP.NET MVC 5项目迁移到ASP.NET的Core 2的过程,并据我可以告诉碰上关于MultipartFormDataStreamProvider
MultipartFormDataStreamProvider用于ASP.NET的Core 2
一些问题它还不是.NET Core的一部分,因此无法使用。我试图解决的问题是Sendgrid正在使用的代码的一部分,解析电子邮件。
的.NET MVC 5代码如下
[HttpPost]
public async Task<HttpResponseMessage> Post()
{
var root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
await Request.Content.ReadAsMultipartAsync(provider);
var email = new Email
{
Dkim = provider.FormData.GetValues("dkim").FirstOrDefault(),
To = provider.FormData.GetValues("to").FirstOrDefault(),
Html = provider.FormData.GetValues("html").FirstOrDefault()
}
}
这段代码是从Sendgrid API文档获取的一个片段:https://sendgrid.com/docs/Integrate/Code_Examples/Webhook_Examples/csharp.html
所以我一直在摆弄这个一会儿,试图想出一个解决方案,但我完全卡住了。最近的一个解决方案,我来就是通过Chrome浏览器的ARC REST客户端插件(或任何其他的REST API测试仪)在数据发送时使用Request.Form
e.g
To = form["to"].SingleOrDefault(),
From = form["from"].SingleOrDefault()
然而这仅适用。此外,该解决方案将无法处理诸如图像之类的附件。
所以我转向StackOverflow上的社区希望有人有一些提示或如何提前这个迁移到.NET睿2
感谢的解决方案!
答
这是我迄今为止的解决方案。它仍然是一项正在进行的工作,例如,在处理附件方面,但它正在成功解析电子邮件。
它大量借鉴了韦德的博客上以https://dotnetcoretutorials.com/2017/03/12/uploading-files-asp-net-core/
[HttpPost]
[DisableFormValueModelBinding]
[Route("v4/ProcessEmail")]
public async Task<IActionResult> ParseSendGridInboundWebHook()
{
FormValueProvider formModel;
using (var stream = System.IO.File.Create("c:\\temp\\myfile.temp"))
{
formModel = await _context.HttpContext.Request.StreamFile(stream);
}
var viewModel = new SendGridEmailDTO();
var bindingSuccessful = await TryUpdateModelAsync(viewModel, prefix: "",
valueProvider: formModel);
if (!bindingSuccessful)
{
if (!ModelState.IsValid)
{
return new BadRequestResult();
}
}
<your code here>
return new OkResult();
}
public static class MultipartRequestHelper
{
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq"
// The spec says 70 characters is a reasonable limit.
public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
{
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary);
if (string.IsNullOrWhiteSpace(boundary.Value))
{
throw new InvalidDataException("Missing content-type boundary.");
}
if (boundary.Length > lengthLimit)
{
throw new InvalidDataException(
$"Multipart boundary length limit {lengthLimit} exceeded.");
}
return boundary.Value;
}
public static bool IsMultipartContentType(string contentType)
{
return !string.IsNullOrEmpty(contentType)
&& contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static bool HasFormDataContentDisposition(ContentDispositionHeaderValue contentDisposition)
{
// Content-Disposition: form-data; name="key";
return contentDisposition != null
&& contentDisposition.DispositionType.Equals("form-data")
&& string.IsNullOrEmpty(contentDisposition.FileName.Value)
&& string.IsNullOrEmpty(contentDisposition.FileNameStar.Value);
}
public static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition)
{
// Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg"
return contentDisposition != null
&& contentDisposition.DispositionType.Equals("form-data")
&& (!string.IsNullOrEmpty(contentDisposition.FileName.Value)
|| !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value));
}
}
public static class FileStreamingHelper
{
private static readonly FormOptions _defaultFormOptions = new FormOptions();
public static async Task<FormValueProvider> StreamFile(this HttpRequest request, Stream targetStream)
{
if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType))
{
throw new Exception($"Expected a multipart request, but got {request.ContentType}");
}
// Used to accumulate all the form url encoded key value pairs in the
// request.
var formAccumulator = new KeyValueAccumulator();
string targetFilePath = null;
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
await section.Body.CopyToAsync(targetStream);
}
else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
{
// Content-Disposition: form-data; name="key"
//
// value
// Do not limit the key name length here because the
// multipart headers length limit is already in effect.
var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
var encoding = GetEncoding(section);
using (var streamReader = new StreamReader(
section.Body,
encoding,
detectEncodingFromByteOrderMarks: true,
bufferSize: 1024,
leaveOpen: true))
{
// The value length limit is enforced by MultipartBodyLengthLimit
var value = await streamReader.ReadToEndAsync();
if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
{
value = String.Empty;
}
formAccumulator.Append(key.Value, value);
if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit)
{
throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded.");
}
}
}
}
// Drains any remaining section body that has not been consumed and
// reads the headers for the next section.
section = await reader.ReadNextSectionAsync();
}
// Bind form data to a model
var formValueProvider = new FormValueProvider(
BindingSource.Form,
new FormCollection(formAccumulator.GetResults()),
CultureInfo.CurrentCulture);
return formValueProvider;
}
private static Encoding GetEncoding(MultipartSection section)
{
MediaTypeHeaderValue mediaType;
var hasMediaTypeHeader = MediaTypeHeaderValue.TryParse(section.ContentType, out mediaType);
// UTF-7 is insecure and should not be honored. UTF-8 will succeed in
// most cases.
if (!hasMediaTypeHeader || Encoding.UTF7.Equals(mediaType.Encoding))
{
return Encoding.UTF8;
}
return mediaType.Encoding;
}
}
public class SendGridEmailDTO
{
public string Dkim { get; set; }
public string To { get; set; }
public string Html { get; set; }
public string From { get; set; }
public string Text { get; set; }
public string SenderIp { get; set; }
public string Envelope { get; set; }
public int Attachments { get; set; }
public string Subject { get; set; }
public string Charsets { get; set; }
public string Spf { get; set; }
}
上传在ASP.NET核心文件
你是否在使用V3 api for sendgrid? sendgrid C#sdk仍然不支持.net core 2.0 – Niladri
您是否看过Request.Form.Files? – Tratcher