Ife*_*kwu 32 razor asp.net-core-mvc asp.net-core
到目前为止,我认为不ViewComponent
解决这两个问题TagHelper
.这有什么替代品吗?需要参数并返回的东西HtmlString
?
我没有看到任何有害的东西:
@helper foo(string something) {
<div>Say @something</div>
}
var emailbody = classfilenameinAppCodefolder.foo("hello"); //store result in a variable for further processes
Run Code Online (Sandbox Code Playgroud)
现在我相信它在RC之前暂时删除.https://github.com/aspnet/Razor/issues/281和https://github.com/aspnet/Mvc/issues/1130嗯!它更好.我希望有人正在努力.没有@helper
,建立大型HtmlString
或"模板"将是一个严重的痛苦.
注意:部分视图似乎没有成功.我认为它只会渲染视图而不是返回视图变量.
其次,App_Code文件夹发生了什么?
Gar*_*ton 18
根据以下 Github 问题,看起来@helper 回来了,并将包含在 asp .net core 3.0.0 preview 4 中。
https://github.com/aspnet/AspNetCore/issues/5110
更新
从 asp .net core 3 开始,您现在可以在 Razor 代码块中定义本地函数。
@{
void RenderName(string name)
{
<p>Name: <strong>@name</strong></p>
}
RenderName("Mahatma Gandhi");
RenderName("Martin Luther King, Jr.");
}
Run Code Online (Sandbox Code Playgroud)
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.1#razor-code-blocks
或者,您可以像这样使用@functions 指令:
@{
RenderName("Mahatma Gandhi");
RenderName("Martin Luther King, Jr.");
}
@functions {
private void RenderName(string name)
{
<p>Name: <strong>@name</strong></p>
}
}
Run Code Online (Sandbox Code Playgroud)
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.1#functions
小智 15
@{
Func<String, IHtmlContent> foo = @<div>Say @item</div>;
}
Run Code Online (Sandbox Code Playgroud)
Ada*_*mon 10
正如@scott在他的回答中指出的那样,从 .NET Core 3 开始,本地函数终于可用。在之前的版本中,人们可以诉诸模板化的 Razor 委托。
但所有答案都没有解决“App_Code 文件夹发生了什么?”这个问题。上述功能是局部解决方案,即以这些方式定义的辅助函数不能在多个视图之间共享。但全局辅助函数通常比 MS 为视图相关代码重用提供的开箱即用的解决方案更方便。(标签助手、部分视图、视图组件都有其缺点。)这在本期和本期GitHub 中进行了深入讨论。不幸的是,根据这些讨论,微软方面并没有太多的了解,因此对于很快添加该功能(如果有的话)的希望不大。
然而,在深入研究框架源代码之后,我认为我可以找到一个可行的解决方案来解决这个问题。
核心思想是我们可以利用 Razor 视图引擎为我们查找任意视图:例如,定义了我们想要全局使用的一些局部函数的部分视图。一旦我们设法获得对该视图的引用,就没有什么可以阻止我们调用它的公共方法。
下面的类GlobalRazorHelpersFactory
封装了这个想法:
public interface IGlobalRazorHelpersFactory
{
dynamic Create(string helpersViewPath, ViewContext viewContext);
THelpers Create<THelpers>(ViewContext viewContext) where THelpers : class;
}
public class GlobalRazorHelpersOptions
{
public Dictionary<Type, string> HelpersTypeViewPathMappings { get; } = new Dictionary<Type, string>();
}
public sealed class GlobalRazorHelpersFactory : IGlobalRazorHelpersFactory
{
private readonly ICompositeViewEngine _viewEngine;
private readonly IRazorPageActivator _razorPageActivator;
private readonly ConcurrentDictionary<Type, string> _helpersTypeViewPathMappings;
public GlobalRazorHelpersFactory(ICompositeViewEngine viewEngine, IRazorPageActivator razorPageActivator, IOptions<GlobalRazorHelpersOptions>? options)
{
_viewEngine = viewEngine ?? throw new ArgumentNullException(nameof(viewEngine));
_razorPageActivator = razorPageActivator ?? throw new ArgumentNullException(nameof(razorPageActivator));
var optionsValue = options?.Value;
_helpersTypeViewPathMappings = new ConcurrentDictionary<Type, string>(optionsValue?.HelpersTypeViewPathMappings ?? Enumerable.Empty<KeyValuePair<Type, string>>());
}
public IRazorPage CreateRazorPage(string helpersViewPath, ViewContext viewContext)
{
var viewEngineResult = _viewEngine.GetView(viewContext.ExecutingFilePath, helpersViewPath, isMainPage: false);
var originalLocations = viewEngineResult.SearchedLocations;
if (!viewEngineResult.Success)
viewEngineResult = _viewEngine.FindView(viewContext, helpersViewPath, isMainPage: false);
if (!viewEngineResult.Success)
{
var locations = string.Empty;
if (originalLocations.Any())
locations = Environment.NewLine + string.Join(Environment.NewLine, originalLocations);
if (viewEngineResult.SearchedLocations.Any())
locations += Environment.NewLine + string.Join(Environment.NewLine, viewEngineResult.SearchedLocations);
throw new InvalidOperationException($"The Razor helpers view '{helpersViewPath}' was not found. The following locations were searched:{locations}");
}
var razorPage = ((RazorView)viewEngineResult.View).RazorPage;
razorPage.ViewContext = viewContext;
// we need to save and restore the original view data dictionary as it is changed by IRazorPageActivator.Activate
// https://github.com/dotnet/aspnetcore/blob/v3.1.6/src/Mvc/Mvc.Razor/src/RazorPagePropertyActivator.cs#L59
var originalViewData = viewContext.ViewData;
try { _razorPageActivator.Activate(razorPage, viewContext); }
finally { viewContext.ViewData = originalViewData; }
return razorPage;
}
public dynamic Create(string helpersViewPath, ViewContext viewContext) => CreateRazorPage(helpersViewPath, viewContext);
public THelpers Create<THelpers>(ViewContext viewContext) where THelpers : class
{
var helpersViewPath = _helpersTypeViewPathMappings.GetOrAdd(typeof(THelpers), type => "_" + (type.Name.StartsWith("I", StringComparison.Ordinal) ? type.Name.Substring(1) : type.Name));
return (THelpers)CreateRazorPage(helpersViewPath, viewContext);
}
}
Run Code Online (Sandbox Code Playgroud)
将单例IGlobalRazorHelpersFactory
服务引入 DI 后,我们可以将其注入视图中并调用该Create
方法来获取包含辅助函数的视图实例。
通过在辅助视图中使用@implements
指令,我们甚至可以获得类型安全的访问:
@inherits Microsoft.AspNetCore.Mvc.Razor.RazorPage
@implements IMyGlobalHelpers
@functions {
public void MyAwesomeGlobalFunction(string someParam)
{
<div>@someParam</div>
}
}
Run Code Online (Sandbox Code Playgroud)
GlobalRazorHelpersOptions
(可以通过以普通方式配置- by services.Configure<GlobalRazorHelpersOptions>(o => ...)
- 来显式定义接口类型来查看路径映射,但通常我们可以简单地依赖实现的命名约定:在接口的情况下IMyGlobalHelpers
,它将查找名为的视图_MyGlobalHelpers.cshtml
在常规位置。最好将其放入/Views/Shared
。)
到目前为止还不错,但我们可以做得更好!如果我们可以直接在消费者视图中注入辅助实例,那就方便多了。IOptions<T>
我们可以使用//HtmlLocalizer<T>
背后的想法轻松实现这一点ViewLocalizer
:
public interface IGlobalRazorHelpers<out THelpers> : IViewContextAware
where THelpers : class
{
THelpers Instance { get; }
}
public sealed class GlobalRazorHelpers<THelpers> : IGlobalRazorHelpers<THelpers>
where THelpers : class
{
private readonly IGlobalRazorHelpersFactory _razorHelpersFactory;
public GlobalRazorHelpers(IGlobalRazorHelpersFactory razorHelpersFactory)
{
_razorHelpersFactory = razorHelpersFactory ?? throw new ArgumentNullException(nameof(razorHelpersFactory));
}
private THelpers? _instance;
public THelpers Instance => _instance ?? throw new InvalidOperationException("The service was not contextualized.");
public void Contextualize(ViewContext viewContext) => _instance = _razorHelpersFactory.Create<THelpers>(viewContext);
}
Run Code Online (Sandbox Code Playgroud)
现在我们必须在以下位置注册我们的服务Startup.ConfigureServices
:
services.AddSingleton<IGlobalRazorHelpersFactory, GlobalRazorHelpersFactory>();
services.AddTransient(typeof(IGlobalRazorHelpers<>), typeof(GlobalRazorHelpers<>));
Run Code Online (Sandbox Code Playgroud)
最后,我们准备在视图中使用全局 Razor 函数:
@inject IGlobalRazorHelpers<IMyGlobalHelpers> MyGlobalHelpers;
@{ MyGlobalHelpers.Instance.MyAwesomeGlobalFunction("Here we go!"); }
Run Code Online (Sandbox Code Playgroud)
这比原始的 App_Code + 静态方法功能稍微复杂一些,但我认为这是我们能得到的最接近的。根据我的测试,该解决方案在启用运行时编译的情况下也能很好地工作。到目前为止,我还没有时间进行基准测试,但从理论上讲,它通常应该比使用部分视图更快,因为每个消费者视图仅查找共享视图一次,之后它只是简单的方法调用。但我不确定标签助手。做一些基准测试来比较它们会很有趣。但我把这件事留给了采用者。
(在 .NET Core 3.1 上测试。)
更新
您可以在我的 ASP.NET 样板项目中找到此概念的工作演示:
基础设施(相关文件仅是名称包含GlobalRazorHelpers 的文件)
我想扩展@Alexaku的答案并展示我是如何实现一个类似函数的帮助器.它仅在一个特定页面上有用,但它允许您使用输入参数多次执行一段剃刀代码.语法不是很好,但我发现它在没有razor的@helper函数时非常有用.首先声明某种Dto,它将包含输入参数到函数中.
@functions {
private class Dto
{
public string Data { get;set; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后声明剃刀功能.请注意,displayItem值可以是多行的,并且还要注意您使用@item访问Dto变量.
@{
Func<Dto, IHtmlContent> displayItem = @<span>@item.Data</span>;
}
Run Code Online (Sandbox Code Playgroud)
然后,当您想要使用剃刀模板时,您可以从页面中的任何位置调用它,如下所示.
<div>
@displayItem(new Dto {Data = "testingData1" });
</div>
<div>
@displayItem(new Dto {Data = "testingData2" });
</div>
Run Code Online (Sandbox Code Playgroud)
小智 8
对于 .NET Core 3,您可以使用本地函数:
@{
void RenderName(string name)
{
<p>Name: <strong>@name</strong></p>
}
RenderName("Mahatma Gandhi");
RenderName("Martin Luther King, Jr.");
}
Run Code Online (Sandbox Code Playgroud)
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.1#razor-code-blocks
该@helper
指令已被删除,因为它不完整,并且其当前设计不适合新的“ASP.NET 5 方式”。原因之一是助手应该在App_Code
文件夹中声明,而 ASP.NET 5没有特殊文件夹的概念。因此团队决定暂时删除该功能。
归档时间: |
|
查看次数: |
10113 次 |
最近记录: |