File: Infrastructure\DefaultPageActivatorProvider.cs
Web Access
Project: src\src\Mvc\Mvc.RazorPages\src\Microsoft.AspNetCore.Mvc.RazorPages.csproj (Microsoft.AspNetCore.Mvc.RazorPages)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Rendering;
 
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
 
/// <summary>
/// <see cref="IPageActivatorProvider"/> that uses type activation to create Pages.
/// </summary>
internal sealed class DefaultPageActivatorProvider : IPageActivatorProvider
{
    private readonly Action<PageContext, ViewContext, object> _disposer = Dispose;
    private readonly Func<PageContext, ViewContext, object, ValueTask> _asyncDisposer = AsyncDispose;
    private readonly Func<PageContext, ViewContext, object, ValueTask> _syncAsyncDisposer = SyncAsyncDispose;
 
    /// <inheritdoc />
    public Func<PageContext, ViewContext, object> CreateActivator(CompiledPageActionDescriptor actionDescriptor)
    {
        ArgumentNullException.ThrowIfNull(actionDescriptor);
 
        var pageTypeInfo = actionDescriptor.PageTypeInfo?.AsType();
        if (pageTypeInfo == null)
        {
            throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
                nameof(actionDescriptor.PageTypeInfo),
                nameof(actionDescriptor)),
                nameof(actionDescriptor));
        }
 
        return CreatePageFactory(pageTypeInfo);
    }
 
    public Action<PageContext, ViewContext, object>? CreateReleaser(CompiledPageActionDescriptor actionDescriptor)
    {
        ArgumentNullException.ThrowIfNull(actionDescriptor);
 
        if (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo))
        {
            return _disposer;
        }
 
        return null;
    }
 
    public Func<PageContext, ViewContext, object, ValueTask>? CreateAsyncReleaser(CompiledPageActionDescriptor actionDescriptor)
    {
        ArgumentNullException.ThrowIfNull(actionDescriptor);
 
        if (typeof(IAsyncDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo))
        {
            return _asyncDisposer;
        }
 
        if (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo))
        {
            return _syncAsyncDisposer;
        }
 
        return null;
    }
 
    private static Func<PageContext, ViewContext, object> CreatePageFactory(Type pageTypeInfo)
    {
        var parameter1 = Expression.Parameter(typeof(PageContext), "pageContext");
        var parameter2 = Expression.Parameter(typeof(ViewContext), "viewContext");
 
        // new Page();
        var newExpression = Expression.New(pageTypeInfo);
 
        // () => new Page();
        var pageFactory = Expression
            .Lambda<Func<PageContext, ViewContext, object>>(newExpression, parameter1, parameter2)
            .Compile();
        return pageFactory;
    }
 
    private static void Dispose(PageContext context, ViewContext viewContext, object page)
    {
        ArgumentNullException.ThrowIfNull(context);
        ArgumentNullException.ThrowIfNull(viewContext);
        ArgumentNullException.ThrowIfNull(page);
 
        ((IDisposable)page).Dispose();
    }
 
    private static ValueTask SyncAsyncDispose(PageContext context, ViewContext viewContext, object page)
    {
        Dispose(context, viewContext, page);
        return default;
    }
 
    private static ValueTask AsyncDispose(PageContext context, ViewContext viewContext, object page)
    {
        ArgumentNullException.ThrowIfNull(context);
        ArgumentNullException.ThrowIfNull(viewContext);
        ArgumentNullException.ThrowIfNull(page);
 
        return ((IAsyncDisposable)page).DisposeAsync();
    }
}