asp.net-core - 从 .net core 5 中的 View 访问 Controller 实例

标签 asp.net-core asp.net-core-5.0

我一直在通过下一行 ASP.NET 从 View 访问基本 Controller 实例

BaseController baseController = ViewContext.Controller as BaseController;

我在 ASP.NET Core 5.0 中有一个新项目。出于某种原因我想访问基本 Controller ,但现在看来它与以前版本的 MVC 不相似。

是否有任何解决方案或替代方案来实现同样的目标?

注意:我想访问 Controller 的完全初始化实例。我尝试使用 GetService() 方法通过依赖注入(inject)获取实例。它提供了 Controller 的新实例,但没有完全初始化,例如HttpContextUser 等属性都是空的。

最佳答案

注意第一个基于 ControllerActionInvokerCache 的解决方案在 asp.net core 2.2 中进行了测试并且运行良好。但是在以后的版本中,看起来该类是 internal 并且不再可访问,此解决方案将无济于事。试试后面介绍的第二种方案。

调用的 Controller 之前缓存在 ControllerActionInvokerCache 中(可通过 DI 获得)。缓存键是 ControllerContext 的一个实例,它不是通过引用进行相等比较的(因此只要包装的 ActionContext 是当前实例,您就可以实例化一个新实例)。 ControllerActionInvokerCache其实就是一个复合缓存。

具体可以看下面的代码:

public static class RazorViewExtensions
{
    public static Controller GetInvokedController(this RazorPage view)
    {
        var serviceProvider = view.Context.RequestServices;
        var controllerCache = serviceProvider.GetRequiredService<ControllerActionInvokerCache>();         
        //ViewContext here is also an ActionContext   
        var controllerContext = new ControllerContext(view.ViewContext);
        var cacheEntry = controllerCache.GetCachedResult(controllerContext).cacheEntry;
        return cacheEntry == null ? null : cacheEntry.ControllerFactory(controllerContext) as Controller;
    }
}    

为方便起见,我们声明了一个扩展方法,如上。在 Controller 的 View 中使用它:

var controller = this.GetInvokedController();

您可以基于此编写一个类似的扩展方法,用于在 Razor 页面内部使用(基础页面是 Page 而不是 RazorPage)。

实际上 ControllerActionInvokerCacheEntry 被传递给 ControllerActionDescriptor.CacheEntry。但是 CacheEntry 属性是内部的(当然没有记录)。我们可以在源代码中看到这一点。所以基本上你可以使用 reflection 来获取缓存条目。但是它需要反射,所以代码块比我们上面使用的第一个解决方案还要长。

这是从 ActionExecutingContext.Controller 中提取 Controller 实例的另一种解决方案。这可能比第一个解决方案快一点,但我们需要一个单独的类来为自定义 IActionFilter 捕获 Controller 实例到一个功能中通过 HttpContext.Features 共享。代码当然有点长,像这样:

//define the feature types
public interface IInvokedControllerFeature
{
    Controller Controller { get; }
}
public class InvokedControllerFeature : IInvokedControllerFeature
{
    public InvokedControllerFeature(Controller controller)
    {
        Controller = controller;
    }
    public Controller Controller { get; }
}

//an extension class to contain several convenient extension methods
//to setup the feature and get the controller instance later
public static class InvokedControllerFeatureExtensions
{
    public static Controller GetInvokedController(this HttpContext httpContext)
    {
        return httpContext.Features.Get<IInvokedControllerFeature>()?.Controller;
    }
    public static Controller GetInvokedController(this RazorPage view)
    {
        return view.Context.GetInvokedController();
    }
    public static IServiceCollection AddInvokedControllerFeature(this IServiceCollection services)
    {
        return services.Configure<MvcOptions>(o => {
            o.Filters.Add<InvokedControllerFeatureActionFilter>();
        });
    }
    class InvokedControllerFeatureActionFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context) {}

        public void OnActionExecuting(ActionExecutingContext context)
        {
            //share the controller instance via a feature
            context.HttpContext.Features.Set<IInvokedControllerFeature>(new InvokedControllerFeature(context.Controller as Controller));
        }
    }
}

//register the feature inside Startup.ConfigureServices
services.AddInvokedControllerFeature();

Controller View 中的用法与第一个解决方案中的用法相同。

关于asp.net-core - 从 .net core 5 中的 View 访问 Controller 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66689593/

相关文章:

c# - ASP.NET 5 (vNext) 中的身份验证

c# - 将 GeoJson 特征映射到属性

asp.net-core - 在 db ASP.NET Core 中临时保存密码

c# - 如何禁用特定 ASP.NET Core 5.0 Web API 操作的自动模型绑定(bind)?

c# - 需要哪些配置才能使 NodaTime.Instant 在 AspNetCore 中用作查询/路径/表单参数?

c# - 如何使用 ASP.NET 5 运行 Firebird 嵌入式数据库?

azure - .net core 5.0 生产环境是否已准备好用于 azure 应用服务

c# - 如何在 ASP.NET Core 5 中使用 IdentityUser 和 IdentityRole 之间的隐式多对多

asp.net-core - 如何解决 Blazor 中重新渲染缓慢的问题;如何获取各个组件的渲染时间?

c# - 由于对象的当前状态,操作无效。使用 dotnet core 5 在 eventhub 中获取 microsoft.azure.amqp