迭代ASP.NET MVC视图以查找支持特定模型类型的所有视图

本文关键字:视图 类型 模型 支持 NET ASP MVC 查找 迭代 | 更新日期: 2023-09-27 18:28:34

我想获得一个支持呈现特定模型类型的所有视图的列表。

伪代码:

IEnumerable GetViewsByModelType(Type modelType)
{
   foreach (var view in SomeWayToGetAllViews())
   {
      if (typeof(view.ModelType).IsAssignableFrom(modelType))
      {
         yield return view; // This view supports the specified model type
      }
   }
}

换句话说,假设我有一个MyClass模型,我想找到所有支持渲染它的视图。例如,@model类型为MyClass或其继承链中的类型的所有视图。

迭代ASP.NET MVC视图以查找支持特定模型类型的所有视图

根据我的发现,汇编的视图不包括在程序集中,所以这不会是在公园里散步。

在我看来,最好的办法是列出.cshtml剃刀视图,然后使用BuildManager类编译类型,这将允许您获得Model属性类型。

以下是查找所有@Model类型为LoginViewModel:的Razor视图的示例

var dir = Directory.GetFiles(string.Format("{0}/Views", HostingEnvironment.ApplicationPhysicalPath), 
    "*.cshtml", SearchOption.AllDirectories);
foreach (var file in dir)
{
    var relativePath = file.Replace(HostingEnvironment.ApplicationPhysicalPath, String.Empty);
    Type type = BuildManager.GetCompiledType(relativePath);
    var modelProperty = type.GetProperties().FirstOrDefault(p => p.Name == "Model");
    if (modelProperty != null && modelProperty.PropertyType == typeof(LoginViewModel))
    {
        // You got the correct type
    }
}

根据@Faris Zacina的回答,我想出了这个代码:

string[] GetViews<TModel>(string virtualPath)
{
    var physicalPath = HostingEnvironment.MapPath(virtualPath);
    
    return Directory
        .GetFiles(physicalPath, "*.cshtml", SearchOption.TopDirectoryOnly)
        .Select(viewPath => virtualPath + "/" + Path.GetFileName(viewPath))
        .Where(virtualViewPath => BuildManager.GetCompiledType(virtualViewPath).GetProperty("Model", typeof(TModel)) != null)
        .ToArray();
}

通过IO操作查找视图仅在开发过程中有效,因为它们在发布后不作为物理文件存在(毕竟会得到DLL)。如果需要在运行时获取视图,则需要从ApplicationPartManager服务解析ViewsFeature

    using Microsoft.AspNetCore.Mvc.ApplicationParts;
    using Microsoft.AspNetCore.Mvc.Razor.Compilation;
    
    public class MyService
    {
        private readonly ApplicationPartManager _applicationPartManager;
        public MyService(ApplicationPartManager applicationPartManager)
        {
            _applicationPartManager = applicationPartManager;
        }
        public IList<CompiledViewDescriptor> GetAllViews()
        {
            var viewsFeature = new ViewsFeature();
            _applicationPartManager.PopulateFeature(viewsFeature);
            return viewsFeature.ViewDescriptors;
        }
    }