Unwrap filter factories in TypeFilterAttribute & ServiceFilterAttribute

Fixes #7855
This commit is contained in:
Pranav K 2018-08-20 18:51:16 -07:00
parent dfb579d45c
commit a7301120b1
No known key found for this signature in database
GPG Key ID: 1963DA6D96C3057A
4 changed files with 190 additions and 10 deletions

View File

@ -3,7 +3,6 @@
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
@ -58,14 +57,11 @@ namespace Microsoft.AspNetCore.Mvc
throw new ArgumentNullException(nameof(serviceProvider));
}
var service = serviceProvider.GetRequiredService(ServiceType);
var filter = service as IFilterMetadata;
if (filter == null)
var filter = (IFilterMetadata)serviceProvider.GetRequiredService(ServiceType);
if (filter is IFilterFactory filterFactory)
{
throw new InvalidOperationException(Resources.FormatFilterFactoryAttribute_TypeMustImplementIFilter(
typeof(ServiceFilterAttribute).Name,
typeof(IFilterMetadata).Name));
// Unwrap filter factories
filter = filterFactory.CreateInstance(serviceProvider);
}
return filter;

View File

@ -73,11 +73,17 @@ namespace Microsoft.AspNetCore.Mvc
if (_factory == null)
{
var argumentTypes = Arguments?.Select(a => a.GetType())?.ToArray();
_factory = ActivatorUtilities.CreateFactory(ImplementationType, argumentTypes ?? Type.EmptyTypes);
}
return (IFilterMetadata)_factory(serviceProvider, Arguments);
var filter = (IFilterMetadata)_factory(serviceProvider, Arguments);
if (filter is IFilterFactory filterFactory)
{
// Unwrap filter factories
filter = filterFactory.CreateInstance(serviceProvider);
}
return filter;
}
}
}

View File

@ -0,0 +1,62 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Mvc
{
public class ServiceFilterAttributeTest
{
[Fact]
public void CreateService_GetsFilterFromServiceProvider()
{
// Arrange
var expected = new TestFilter();
var serviceProvider = new ServiceCollection()
.AddSingleton(expected)
.BuildServiceProvider();
var serviceFilter = new ServiceFilterAttribute(typeof(TestFilter));
// Act
var filter = serviceFilter.CreateInstance(serviceProvider);
// Assert
Assert.Same(expected, filter);
}
[Fact]
public void CreateService_UnwrapsFilterFactory()
{
// Arrange
var serviceProvider = new ServiceCollection()
.AddSingleton(new TestFilterFactory())
.BuildServiceProvider();
var serviceFilter = new ServiceFilterAttribute(typeof(TestFilterFactory));
// Act
var filter = serviceFilter.CreateInstance(serviceProvider);
// Assert
Assert.IsType<TestFilter>(filter);
}
public class TestFilter : IFilterMetadata
{
}
public class TestFilterFactory : IFilterFactory
{
public bool IsReusable => throw new NotImplementedException();
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new TestFilter();
}
}
}
}

View File

@ -0,0 +1,116 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Mvc
{
public class TypeFilterAttributeTest
{
[Fact]
public void CreateService_TypeActivatesImplementationType()
{
// Arrange
var value = "Some value";
var uri = new Uri("http://www.asp.net");
var serviceProvider = new ServiceCollection()
.AddSingleton(value)
.AddSingleton(uri)
.BuildServiceProvider();
var typeFilter = new TypeFilterAttribute(typeof(TestFilter));
// Act
var filter = typeFilter.CreateInstance(serviceProvider);
// Assert
var testFilter = Assert.IsType<TestFilter>(filter);
Assert.Same(value, testFilter.Value);
Assert.Same(uri, testFilter.Uri);
}
[Fact]
public void CreateService_UsesArguments()
{
// Arrange
var value = "Some value";
var uri = new Uri("http://www.asp.net");
var serviceProvider = new ServiceCollection()
.AddSingleton("Value in DI")
.AddSingleton(uri)
.BuildServiceProvider();
var typeFilter = new TypeFilterAttribute(typeof(TestFilter))
{
Arguments = new[] { value, }
};
// Act
var filter = typeFilter.CreateInstance(serviceProvider);
// Assert
var testFilter = Assert.IsType<TestFilter>(filter);
Assert.Same(value, testFilter.Value);
Assert.Same(uri, testFilter.Uri);
}
[Fact]
public void CreateService_UnwrapsFilterFactory()
{
// Arrange
var value = "Some value";
var uri = new Uri("http://www.asp.net");
var serviceProvider = new ServiceCollection()
.AddSingleton("Value in DI")
.AddSingleton(uri)
.BuildServiceProvider();
var typeFilter = new TypeFilterAttribute(typeof(TestFilterFactory))
{
Arguments = new[] { value, }
};
// Act
var filter = typeFilter.CreateInstance(serviceProvider);
// Assert
var testFilter = Assert.IsType<TestFilter>(filter);
Assert.Same(value, testFilter.Value);
Assert.Same(uri, testFilter.Uri);
}
public class TestFilter : IFilterMetadata
{
public TestFilter(string value, Uri uri)
{
Value = value;
Uri = uri;
}
public string Value { get; }
public Uri Uri { get; }
}
public class TestFilterFactory : IFilterFactory
{
private readonly string _value;
private readonly Uri _uri;
public TestFilterFactory(string value, Uri uri)
{
_value = value;
_uri = uri;
}
public bool IsReusable => throw new NotImplementedException();
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return new TestFilter(_value, _uri);
}
}
}
}