2017-10-26 4 views
0

長い話を短くパラメータとして列挙子を使用して - 私はEnum typeプロパティを受け入れるEntity Frameworkモデルを持っている:FileExtensions属性 -

public class FileUploads { 
    public AllowedFileTypes FileType { get; set; } 
} 

列挙型は次のとおりです。

public enum AllowedFileTypes { 
    jpg, 
    png, 
    gif, 
    jpeg, 
    bmp, 
} 

その後、Web APIコントローラIにの検証属性を次のように設定します。

[HttpPost] 
public async Task<IActionResult> Upload(
    [Required] 
    [FileExtensions(Extensions = "jpg,png,gif,jpeg,bmp")] // allowed filetypes 
    IFormFile file) 
{ 
    return Ok() 
} 

このメソッドは、ファイルをアップロードするために使用されます。今、問題は私が基本的にFileExtensions属性が手動で許されるフォーマットを設定しているということです。これは、新しいファイル形式が将来enumに追加されるたびに、各FileExtensions属性を手動で更新する必要があることを意味します。これは簡単に忘れてしまったり、他の開発者がこの事実を認識できない可能性があります。属性にEnum型パラメータを渡すことが可能かどうか、考えていましたか?

[FileExtensions(Extensions = string.Join(",", Enum.GetValues(typeof(FileExtensions))))] 

は残念ながら、Extensionsパラメータは、したがって、エラーがVSによってスローされconst文字列型でなければなりません:

私の試みは以下の通りでした。

FileExtensions fileExtension; 
bool fileExtensionParseResult = Enum.TryParse<FileExtensions>(Path.GetExtension(file.FileName), true, out fileExtension); 

他のアイデア:私はもちろん、このような属性の私自身のカスタム検証を書き込むことができますか?

答えて

2

ホワイトリストを扱うとき、私は一般に、これをアプリケーションにハードコーディングするのではなく、設定ファイルを利用します。また、Content-Typeヘッダーを使用して、要求のコンテンツタイプを判断します。 jpgをアップロードするとき、彼らはimage/jpegのようなものを送るべきです。

これで十分な情報が得られない場合は、ご意見をお寄せください。

編集:

ここは自分のプロジェクトの例です。 appsettings.jsonで、以下を追加します。

"AllowedFileUploadTypes": { 
    "image/jpeg": "jpg", 
    "video/quicktime": "mov" 
    } 

私は一般の設定にアクセスするためのラッパークラスを作成し、以下の私の.NET Coreバージョン鉱山の例である:あなたが持っているもちろん

using System.Linq; 
using Microsoft.Extensions.Configuration; 
using System; 
using System.Collections.Generic; 

public class AppConfigurationManager 
{ 
    private IConfiguration _configuration; 

    public AppConfigurationManager(IConfiguration configuration) 
    { 
     _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); 
    } 

    public IDictionary<string, string> AllowedFileUploadTypes => 
        _configuration.GetSection(nameof(AllowedFileUploadTypes)).GetChildren() 
         .Select(item => new KeyValuePair<string, string>(item.Key, item.Value)) 
         .ToDictionary(x => x.Key, x => x.Value); 

} 

その後

public class Startup 
{ 
    public Startup(IConfiguration configuration) 
    {    
     Configuration = configuration; 

    } 
    public IConfiguration Configuration { get; } 

    // This method gets called by the runtime. Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services) 
    { 
     //stuff... 
     services.AddSingleton(Configuration); 
     services.AddSingleton<AppConfigurationManager>(); 
     //other stuff... 
    } 
} 

は、ファイルのコンテンツタイプを検証するIFormFile.ContentType性を評価するためにAppConfigurationManager.AllowedFileUploadTypesを使用することができますStartup.cs

でこれを登録することがValでid。辞書から値を取得し、そのプロパティに対して検証を試みることができます。ドキュメントに基づいて、私は ContentTypeプロパティがContent-Typeヘッダーによって設定されることを前提としています。私は一般的にチャンクを使ってファイルをアップロードするので、 IFormFileは使用していません。

編集:アクションに適用する方法をお望みです。

using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Mvc.Filters; 
using System.Linq; 
using System.Reflection; 
using System.Threading.Tasks; 

public class ValidateFileExtensionsAttribute : ActionFilterAttribute 
{ 

    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) 
    { 
     var fileKeyValue = context.ActionArguments.FirstOrDefault(x => typeof(IFormFile).IsAssignableFrom(x.Value.GetType())); 

     if (fileKeyValue.Value != null) 
     { 
      AppConfigurationManager sessionService = context.HttpContext.RequestServices.GetService(typeof(AppConfigurationManager)) as AppConfigurationManager; 
      IFormFile fileArg = fileKeyValue.Value as IFormFile; 

      if (!sessionService.AllowedFileUploadTypes.Keys.Any(x => x == fileArg.ContentType)) 
      { 
       context.Result = new ObjectResult(new { Error = $"The content-type '{fileArg.ContentType}' is not valid." }) { StatusCode = 400 }; 

       //or you could set the modelstate 
       //context.ModelState.AddModelError(fileKeyValue.Key, $"The content-type '{fileArg.ContentType}' is not valid."); 
       return; 
      } 
     } 

     await next(); 
    } 
} 

次に、あなたがこのような行動にそれを適用することもできます:ActionFilterAttributeを使用して

、あなたはこのような何か行うことができます

[HttpPost] 
[ValidateFileExtensions] 
public async Task<IActionResult> Upload([Required]IFormFile file) 
{ 
    return Ok(); 
} 

をあなたはにModelStateを設定するのActionFilterを修正することができますか、あなたは値を返すことができます。

〜乾杯

+0

@Alexご質問がある場合は、ご確認ください。 – Rogala

+0

返事ありがとうございます。チャンクファイルのアップロードに関しては、複数のファイルのアップロードにも 'IForm'タイプを使うことができると思います。 'List 'に変更して、 'multipart/form-data'形式のフォームを使って提出してください...私の問題については、あなたの答えは、許可されたフォーマットを保存する方法に関する質問に部分的に答えていると思います。これらの値を使用する検証属性 'FileExtensions'をどのように変更するのかという質問に答えてください..あなたのアプリケーションではどこで検証を実行しますか?バリデーション属性、別のバリデータークラス、またはif/elsesを使用したコントローラーアクションで直接ですか? – Alex

+0

私は、検証を一元化し、検証クラスに配置したいと思う傾向があります。 FluentValidationは非常に強力なフレームワークです:http://fluentvalidation.codeplex.com/ – Rogala