。NET Core反射-如何在ASP.NET Core 3 Razor视图中查找属性的引用?

问题描述 投票:0回答:1

我使用IViewLocalizer的localizated resources具有Razor视图:

@inject  Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer Localizer
...
@Localizer.GetString("Click here to Log in")

我正在尝试从我的预编译视图中提取所有这些字符串(以构建PO文件字典),所以我想我必须找到注入到我的视图中的IViewLocalizer的所有引用,像这样的东西:


var findAll = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic |
                                         BindingFlags.Instance | BindingFlags.Static;
var asm = Assembly.LoadFile("MySite.Web.Views.dll"));
var view = asm.GetType("AspNetCore.Views_Home_Index");
var props = view.GetProperties(findAll).Where(p=>p.PropertyType.FullName == "Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer").ToList();

// I want to find all references that use this this IViewLocalizer Localizer.get()
var getter = props.First().GetGetMethod().MetadataToken; 

// How can I do it?
var allMethods = view.GetMethods(findAll);
foreach(var method in allMethods)
{
    // How can I check my methods for usages of that property getter, and in case get the strings?
}

我尝试使用this answer中的代码,该代码使用MethodBase.GetMethodBody()。GetILAsByteArray(),但没有用-看起来方法public override Task ExecuteAsync()很短,所以看起来我的视图在其他地方渲染了。

[此外,我不确定是否应该查找getter的MetadataToken(将IViewLocalizer注入到视图中)还是应该查找实现IViewLocalizer.GetString(string)IViewLocalizer.GetString(string, params object[])的任何具体方法的用法。

PS:我知道,只要注入的本地化程序遵循某种命名标准,就可以在cshtml视图上使用Regex。如果我不知道反射解决方案,那就是计划B。

asp.net-mvc asp.net-core reflection system.reflection
1个回答
0
投票
借助于ILSpy(后来得到this answerthis one的确认,我发现

异步方法(以及迭代器类)是在代表状态机的嵌套帮助器类中生成的。这些帮助程序类可以在主要类型的NestedTypes属性中找到。

当我将所有内部类型的方法添加到搜索中时,我可以找到对我正在寻找的方法的多次调用(IViewLocalizer的获取)。

此方法有效:

var allMethods = view.GetMethods(findAll).ToList(); allMethods.AddRange( // also search in methods of nested types view.GetNestedTypes(findAll).SelectMany(x => x.GetMethods(findAll))); foreach(var method in allMethods) { var usages = ((MethodBase)method).GetMethodUsageOffsets(get); if (usages.Count() > 0) Debug.WriteLine($"{method.ReflectedType.FullName}.{method.Name}"); }

我期望在AspNetCore.Views_Home_Index3.ExecuteAsync()中找到的所有调用实际上都分布在内部类型的这些方法中:

AspNetCore.Views_Home_Index3+<ExecuteAsync>d__22.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_0>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_1>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_2>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_3>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_4>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_5>d.MoveNext AspNetCore.Views_Home_Index3+<<ExecuteAsync>b__22_6>d.MoveNext ... etc... all states from the state machine
使用Mono.Cecil变得更加容易,因为我什至不需要这个GetMethodUsageOffsets extension,因为Cecil可以轻松地解释字节码:

var module = ModuleDefinition.ReadModule(System.IO.Path.Combine(appFolder, "MyApp.Web.Views.dll")); var type = module.Types.First(x => x.Name.EndsWith("Index3")); var allInstructions = typeDefinition.Methods .Union(typeDefinition.NestedTypes.SelectMany(x => x.Methods)) .Where(m => m.HasBody) .SelectMany(x => x.Body.Instructions).ToList(); var calls = allInstructions.Where(i => i.ToString().Contains( "callvirt Microsoft.Extensions.Localization.LocalizedString Microsoft.AspNetCore.Mvc.Localization.IHtmlLocalizer::GetString(System.String)")).ToList(); foreach (var call in calls) // previous is where string parameter is loaded System.Diagnostics.Debug.WriteLine(i.Previous.ToString());

结果:

IL_020a: ldstr "More Options" IL_0241: ldstr "Add Text" IL_15c8: ldstr "Reset" IL_15ff: ldstr "Save Text Box Settings" IL_0019: ldstr "None" ...etc
© www.soinside.com 2019 - 2024. All rights reserved.