2017-10-21 233 views
4

我从ASP.NET MVC 5项目迁移到ASP.NET的Core 2的过程,并据我可以告诉碰上关于MultipartFormDataStreamProviderMultipartFormDataStreamProvider用于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

感谢的解决方案!

+0

你是否在使用V3 api for sendgrid? sendgrid C#sdk仍然不支持.net core 2.0 – Niladri

+0

您是否看过Request.Form.Files? – Tratcher

回答

1

这是我迄今为止的解决方案。它仍然是一项正在进行的工作,例如,在处理附件方面,但它正在成功解析电子邮件。

它大量借鉴了韦德的博客上以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核心文件
+0

类型['MultipartRequestHeader'](http://source.dot.net/#System.Net.Http/System/Net/Http/Headers/MediaTypeHeaderValue.cs,9856dc052045cf60)不包含成员'Boundary'。 – Shimmy

+0

明白了,我们必须添加一个使用'Microsoft.Net.Http.Headers',而不是'System.Net.Http.Headers',它缺少该属性。 – Shimmy

相关问题