2017-10-21 285 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

相關問題