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框架提供的挂钩
- 不需要更改视图组件,只需添加设置调用限制的属性即可
- 它在异步调用视图组件时工作
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>