我正在将项目从ASP.NET MVC 5迁移到ASP.NET Core 2,并且遇到了有关MultipartFormDataStreamProvider的一些问题
据我所知,它还不是.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获取的代码段
所以我一直在摆弄这个问题,试图想出一个解决方案,但我完全陷入困境.最接近解决方案的是使用Request.Form,例如
To = form["to"].SingleOrDefault(),From = form["from"].SingleOrDefault()
但是,这仅适用于通过ARC(或任何其他REST-API测试程序)的ARC REST客户端插件发送数据.此解决方案也将无法处理诸如图像之类的附件.
所以我转向StackOverflow社区,希望有人有一些指针或解决方案,如何将其迁移到.NET Core 2.
提前致谢!
解决方法
这是我到目前为止的解决方案.它仍然是一项正在进行的工作,例如,在处理附件方面,但它已成功解析电子邮件.它从Wade的博客中大量借鉴了在
https://dotnetcoretutorials.com/2017/03/12/uploading-files-asp-net-core/上的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; } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。