parent
cc584ada39
commit
3e214e2399
|
|
@ -0,0 +1,27 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to create a Razor Page model.
|
||||
/// </summary>
|
||||
public interface IPageModelActivatorProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a Razor Page model activator.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The <see cref="CompiledPageActionDescriptor"/>.</param>
|
||||
/// <returns>The delegate used to activate the page model.</returns>
|
||||
Func<PageContext, object> CreateActivator(CompiledPageActionDescriptor descriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Releases a Razor Page model.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The <see cref="CompiledPageActionDescriptor"/>.</param>
|
||||
/// <returns>The delegate used to dispose the activated Razor Page model.</returns>
|
||||
Action<PageContext, object> CreateReleaser(CompiledPageActionDescriptor descriptor);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for creation and disposal of Razor Page models.
|
||||
/// </summary>
|
||||
public interface IPageModelFactoryProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a factory for producing models for Razor Pages given the specified <see cref="PageContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The <see cref="CompiledPageActionDescriptor"/>.</param>
|
||||
/// <returns>The Razor Page model factory.</returns>
|
||||
Func<PageContext, object> CreateModelFactory(CompiledPageActionDescriptor descriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Releases a Razor Page model.
|
||||
/// </summary>
|
||||
/// <param name="descriptor">The <see cref="CompiledPageActionDescriptor"/>.</param>
|
||||
/// <returns>The delegate used to release the created Razor Page model.</returns>
|
||||
Action<PageContext, object> CreateModelDisposer(CompiledPageActionDescriptor descriptor);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IPageActivatorProvider"/> that uses type activation to create Pages.
|
||||
|
|
@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Mvc.Rendering;
|
|||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageFactory : IPageFactoryProvider
|
||||
{
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// 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 System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IPageActivatorProvider"/> that uses type activation to create Razor Page instances.
|
||||
/// </summary>
|
||||
public class DefaultPageModelActivatorProvider : IPageModelActivatorProvider
|
||||
{
|
||||
private readonly Action<PageContext, object> _disposer = Dispose;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Func<PageContext, object> CreateActivator(CompiledPageActionDescriptor actionDescriptor)
|
||||
{
|
||||
if (actionDescriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(actionDescriptor));
|
||||
}
|
||||
|
||||
var modelTypeInfo = actionDescriptor.ModelTypeInfo?.AsType();
|
||||
if (modelTypeInfo == null)
|
||||
{
|
||||
throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(actionDescriptor.ModelTypeInfo),
|
||||
nameof(actionDescriptor)),
|
||||
nameof(actionDescriptor));
|
||||
}
|
||||
|
||||
var factory = ActivatorUtilities.CreateFactory(modelTypeInfo, Type.EmptyTypes);
|
||||
return (context) => factory(context.HttpContext.RequestServices, EmptyArray<object>.Instance);
|
||||
}
|
||||
|
||||
public virtual Action<PageContext, object> CreateReleaser(CompiledPageActionDescriptor actionDescriptor)
|
||||
{
|
||||
if (actionDescriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(actionDescriptor));
|
||||
}
|
||||
|
||||
if (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.ModelTypeInfo))
|
||||
{
|
||||
return _disposer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void Dispose(PageContext context, object page)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (page == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(page));
|
||||
}
|
||||
|
||||
((IDisposable)page).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// 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 System.Reflection;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageModelFactoryProvider : IPageModelFactoryProvider
|
||||
{
|
||||
private static readonly Func<PropertyInfo, PropertyActivator<PageContext>> _createActivateInfo =
|
||||
CreateActivateInfo;
|
||||
private readonly IPageModelActivatorProvider _modelActivator;
|
||||
|
||||
public DefaultPageModelFactoryProvider(IPageModelActivatorProvider modelActivator)
|
||||
{
|
||||
_modelActivator = modelActivator;
|
||||
}
|
||||
|
||||
public virtual Func<PageContext, object> CreateModelFactory(CompiledPageActionDescriptor descriptor)
|
||||
{
|
||||
if (descriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(descriptor));
|
||||
}
|
||||
|
||||
if (descriptor.ModelTypeInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var modelActivator = _modelActivator.CreateActivator(descriptor);
|
||||
var propertyActivator = PropertyActivator<PageContext>.GetPropertiesToActivate(
|
||||
descriptor.ModelTypeInfo.AsType(),
|
||||
typeof(PageContextAttribute),
|
||||
_createActivateInfo,
|
||||
includeNonPublic: false);
|
||||
|
||||
return pageContext =>
|
||||
{
|
||||
var model = modelActivator(pageContext);
|
||||
for (var i = 0; i < propertyActivator.Length; i++)
|
||||
{
|
||||
propertyActivator[i].Activate(model, pageContext);
|
||||
}
|
||||
|
||||
return model;
|
||||
};
|
||||
}
|
||||
|
||||
public virtual Action<PageContext, object> CreateModelDisposer(CompiledPageActionDescriptor descriptor)
|
||||
{
|
||||
if (descriptor == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(descriptor));
|
||||
}
|
||||
|
||||
if (descriptor.ModelTypeInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _modelActivator.CreateReleaser(descriptor);
|
||||
}
|
||||
|
||||
private static PropertyActivator<PageContext> CreateActivateInfo(PropertyInfo property) =>
|
||||
new PropertyActivator<PageContext>(property, pageContext => pageContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
private const string ModelPropertyName = "Model";
|
||||
private readonly IPageLoader _loader;
|
||||
private readonly IPageFactoryProvider _pageFactoryProvider;
|
||||
private readonly IPageModelFactoryProvider _modelFactoryProvider;
|
||||
private readonly IActionDescriptorCollectionProvider _collectionProvider;
|
||||
private readonly IFilterProvider[] _filterProviders;
|
||||
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
|
||||
|
|
@ -38,6 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
public PageActionInvokerProvider(
|
||||
IPageLoader loader,
|
||||
IPageFactoryProvider pageFactoryProvider,
|
||||
IPageModelFactoryProvider modelFactoryProvider,
|
||||
IActionDescriptorCollectionProvider collectionProvider,
|
||||
IEnumerable<IFilterProvider> filterProviders,
|
||||
IEnumerable<IValueProviderFactory> valueProviderFactories,
|
||||
|
|
@ -49,8 +51,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_loader = loader;
|
||||
_collectionProvider = collectionProvider;
|
||||
_pageFactoryProvider = pageFactoryProvider;
|
||||
_modelFactoryProvider = modelFactoryProvider;
|
||||
_collectionProvider = collectionProvider;
|
||||
_filterProviders = filterProviders.ToArray();
|
||||
_valueProviderFactories = valueProviderFactories.ToArray();
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
|
|
@ -157,12 +160,23 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
PageTypeInfo = compiledType,
|
||||
};
|
||||
|
||||
var pageFactory = _pageFactoryProvider.CreatePageFactory(compiledActionDescriptor);
|
||||
var pageDisposer = _pageFactoryProvider.CreatePageDisposer(compiledActionDescriptor);
|
||||
|
||||
Func<PageContext, object> modelFactory = null;
|
||||
Action<PageContext, object> modelReleaser = null;
|
||||
if (modelType != null)
|
||||
{
|
||||
modelFactory = _modelFactoryProvider.CreateModelFactory(compiledActionDescriptor);
|
||||
modelReleaser = _modelFactoryProvider.CreateModelDisposer(compiledActionDescriptor);
|
||||
}
|
||||
|
||||
return new PageActionInvokerCacheEntry(
|
||||
compiledActionDescriptor,
|
||||
_pageFactoryProvider.CreatePageFactory(compiledActionDescriptor),
|
||||
_pageFactoryProvider.CreatePageDisposer(compiledActionDescriptor),
|
||||
c => { throw new NotImplementedException(); },
|
||||
(_, __) => { throw new NotImplementedException(); },
|
||||
pageFactory,
|
||||
pageDisposer,
|
||||
modelFactory,
|
||||
modelReleaser,
|
||||
cachedFilters);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies that a Razor Page model property should be set with the current <see cref="PageContext"/> when creating
|
||||
/// the model instance. The property must have a public set method.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||
public class PageContextAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Testing;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageActivatorTest
|
||||
{
|
||||
|
|
@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
|||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageFactoryProviderTest
|
||||
{
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// 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 System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageModelActivatorProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void CreateActivator_ThrowsIfModelTypeInfoOnActionDescriptorIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var activatorProvider = new DefaultPageModelActivatorProvider();
|
||||
var actionDescriptor = new CompiledPageActionDescriptor();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
() => activatorProvider.CreateActivator(actionDescriptor),
|
||||
"actionDescriptor",
|
||||
"The 'ModelTypeInfo' property of 'actionDescriptor' must not be null.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateActivator_CreatesModelInstance()
|
||||
{
|
||||
// Arrange
|
||||
var activatorProvider = new DefaultPageModelActivatorProvider();
|
||||
var actionDescriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
ModelTypeInfo = typeof(SimpleModel).GetTypeInfo(),
|
||||
};
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var generator = Mock.Of<IHtmlGenerator>();
|
||||
serviceCollection.AddSingleton(generator);
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = serviceCollection.BuildServiceProvider(),
|
||||
};
|
||||
var pageContext = new PageContext
|
||||
{
|
||||
HttpContext = httpContext
|
||||
};
|
||||
|
||||
// Act
|
||||
var activator = activatorProvider.CreateActivator(actionDescriptor);
|
||||
var model = activator(pageContext);
|
||||
|
||||
// Assert
|
||||
var simpleModel = Assert.IsType<SimpleModel>(model);
|
||||
Assert.NotNull(simpleModel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateActivator_TypeActivatesModelType()
|
||||
{
|
||||
// Arrange
|
||||
var activatorProvider = new DefaultPageModelActivatorProvider();
|
||||
var actionDescriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
ModelTypeInfo = typeof(ModelWithServices).GetTypeInfo(),
|
||||
};
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var generator = Mock.Of<IHtmlGenerator>();
|
||||
serviceCollection.AddSingleton(generator);
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = serviceCollection.BuildServiceProvider(),
|
||||
};
|
||||
var pageContext = new PageContext
|
||||
{
|
||||
HttpContext = httpContext
|
||||
};
|
||||
|
||||
// Act
|
||||
var activator = activatorProvider.CreateActivator(actionDescriptor);
|
||||
var model = activator(pageContext);
|
||||
|
||||
// Assert
|
||||
var modelWithServices = Assert.IsType<ModelWithServices>(model);
|
||||
Assert.Same(generator, modelWithServices.Generator);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(SimpleModel))]
|
||||
[InlineData(typeof(object))]
|
||||
public void CreateReleaser_ReturnsNullForModelsThatDoNotImplementDisposable(Type pageType)
|
||||
{
|
||||
// Arrange
|
||||
var context = new PageContext();
|
||||
var activator = new DefaultPageActivator();
|
||||
var actionDescriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
PageTypeInfo = pageType.GetTypeInfo(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var releaser = activator.CreateReleaser(actionDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Null(releaser);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateReleaser_CreatesDelegateThatDisposesDisposableTypes()
|
||||
{
|
||||
// Arrange
|
||||
var context = new PageContext();
|
||||
var activator = new DefaultPageActivator();
|
||||
var actionDescriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
PageTypeInfo = typeof(DisposableModel).GetTypeInfo(),
|
||||
};
|
||||
var model = new DisposableModel();
|
||||
|
||||
// Act & Assert
|
||||
var releaser = activator.CreateReleaser(actionDescriptor);
|
||||
releaser(context, model);
|
||||
|
||||
// Assert
|
||||
Assert.True(model.Disposed);
|
||||
}
|
||||
|
||||
private class SimpleModel
|
||||
{
|
||||
}
|
||||
|
||||
private class ModelWithServices
|
||||
{
|
||||
public ModelWithServices(IHtmlGenerator generator)
|
||||
{
|
||||
Generator = generator;
|
||||
}
|
||||
|
||||
public IHtmlGenerator Generator { get; }
|
||||
}
|
||||
|
||||
private class DisposableModel : IDisposable
|
||||
{
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
// 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 System.Reflection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
public class DefaultPageModelFactoryProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void CreateModelFactory_ReturnsNullFactoryIfModelTypeIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new CompiledPageActionDescriptor();
|
||||
var pageContext = new PageContext();
|
||||
var factoryProvider = CreateModelFactoryProvider();
|
||||
|
||||
// Act
|
||||
var factory = factoryProvider.CreateModelFactory(descriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Null(factory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateModelDisposer_ReturnsNullFactoryIfModelTypeIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new CompiledPageActionDescriptor();
|
||||
var pageContext = new PageContext();
|
||||
var factoryProvider = CreateModelFactoryProvider();
|
||||
|
||||
// Act
|
||||
var disposer = factoryProvider.CreateModelDisposer(descriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Null(disposer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelFactory_InitializesModelInstances()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
ModelTypeInfo = typeof(SimpleModel).GetTypeInfo(),
|
||||
};
|
||||
var pageContext = new PageContext();
|
||||
var factoryProvider = CreateModelFactoryProvider();
|
||||
|
||||
// Act
|
||||
var factory = factoryProvider.CreateModelFactory(descriptor);
|
||||
var instance = factory(pageContext);
|
||||
|
||||
// Assert
|
||||
var model = Assert.IsType<SimpleModel>(instance);
|
||||
Assert.NotNull(model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelFactory_InjectsPropertiesWithPageContextAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
ModelTypeInfo = typeof(ModelWithPageContext).GetTypeInfo(),
|
||||
};
|
||||
var pageContext = new PageContext();
|
||||
var factoryProvider = CreateModelFactoryProvider();
|
||||
|
||||
// Act
|
||||
var factory = factoryProvider.CreateModelFactory(descriptor);
|
||||
var instance = factory(pageContext);
|
||||
|
||||
// Assert
|
||||
var testModel = Assert.IsType<ModelWithPageContext>(instance);
|
||||
Assert.Same(pageContext, testModel.ContextWithAttribute);
|
||||
Assert.Null(testModel.ContextWithoutAttribute);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateModelDisposer_ReturnsDisposerFromModelActivatorProvider()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
ModelTypeInfo = typeof(SimpleModel).GetTypeInfo()
|
||||
};
|
||||
var pageContext = new PageContext();
|
||||
var modelActivatorProvider = new Mock<IPageModelActivatorProvider>();
|
||||
Action<PageContext, object> disposer = (_, __) => { };
|
||||
modelActivatorProvider.Setup(p => p.CreateReleaser(descriptor))
|
||||
.Returns(disposer);
|
||||
var factoryProvider = CreateModelFactoryProvider(modelActivatorProvider.Object);
|
||||
|
||||
// Act
|
||||
var actual = factoryProvider.CreateModelDisposer(descriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Same(disposer, actual);
|
||||
}
|
||||
|
||||
private static DefaultPageModelFactoryProvider CreateModelFactoryProvider(
|
||||
IPageModelActivatorProvider modelActivator = null)
|
||||
{
|
||||
if (modelActivator == null)
|
||||
{
|
||||
var mockActivator = new Mock<IPageModelActivatorProvider>();
|
||||
mockActivator.Setup(a => a.CreateActivator(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns((CompiledPageActionDescriptor descriptor) =>
|
||||
{
|
||||
return (context) => Activator.CreateInstance(descriptor.ModelTypeInfo.AsType());
|
||||
});
|
||||
|
||||
modelActivator = mockActivator.Object;
|
||||
}
|
||||
|
||||
return new DefaultPageModelFactoryProvider(modelActivator);
|
||||
}
|
||||
|
||||
private class SimpleModel
|
||||
{
|
||||
}
|
||||
|
||||
private class ModelWithPageContext
|
||||
{
|
||||
[PageContext]
|
||||
public PageContext ContextWithAttribute { get; set; }
|
||||
|
||||
public PageContext ContextWithoutAttribute { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,24 +3,24 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
{
|
||||
public class PageInvokerProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_PopulatesCacheEntry()
|
||||
public void OnProvidersExecuting_WithEmptyModel_PopulatesCacheEntry()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor
|
||||
|
|
@ -30,22 +30,23 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
};
|
||||
Func<PageContext, object> factory = _ => null;
|
||||
Action<PageContext, object> releaser = (_, __) => { };
|
||||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(object));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
var factoryProvider = new Mock<IPageFactoryProvider>();
|
||||
factoryProvider.Setup(f => f.CreatePageFactory(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
var pageFactoryProvider = new Mock<IPageFactoryProvider>();
|
||||
pageFactoryProvider.Setup(f => f.CreatePageFactory(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(factory);
|
||||
factoryProvider.Setup(f => f.CreatePageDisposer(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
pageFactoryProvider.Setup(f => f.CreatePageDisposer(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(releaser);
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
factoryProvider.Object);
|
||||
pageFactoryProvider.Object);
|
||||
var context = new ActionInvokerProviderContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), descriptor));
|
||||
|
||||
|
|
@ -60,6 +61,63 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.Equal(descriptor.RelativePath, compiledPageActionDescriptor.RelativePath);
|
||||
Assert.Same(factory, entry.PageFactory);
|
||||
Assert.Same(releaser, entry.ReleasePage);
|
||||
Assert.Null(entry.ModelFactory);
|
||||
Assert.Null(entry.ReleaseModel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_WithModel_PopulatesCacheEntry()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
};
|
||||
Func<PageContext, object> factory = _ => null;
|
||||
Action<PageContext, object> releaser = (_, __) => { };
|
||||
Func<PageContext, object> modelFactory = _ => null;
|
||||
Action<PageContext, object> modelDisposer = (_, __) => { };
|
||||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(PageWithModel));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
var pageFactoryProvider = new Mock<IPageFactoryProvider>();
|
||||
pageFactoryProvider.Setup(f => f.CreatePageFactory(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(factory);
|
||||
pageFactoryProvider.Setup(f => f.CreatePageDisposer(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(releaser);
|
||||
|
||||
var modelFactoryProvider = new Mock<IPageModelFactoryProvider>();
|
||||
modelFactoryProvider.Setup(f => f.CreateModelFactory(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(modelFactory);
|
||||
modelFactoryProvider.Setup(f => f.CreateModelDisposer(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(modelDisposer);
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
pageFactoryProvider.Object,
|
||||
modelFactoryProvider.Object);
|
||||
var context = new ActionInvokerProviderContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), descriptor));
|
||||
|
||||
// Act
|
||||
invokerProvider.OnProvidersExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(context.Result);
|
||||
var actionInvoker = Assert.IsType<PageActionInvoker>(context.Result);
|
||||
var entry = actionInvoker.CacheEntry;
|
||||
var compiledPageActionDescriptor = Assert.IsType<CompiledPageActionDescriptor>(entry.ActionDescriptor);
|
||||
Assert.Equal(descriptor.RelativePath, compiledPageActionDescriptor.RelativePath);
|
||||
Assert.Same(factory, entry.PageFactory);
|
||||
Assert.Same(releaser, entry.ReleasePage);
|
||||
Assert.Same(modelFactory, entry.ModelFactory);
|
||||
Assert.Same(modelDisposer, entry.ReleaseModel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -80,8 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
Mock.Of<IPageFactoryProvider>());
|
||||
actionDescriptorProvider.Object);
|
||||
var context = new ActionInvokerProviderContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), descriptor));
|
||||
|
||||
|
|
@ -124,8 +181,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
.Returns(typeof(object));
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
Mock.Of<IPageFactoryProvider>());
|
||||
actionDescriptorProvider.Object);
|
||||
var context = new ActionInvokerProviderContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), descriptor));
|
||||
|
||||
|
|
@ -150,7 +206,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
private static PageActionInvokerProvider CreateInvokerProvider(
|
||||
IPageLoader loader,
|
||||
IActionDescriptorCollectionProvider actionDescriptorProvider,
|
||||
IPageFactoryProvider factoryProvider)
|
||||
IPageFactoryProvider pageProvider = null,
|
||||
IPageModelFactoryProvider modelProvider = null)
|
||||
{
|
||||
var tempDataFactory = new Mock<ITempDataDictionaryFactory>();
|
||||
tempDataFactory.Setup(t => t.GetTempData(It.IsAny<HttpContext>()))
|
||||
|
|
@ -158,7 +215,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
return new PageActionInvokerProvider(
|
||||
loader,
|
||||
factoryProvider,
|
||||
pageProvider ?? Mock.Of<IPageFactoryProvider>(),
|
||||
modelProvider ?? Mock.Of<IPageModelFactoryProvider>(),
|
||||
actionDescriptorProvider,
|
||||
new IFilterProvider[0],
|
||||
new IValueProviderFactory[0],
|
||||
|
|
@ -169,5 +227,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||
NullLoggerFactory.Instance);
|
||||
}
|
||||
|
||||
private class PageWithModel
|
||||
{
|
||||
public object Model { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue