FileExtensions 属性 - 使用 Enumerator 作为参数
FileExtensions attribute - using Enumerator as a parameter
长话短说 - 我有一个 Entity Framework
模型接受 Enum
类型 属性:
public class FileUploads {
public AllowedFileTypes FileType { get; set; }
}
枚举是:
public enum AllowedFileTypes {
jpg,
png,
gif,
jpeg,
bmp,
}
然后,在 Web API
控制器中,我为 IFormFile
设置了一个验证属性,如下所示:
[HttpPost]
public async Task<IActionResult> Upload(
[Required]
[FileExtensions(Extensions = "jpg,png,gif,jpeg,bmp")] // allowed filetypes
IFormFile file)
{
return Ok()
}
该方法用于上传文件。现在,问题是我基本上是手动设置 FileExtensions
属性允许的格式。这意味着将来无论何时将新文件格式添加到枚举中——我都需要手动更新每个 FileExtensions
属性。这很容易被遗忘,或者任何其他开发人员都不知道这一事实..
所以,我在想是否可以或如何将 Enum
类型参数传递给 FileExtensions
属性?
我的尝试如下:
[FileExtensions(Extensions = string.Join(",", Enum.GetValues(typeof(FileExtensions))))]
不幸的是,Extensions
参数必须是 const
类型的字符串,因此 VS
会抛出错误。我当然可以编写自己的自定义验证属性,例如:
FileExtensions fileExtension;
bool fileExtensionParseResult = Enum.TryParse<FileExtensions>(Path.GetExtension(file.FileName), true, out fileExtension);
还有其他想法吗?
因此,当我处理白名单时,我通常使用配置文件而不是将其硬编码到应用程序中。另外,我会利用 Content-Type header 来确定请求的内容类型。上传 jpg 时,他们应该发送类似 image/jpeg 的内容。
如果这不能为您提供足够的入门信息,请发表评论,我将制作一个快速示例。
已编辑:
这是我自己项目中的一个例子。在 appsettings.json 中,添加以下内容:
"AllowedFileUploadTypes": {
"image/jpeg": "jpg",
"video/quicktime": "mov"
}
我通常创建一个包装器 class 来访问设置,下面是我的 .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);
}
当然你必须在Startup.cs
中注册这个
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...
}
}
然后你可以使用AppConfigurationManager.AllowedFileUploadTypes
来评估IFormFile.ContentType
属性来验证文件的内容类型是否有效。您可以尝试从字典中获取值,然后根据 属性 进行验证。根据文档,我假设 ContentType
属性 将由 Content-Type header 填充。我一般都是分块上传文件,所以没用过IFormFile
.
已编辑:想要一种方法来应用于操作。
使用 ActionFilterAttribute,您可以这样做:
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();
}
}
然后你可以将其应用于这样的操作:
[HttpPost]
[ValidateFileExtensions]
public async Task<IActionResult> Upload([Required]IFormFile file)
{
return Ok();
}
您可以修改 ActionFilter 以设置 ModelState,或者您可以只 return 值。
长话短说 - 我有一个 Entity Framework
模型接受 Enum
类型 属性:
public class FileUploads {
public AllowedFileTypes FileType { get; set; }
}
枚举是:
public enum AllowedFileTypes {
jpg,
png,
gif,
jpeg,
bmp,
}
然后,在 Web API
控制器中,我为 IFormFile
设置了一个验证属性,如下所示:
[HttpPost]
public async Task<IActionResult> Upload(
[Required]
[FileExtensions(Extensions = "jpg,png,gif,jpeg,bmp")] // allowed filetypes
IFormFile file)
{
return Ok()
}
该方法用于上传文件。现在,问题是我基本上是手动设置 FileExtensions
属性允许的格式。这意味着将来无论何时将新文件格式添加到枚举中——我都需要手动更新每个 FileExtensions
属性。这很容易被遗忘,或者任何其他开发人员都不知道这一事实..
所以,我在想是否可以或如何将 Enum
类型参数传递给 FileExtensions
属性?
我的尝试如下:
[FileExtensions(Extensions = string.Join(",", Enum.GetValues(typeof(FileExtensions))))]
不幸的是,Extensions
参数必须是 const
类型的字符串,因此 VS
会抛出错误。我当然可以编写自己的自定义验证属性,例如:
FileExtensions fileExtension;
bool fileExtensionParseResult = Enum.TryParse<FileExtensions>(Path.GetExtension(file.FileName), true, out fileExtension);
还有其他想法吗?
因此,当我处理白名单时,我通常使用配置文件而不是将其硬编码到应用程序中。另外,我会利用 Content-Type header 来确定请求的内容类型。上传 jpg 时,他们应该发送类似 image/jpeg 的内容。
如果这不能为您提供足够的入门信息,请发表评论,我将制作一个快速示例。
已编辑:
这是我自己项目中的一个例子。在 appsettings.json 中,添加以下内容:
"AllowedFileUploadTypes": {
"image/jpeg": "jpg",
"video/quicktime": "mov"
}
我通常创建一个包装器 class 来访问设置,下面是我的 .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);
}
当然你必须在Startup.cs
中注册这个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...
}
}
然后你可以使用AppConfigurationManager.AllowedFileUploadTypes
来评估IFormFile.ContentType
属性来验证文件的内容类型是否有效。您可以尝试从字典中获取值,然后根据 属性 进行验证。根据文档,我假设 ContentType
属性 将由 Content-Type header 填充。我一般都是分块上传文件,所以没用过IFormFile
.
已编辑:想要一种方法来应用于操作。
使用 ActionFilterAttribute,您可以这样做:
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();
}
}
然后你可以将其应用于这样的操作:
[HttpPost]
[ValidateFileExtensions]
public async Task<IActionResult> Upload([Required]IFormFile file)
{
return Ok();
}
您可以修改 ActionFilter 以设置 ModelState,或者您可以只 return 值。