Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net core mvc 如何以及在何处判断ViewComponent是否在视图中被调用了x次?_Asp.net Core Mvc - Fatal编程技术网

Asp.net core mvc 如何以及在何处判断ViewComponent是否在视图中被调用了x次?

Asp.net core mvc 如何以及在何处判断ViewComponent是否在视图中被调用了x次?,asp.net-core-mvc,Asp.net Core Mvc,我有一个ViewComponent,我只需要调用两次!我如何以及在何处知道调用计数 目前我可以使用会话,但我不喜欢在mvc应用程序中使用会话!我怎样才能做到这一点 namespace Partials.Components { public class MyComponent : ViewComponent { public IViewComponentResult Invoke() { Session["in

我有一个
ViewComponent
,我只需要调用两次!我如何以及在何处知道调用计数

目前我可以使用会话,但我不喜欢在mvc应用程序中使用会话!我怎样才能做到这一点

 namespace Partials.Components
 {
     public class MyComponent : ViewComponent
     {
         public IViewComponentResult Invoke()
         {
             Session["invoked"]=(int)Session["invoked"]+1;
             var model = new{
                        Website="Stack Overflow",
                        Url="www.http://stackoverflow.com"
                       };
             return View("_MyComponent ", model);
         }
     }
 }
在我看来

 @Component.Invoke("MyComponent")
 <span>Invoked ViewComponent <span>@Session["invoked"]</span>  times</span>
@Component.Invoke(“MyComponent”)
调用ViewComponent@Session[“调用”]次

您可以使用TempData。它只会持续到下一个请求

TempData["invoked"]=(int)TempData["invoked"]+1;
视图:

调用ViewComponent@TempData[“调用”]次
注意:TempData在封面下使用会话。

您可以使用它,它的优点是不使用会话。这些项目根据请求存储和共享,这也符合您的目标

在viewComponent中,您可以添加/检索项目,如
this.Context.Items[“MyComponentLocationCount”]
中所示。每当计数大于2时,您可以使用
返回内容(String.empty)
返回一个空内容

您可以将其与扩展方法相结合,以便从该类外部获取计数:

[ViewComponent(Name = "MyComponent")]
public class MyViewComponent : ViewComponent
{
    internal static readonly string ContextItemName = "InvocationCount";

    public IViewComponentResult Invoke()
    {
        this.InvocationCount = this.InvocationCount + 1;
        if (this.InvocationCount > 2) return Content(String.Empty);

        //return your content here
        return Content("Can be invoked");
    }

    private int InvocationCount
    {
        get
        {
            return this.Context.InvocationCount();
        }
        set
        {
            this.Context.Items[ContextItemName] = value;
        }
    }
}

public static class MyViewComponentExtensions
{
    public static int InvocationCount(this HttpContext context)
    {
        var count = context.Items[MyViewComponent.ContextItemName];
        return count == null ? 0 : (int)count;
    }
}
然后您可以在如下视图中使用它:

@Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>@Context.InvocationCount()</span>  times</span>
然后,您将像往常一样创建视图组件,唯一的更改是添加此属性:

[PerRequestInvocationLimit(PerRequestInvocationLimit = 2)]
public class MyViewComponent : ViewComponent
{
    //implementation of view component
}
然后,我们可以创建一个定制的
IViewComponentInvoker
,用于装饰

  • 此自定义视图组件调用程序将跟踪 在当前请求中调用视图组件的次数
  • 当调用具有新属性的视图组件时,它只会 如果调用次数低于限制,则真正调用它
实现此视图组件调用程序如下所示:

public class LimitedPerRequestViewComponentInvoker : IViewComponentInvoker
{
    private readonly IViewComponentInvoker _defaultViewComponentInvoker;
    public LimitedPerRequestViewComponentInvoker(IViewComponentInvoker defaultViewComponentInvoker)
    {
        this._defaultViewComponentInvoker = defaultViewComponentInvoker;
    }

    public void Invoke(ViewComponentContext context)
    {            
        if (!CanInvokeViewComponent(context)) return;
        this._defaultViewComponentInvoker.Invoke(context);
    }

    public Task InvokeAsync(ViewComponentContext context)
    {
        if (!CanInvokeViewComponent(context)) return Task.WhenAll();
        return this._defaultViewComponentInvoker.InvokeAsync(context);
    }

    private bool CanInvokeViewComponent(ViewComponentContext context)
    {
        // 1. Increase invocation count
        var increasedCount = context.ViewContext.HttpContext.IncreaseInvocationCount(
                                                                context.ViewComponentDescriptor.ShortName);

        // 2. check if there is any limit for this viewComponent, if over the limit then return false
        var limitAttribute = context.ViewComponentDescriptor.Type
                                        .GetCustomAttributes(true)
                                        .OfType<PerRequestInvocationLimitAttribute>()
                                        .FirstOrDefault();
        if (limitAttribute != null && limitAttribute.PerRequestInvocationLimit < increasedCount)
        {
            return false;
        }

        // 3. There is no limit set or the limit has not been reached yet
        return true;
    }
}
最后一步是创建一个新的
IViewComponentInvokerFactory
,以替换,因此它将创建新的自定义视图组件调用器的实例,而不是默认的实例。您还需要在Startup.cs上注册它:

public class MyViewComponentInvokerFactory : IViewComponentInvokerFactory
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ITypeActivatorCache _typeActivatorCache;
    private readonly IViewComponentActivator _viewComponentActivator;

    public MyViewComponentInvokerFactory(IServiceProvider serviceProvider, ITypeActivatorCache typeActivatorCache, IViewComponentActivator viewComponentActivator)
    {
        _serviceProvider = serviceProvider;
        _typeActivatorCache = typeActivatorCache;
        _viewComponentActivator = viewComponentActivator;
    }

    public IViewComponentInvoker CreateInstance(ViewComponentDescriptor viewComponentDescriptor, object[] args)
    {
        return new LimitedPerRequestViewComponentInvoker(
            new DefaultViewComponentInvoker(_serviceProvider, _typeActivatorCache, _viewComponentActivator));
    }
}

//Configure the ViewComponentInvokerFactory in Startup.ConfigureServices
services.AddTransient<IViewComponentInvokerFactory, MyViewComponentInvokerFactory>();
公共类MyViewComponentInvokerFactory:IViewComponentInvokerFactory
{
私有只读服务器ViceProvider\u服务提供商;
私有只读ITypeActivatorCache\u typeActivatorCache;
私有只读IViewComponentActivator\u viewComponentActivator;
公共MyViewComponentVokerFactory(IServiceProvider服务提供程序、ITypeActivatorCache类型ActivatorCache、IViewComponentActivator或viewComponentActivator)
{
_服务提供者=服务提供者;
_typeActivatorCache=typeActivatorCache;
_viewComponentActivator=viewComponentActivator;
}
公共IViewComponentInvoker CreateInstance(ViewComponentDescriptor ViewComponentDescriptor,对象[]args)
{
返回新的LimitedPerRequestViewComponentVoker(
新的DefaultViewComponentInvoker(_serviceProvider,_typeActivatorCache,_viewComponentActivator));
}
}
//在Startup.ConfigureServices中配置ViewComponentVokerFactory
services.AddTransient();
所有这些部分就绪后,您可以使用视图组件3次,并且您将看到如何仅渲染两次:

@Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>@Context.InvocationCount("MyComponent")</span>  times</span>
@Component.Invoke(“MyComponent”)
调用ViewComponent@Context.InvocationCount(“MyComponent”)的次数
出于以下几个原因,我更喜欢此解决方案:

  • 它基于新mvc框架提供的挂钩
  • 不需要更改视图组件,只需添加设置调用限制的属性即可
  • 它在异步调用视图组件时工作

您希望每个用户或每个请求总共调用它2次吗?您试图实现的场景是什么?…您是否看到视图组件被调用的次数超过了您预期的次数?我希望每个请求调用它2次…然后您可以使用
Context.Items
,在那里添加新的数据谢谢@Daniel J.G.这很有帮助!行
返回这个.Context.InvocationCount()似乎很难理解,我终于将它改成了另一个不太特殊的东西。您可以将其重命名为
myViewComponentLocationCount
,因此它的读起来像
this.Context.myViewComponentOnLocationCount()
。如果您计划让许多视图组件使用此模式,最好对其进行一点重构,甚至开始考虑使用
IViewComponentInvoker
的装饰器,这里有一个问题,因为TempData将一直存在到下一个请求。如果刷新页面,这可能会阻止呈现组件!您是否尝试过按F5刷新页面?
public static class ViewComponentExtensions
{
    public static int InvocationCount(this HttpContext context, string viewComponentName)
    {
        var count = context.Items[GetHttpContextItemsName(viewComponentName)];
        return count == null ? 0 : (int)count;
    }

    internal static int IncreaseInvocationCount(this HttpContext context, string viewComponentName)
    {
        var count = context.InvocationCount(viewComponentName);
        context.Items[GetHttpContextItemsName(viewComponentName)] = ++count;
        return count;
    }

    private static string GetHttpContextItemsName(string viewComponentName)
    {
        return string.Format("InvocationCount-{0}", viewComponentName);
    }
}
public class MyViewComponentInvokerFactory : IViewComponentInvokerFactory
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ITypeActivatorCache _typeActivatorCache;
    private readonly IViewComponentActivator _viewComponentActivator;

    public MyViewComponentInvokerFactory(IServiceProvider serviceProvider, ITypeActivatorCache typeActivatorCache, IViewComponentActivator viewComponentActivator)
    {
        _serviceProvider = serviceProvider;
        _typeActivatorCache = typeActivatorCache;
        _viewComponentActivator = viewComponentActivator;
    }

    public IViewComponentInvoker CreateInstance(ViewComponentDescriptor viewComponentDescriptor, object[] args)
    {
        return new LimitedPerRequestViewComponentInvoker(
            new DefaultViewComponentInvoker(_serviceProvider, _typeActivatorCache, _viewComponentActivator));
    }
}

//Configure the ViewComponentInvokerFactory in Startup.ConfigureServices
services.AddTransient<IViewComponentInvokerFactory, MyViewComponentInvokerFactory>();
@Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>@Context.InvocationCount("MyComponent")</span>  times</span>