我在the documentation之后创建了一个简单的ASP.NET MVC核心过滤器,但是在过滤器上添加了一个参数:
public class MyFilterAttribute : TypeFilterAttribute
{
public ApiAuthorizeAttribute(string arg1 = null) : base(typeof(MyFilterImpl))
{
this.Arguments = new object[] { arg1 };
}
private class MyFilterImpl : IAsyncActionFilter
{
private readonly string _arg1;
public MyFilterImpl(string arg1 /*, DI dependencies */)
{
this._arg1 = arg1;
}
async Task IAsyncActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Do stuff
await next();
}
}
}
在应用如下属性时效果很好:
[MyFilter(arg1: "foo")]
public async Task<IActionResult> Get()
{
}
但是在属性声明中传递null时失败:
[MyFilter] // equivalent to [MyFilter(arg1: null)]
public async Task<IActionResult> Get()
{
}
运行时在this line上抛出NullReferenceException
。我可以通过传递""
而不是null来解决此问题,但这是否是预期的或不可避免的行为?
答案 0 :(得分:2)
您已在构造函数中实例化了this.Arguments
,所以我想这是预期的行为。
您有几种解决方法。
您可以添加一个if
子句以不初始化它。如果参数为null,则为参数
public MyFilterAttribute(string arg1 = null) : base(typeof(MyFilterImpl))
{
if(!string.IsNullOrEmpty(arg1))
{
this.Arguments = new object[] { arg1 };
}
}
或添加第二个不初始化此参数的无参数构造函数。参数
public MyFilterAttribute(string arg1) : base(typeof(MyFilterImpl))
{
this.Arguments = new object[] { arg1 };
}
public MyFilterAttribute() : base(typeof(MyFilterImpl))
{
}
两者都会导致MyFilterImpl
被null
或传入的值实例化。
我个人比较喜欢第二种选择,因为它可以使代码更整洁并坚持“单一责任原则”
答案 1 :(得分:0)
您已经找到了根本原因,
if (_factory == null)
{
var argumentTypes = Arguments?.Select(a => a.GetType())?.ToArray();
_factory = ActivatorUtilities.CreateFactory(ImplementationType, argumentTypes ?? Type.EmptyTypes);
}
它将使用a.GetType()
初始化argumentsTypes,如果您传递null或使用optionl参数null
,则此行将引发预期的错误。
为避免每次操作都传递""
,您可以尝试将string arg1
设置为默认值""
。
public MyFilterAttribute(string arg1 = "") : base(typeof(MyFilterImpl))
{
this.Arguments = new object[] { arg1 };
}