当实例化具有null参数的内部过滤器时,TypeFilter属性引发NullReferenceException

时间:2019-01-20 23:02:58

标签: c# asp.net-core

我在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来解决此问题,但这是否是预期的或不可避免的行为?

2 个答案:

答案 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))
{
}

两者都会导致MyFilterImplnull或传入的值实例化。

我个人比较喜欢第二种选择,因为它可以使代码更整洁并坚持“单一责任原则”

答案 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 };
}