C# 在C中获取所有控制器和操作名称#

C# 在C中获取所有控制器和操作名称#,c#,asp.net-mvc,asp.net-mvc-controller,C#,Asp.net Mvc,Asp.net Mvc Controller,是否可以以编程方式列出所有控制器的名称及其操作 我想为每个控制器和操作实现数据库驱动的安全性。作为一名开发人员,我知道所有的控制器和操作,可以将它们添加到数据库表中,但是有没有办法自动添加它们 使用,枚举程序集中的所有类型,并筛选从System.Web.MVC.Controller继承的类,然后将此类型的公共方法列为操作您可以使用反射查找当前程序集中的所有控制器,然后查找未使用NonAction属性修饰的公共方法 Assembly asm = Assembly.GetExecutingAssem

是否可以以编程方式列出所有控制器的名称及其操作


我想为每个控制器和操作实现数据库驱动的安全性。作为一名开发人员,我知道所有的控制器和操作,可以将它们添加到数据库表中,但是有没有办法自动添加它们

使用,枚举程序集中的所有类型,并筛选从
System.Web.MVC.Controller继承的类,然后将此类型的公共方法列为操作

您可以使用反射查找当前程序集中的所有控制器,然后查找未使用
NonAction
属性修饰的公共方法

Assembly asm = Assembly.GetExecutingAssembly();

asm.GetTypes()
    .Where(type=> typeof(Controller).IsAssignableFrom(type)) //filter controllers
    .SelectMany(type => type.GetMethods())
    .Where(method => method.IsPublic && ! method.IsDefined(typeof(NonActionAttribute)));

或者,删减@dcastro的想法,只需获得控制器:

Assembly.GetExecutingAssembly()
.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))

以下内容将提取控制器、动作、属性和返回类型:

Assembly asm = Assembly.GetAssembly(typeof(MyWebDll.MvcApplication));

var controlleractionlist = asm.GetTypes()
        .Where(type=> typeof(System.Web.Mvc.Controller).IsAssignableFrom(type))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof( System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x => new {Controller = x.DeclaringType.Name, Action = x.Name, ReturnType = x.ReturnType.Name, Attributes = String.Join(",", x.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute",""))) })
        .OrderBy(x=>x.Controller).ThenBy(x => x.Action).ToList();
例如,如果在linqpad中运行此代码并调用

controlleractionlist.Dump();
您将获得以下输出:

Assembly assembly = Assembly.LoadFrom(sAssemblyFileName)
IEnumerable<Type> types = assembly.GetTypes().Where(type => typeof(Controller).IsAssignableFrom(type)).OrderBy(x => x.Name);
foreach (Type cls in types)
{
      list.Add(cls.Name.Replace("Controller", ""));
      IEnumerable<MemberInfo> memberInfo = cls.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any()).OrderBy(x => x.Name);
      foreach (MemberInfo method in memberInfo)
      {
           if (method.ReflectedType.IsPublic && !method.IsDefined(typeof(NonActionAttribute)))
           {
                  list.Add("\t" + method.Name.ToString());
           }
      }
}

Assembly Assembly=Assembly.LoadFrom(sAssemblyFileName)
IEnumerable types=assembly.GetTypes().Where(type=>typeof(Controller).IsAssignableFrom(type)).OrderBy(x=>x.Name);
foreach(类型中的类型cls)
{
列表.添加(cls.Name.Replace(“Controller”和“));
IEnumerable memberInfo=cls.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)。其中(m=>!m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute),true)。Any()).OrderBy(x=>x.Name);
foreach(MemberInfo中的MemberInfo方法)
{
如果(method.ReflectedType.IsPublic&&!method.IsDefined(typeof(NonActionAttribute)))
{
list.Add(“\t”+method.Name.ToString());
}
}
}

我一直在寻找一种获取区域、控制器和动作的方法,为此我设法对您在此处发布的方法进行了一些更改,因此,如果有人正在寻找一种获取区域的方法,请看我的丑陋方法(我将其保存为xml):

编辑:

//assuming that the namespace is ProjectName.Areas.Admin.Controllers

 Area=n.DeclaringType.Namespace.Split('.').Reverse().Skip(1).First()

@迪卡斯特罗的回答很好。我添加这个过滤器是为了只返回开发人员声明的公共操作

        var asm = Assembly.GetExecutingAssembly();
        var methods = asm.GetTypes()
            .Where(type => typeof(Controller)
                .IsAssignableFrom(type))
            .SelectMany(type => type.GetMethods())
            .Where(method => method.IsPublic 
                && !method.IsDefined(typeof(NonActionAttribute))
                && (
                    method.ReturnType==typeof(ActionResult) ||
                    method.ReturnType == typeof(Task<ActionResult>) ||
                    method.ReturnType == typeof(String) ||
                    //method.ReturnType == typeof(IHttpResult) ||
                    )
                )
            .Select(m=>m.Name);
var asm=Assembly.getExecutionGassembly();
var methods=asm.GetTypes()
.Where(type=>typeof(Controller)
.IsAssignableFrom(类型))
.SelectMany(type=>type.GetMethods())
.Where(method=>method.IsPublic
&&!method.IsDefined(typeof(NonActionAttribute))
&& (
method.ReturnType==typeof(ActionResult)||
method.ReturnType==typeof(任务)||
method.ReturnType==typeof(字符串)||
//method.ReturnType==typeof(IHttpResult)||
)
)
.选择(m=>m.Name);

如果它对任何人都有帮助的话,我改进了@AVH,以使用递归性获取更多信息。
我的目标是创建一个自动生成的API帮助页面:

 Assembly.GetAssembly(typeof(MyBaseApiController)).GetTypes()
        .Where(type => type.IsSubclassOf(typeof(MyBaseApiController)))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x => new ApiHelpEndpointViewModel
        {
            Endpoint = x.DeclaringType.Name.Replace("Controller", String.Empty),
            Controller = x.DeclaringType.Name,
            Action = x.Name,
            DisplayableName = x.GetCustomAttributes<DisplayAttribute>().FirstOrDefault()?.Name ?? x.Name,
            Description = x.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault()?.Description ?? String.Empty,
            Properties = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties(),
            PropertyDescription = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties()
                                        .Select(q => q.CustomAttributes.SingleOrDefault(a => a.AttributeType.Name == "DescriptionAttribute")?.ConstructorArguments ?? new List<CustomAttributeTypedArgument>() )
                                        .ToList()
        })
        .OrderBy(x => x.Controller)
        .ThenBy(x => x.Action)
        .ToList()
        .ForEach(x => apiHelpViewModel.Endpoints.Add(x)); //See comment below
当我的端点返回
IQueryable
时,最后一个属性(
PropertyDescription
)包含大量与
CustomType
属性相关的元数据。因此,您可以获得名称、类型、说明(添加了
[description]
注释)等。。。每个
CustomType的
属性

原来的问题更进一步,但如果它能帮助某人


更新

更进一步,如果您想在无法修改的字段上添加一些
[DataAnnotation]
(因为它们是由模板生成的),您可以创建一个类:

小心
MyClass
必须是:

  • 一个偏类
  • 与生成的
    MyClass
然后,更新检索元数据的代码:

Assembly.GetAssembly(typeof(MyBaseController)).GetTypes()
        .Where(type => type.IsSubclassOf(typeof(MyBaseController)))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x =>
        {
            var type = x.ReturnType.GenericTypeArguments.FirstOrDefault();
            var metadataType = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true)
                .OfType<MetadataTypeAttribute>().FirstOrDefault();
            var metaData = (metadataType != null)
                ? ModelMetadataProviders.Current.GetMetadataForType(null, metadataType.MetadataClassType)
                : ModelMetadataProviders.Current.GetMetadataForType(null, type);

            return new ApiHelpEndpoint
            {
                Endpoint = x.DeclaringType.Name.Replace("Controller", String.Empty),
                Controller = x.DeclaringType.Name,
                Action = x.Name,
                DisplayableName = x.GetCustomAttributes<DisplayAttribute>().FirstOrDefault()?.Name ?? x.Name,
                Description = x.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault()?.Description ?? String.Empty,
                Properties = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties(),
                PropertyDescription = metaData.Properties.Select(e =>
                {
                    var m = metaData.ModelType.GetProperty(e.PropertyName)
                        .GetCustomAttributes(typeof(DescriptionAttribute), true)
                        .FirstOrDefault();
                    return m != null ? ((DescriptionAttribute)m).Description : string.Empty;
                }).ToList()
            };
        })
        .OrderBy(x => x.Controller)
        .ThenBy(x => x.Action)
        .ToList()
        .ForEach(x => api2HelpViewModel.Endpoints.Add(x));
Assembly.GetAssembly(typeof(MyBaseController)).GetTypes()
.Where(type=>type.IsSubclassOf(typeof(MyBaseController)))
.SelectMany(type=>type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
.Where(m=>!m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute),true)。Any()
.选择(x=>
{
var type=x.ReturnType.GenericTypeArguments.FirstOrDefault();
var metadataType=type.GetCustomAttributes(typeof(MetadataTypeAttribute),true)
.OfType().FirstOrDefault();
变量元数据=(元数据类型!=null)
?ModelMetadataProviders.Current.GetMetadataForType(null,metadataType.MetadataClassType)
:modelmataproviders.Current.GetMetadataForType(null,type);
返回新的ApiHelpEndpoint
{
Endpoint=x.DeclaringType.Name.Replace(“控制器”,String.Empty),
控制器=x.DeclaringType.Name,
Action=x.Name,
DisplayableName=x.GetCustomAttributes().FirstOrDefault()?.Name??x.Name,
Description=x.GetCustomAttributes().FirstOrDefault()?.Description??String.Empty,
Properties=x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties(),
PropertyDescription=metaData.Properties.Select(e=>
{
var m=metaData.ModelType.GetProperty(e.PropertyName)
.GetCustomAttributes(typeof(DescriptionAttribute),true)
.FirstOrDefault();
返回m!=null(?(DescriptionAttribute)m).Description:string.Empty;
})托利斯先生()
};
})
.OrderBy(x=>x.Controller)
.ThenBy(x=>x.Action)
托利斯先生()
.ForEach(x=>api2HelpViewModel.Endpoints.Add(x));
(归功于)

并将
PropertyDescription
更新为
公共列表PropertyDescription{get;set;
 Assembly.GetAssembly(typeof(MyBaseApiController)).GetTypes()
        .Where(type => type.IsSubclassOf(typeof(MyBaseApiController)))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x => new ApiHelpEndpointViewModel
        {
            Endpoint = x.DeclaringType.Name.Replace("Controller", String.Empty),
            Controller = x.DeclaringType.Name,
            Action = x.Name,
            DisplayableName = x.GetCustomAttributes<DisplayAttribute>().FirstOrDefault()?.Name ?? x.Name,
            Description = x.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault()?.Description ?? String.Empty,
            Properties = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties(),
            PropertyDescription = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties()
                                        .Select(q => q.CustomAttributes.SingleOrDefault(a => a.AttributeType.Name == "DescriptionAttribute")?.ConstructorArguments ?? new List<CustomAttributeTypedArgument>() )
                                        .ToList()
        })
        .OrderBy(x => x.Controller)
        .ThenBy(x => x.Action)
        .ToList()
        .ForEach(x => apiHelpViewModel.Endpoints.Add(x)); //See comment below
public class ApiHelpEndpointViewModel
{
    public string Endpoint { get; set; }
    public string Controller { get; set; }
    public string Action { get; set; }
    public string DisplayableName { get; set; }
    public string Description { get; set; }
    public string EndpointRoute => $"/api/{Endpoint}";
    public PropertyInfo[] Properties { get; set; }
    public List<IList<CustomAttributeTypedArgument>> PropertyDescription { get; set; }
}
[MetadataType(typeof(MetadataAttributesMyClass))]
public partial class MyClass
{
}

public class MetadataAttributesMyClass
{
    [Description("My custom description")]
    public int Id {get; set;}

    //all your generated fields with [Description] or other data annotation
}
Assembly.GetAssembly(typeof(MyBaseController)).GetTypes()
        .Where(type => type.IsSubclassOf(typeof(MyBaseController)))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
        .Select(x =>
        {
            var type = x.ReturnType.GenericTypeArguments.FirstOrDefault();
            var metadataType = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true)
                .OfType<MetadataTypeAttribute>().FirstOrDefault();
            var metaData = (metadataType != null)
                ? ModelMetadataProviders.Current.GetMetadataForType(null, metadataType.MetadataClassType)
                : ModelMetadataProviders.Current.GetMetadataForType(null, type);

            return new ApiHelpEndpoint
            {
                Endpoint = x.DeclaringType.Name.Replace("Controller", String.Empty),
                Controller = x.DeclaringType.Name,
                Action = x.Name,
                DisplayableName = x.GetCustomAttributes<DisplayAttribute>().FirstOrDefault()?.Name ?? x.Name,
                Description = x.GetCustomAttributes<DescriptionAttribute>().FirstOrDefault()?.Description ?? String.Empty,
                Properties = x.ReturnType.GenericTypeArguments.FirstOrDefault()?.GetProperties(),
                PropertyDescription = metaData.Properties.Select(e =>
                {
                    var m = metaData.ModelType.GetProperty(e.PropertyName)
                        .GetCustomAttributes(typeof(DescriptionAttribute), true)
                        .FirstOrDefault();
                    return m != null ? ((DescriptionAttribute)m).Description : string.Empty;
                }).ToList()
            };
        })
        .OrderBy(x => x.Controller)
        .ThenBy(x => x.Action)
        .ToList()
        .ForEach(x => api2HelpViewModel.Endpoints.Add(x));