在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
我们知道在MVC5和之前的版本,两个框架的生命周期是不一样的,在新版MVC6中,MVC Controller/Web API Controller已经合二为一了,本章我们主要讲解Controller和Action的定义与使用,以及在MVC框架中,如何根据路由查询相应的Controller和Action。 Controller&Action的定义和使用 在新版MVC6框架中,依然提供了一个Controller基类,在这里除了依然提供了 其遵守如下规则: 继承于 另外还有如下几个特性需要注意:
Controller的查找机制 由上述章节,我们知道MVC6不仅支持正常的Controller(继承于Controller基类的子类),也支持POCO的Controller,本节我们就来研究一下Controller的查找原理机制。 首先,要判断一个类是否是Controller必须先确定有多少个程序集里定义了这样的类。 Microsoft.AspNet.Mvc Microsoft.AspNet.Mvc.Core Microsoft.AspNet.Mvc.ModelBinding Microsoft.AspNet.Mvc.Razor Microsoft.AspNet.Mvc.Razor.Host Microsoft.AspNet.Mvc.TagHelpers Microsoft.AspNet.Mvc.Xml Microsoft.AspNet.PageExecutionInstrumentation.Interfaces 也就是说,如果你定义了一个引用了 程序集的查找 目前有两种方式可以自定义Controller的查找机制,第一种是继承 public interface IAssemblyProvider { IEnumerable<Assembly> CandidateAssemblies { get; } } 另外一种方式,可能相对来说更简单一些,那就是使用 services.AddMvc().WithControllersAsServices(new[] { typeof(MyController).Assembly, typeof(ExternalPocoController).Assembly }); 使用上述代码后,系统将会把 程序集的筛选 确定了程序集以后,另外一个问题就来了,如何判断一个程序集是否引用了上述MVC必要条件中所列的程序集呢?答案是, var col = this.Resolver.GetRequiredService<ILibraryManager>(); var data = col.GetReferencingLibraries("Microsoft.AspNet.Mvc"); 该功能在DefaultAssemblyProvider默认实现类中的使用代码如下: protected virtual IEnumerable<ILibraryInformation> GetCandidateLibraries() { if (ReferenceAssemblies == null) { return Enumerable.Empty<ILibraryInformation>(); } // GetReferencingLibraries returns the transitive closure of referencing assemblies // for a given assembly. return ReferenceAssemblies.SelectMany(_libraryManager.GetReferencingLibraries) .Distinct() .Where(IsCandidateLibrary); } Controller的判断 确定了符合必要条件的程序集之后,就可以遍历该程序集内所有的类型,并接着判断该类型是否是Controller了。在新版的Controller判断上,实现该功能的是一个 public interface IControllerTypeProvider { IEnumerable<TypeInfo> ControllerTypes { get; } }
protected internal virtual bool IsController([NotNull] TypeInfo typeInfo, [NotNull] ISet<Assembly> candidateAssemblies) { if (!typeInfo.IsClass) // 该类型必须是一个类 { return false; } if (typeInfo.IsAbstract) // 该类必须不是抽象类 { return false; } // We only consider public top-level classes as controllers. IsPublic returns false for nested // classes, regardless of visibility modifiers if (!typeInfo.IsPublic) // 该类必须是一个Public类(并且不嵌套),嵌套类不能作为Controller { return false; } if (typeInfo.ContainsGenericParameters) // 该类不能是泛型类 { return false; } if (!typeInfo.Name.EndsWith(ControllerTypeName, StringComparison.OrdinalIgnoreCase) && !DerivesFromController(typeInfo, candidateAssemblies)) // 该类以Controller结尾,或继承于Controller基类,或其父类也是Controller。 { return false; } if (typeInfo.IsDefined(typeof(NonControllerAttribute))) // 该类不能设置NonControllerAttribute特性 { return false; } return true; } 你也可以自己实现 services.AddMvc().WithControllersAsServices(new[] { typeof(MyController), typeof(ExternalPocoController) }); 使用上述代码后,系统将会把 Action的查找机制 Action的选择则是通过 public Task<ActionDescriptor> SelectAsync([NotNull] RouteContext context) { // ... } 还有一个地方会判断一个方法是否是Action,那就是 public IEnumerable<ActionModel> BuildActionModels([NotNull] TypeInfo typeInfo, [NotNull] MethodInfo methodInfo) { if (!IsAction(typeInfo, methodInfo)) { return Enumerable.Empty<ActionModel>(); } // ....省略其它代码 } 该实现方法,通过一个内部的 protected virtual bool IsAction([NotNull] TypeInfo typeInfo, [NotNull] MethodInfo methodInfo) { // The SpecialName bit is set to flag members that are treated in a special way by some compilers // (such as property accessors and operator overloading methods). if (methodInfo.IsSpecialName) // 不能是特殊名称(如重载的操作符或属性访问器) { return false; } if (methodInfo.IsDefined(typeof(NonActionAttribute))) // 不能声明NonActionAttribute特性 { return false; } // Overriden methods from Object class, e.g. Equals(Object), GetHashCode(), etc., are not valid. if (methodInfo.GetBaseDefinition().DeclaringType == typeof(object)) //不能是重载的方法,比如Equals和GetHashCode { return false; } // Dispose method implemented from IDisposable is not valid if (IsIDisposableMethod(methodInfo, typeInfo)) // 不能是Dispose方法 { return false; } if (methodInfo.IsStatic) // 不能是静态方法 { return false; } if (methodInfo.IsAbstract) // 不能是抽象方法 { return false; } if (methodInfo.IsConstructor) // 不能是构造函数 { return false; } if (methodInfo.IsGenericMethod) // 不能是泛型方法 { return false; } return methodInfo.IsPublic; // 必须是Public方法 } 以上内容就是关于Controller和Action查找相关的重要代码,详细原理步骤,请参考 |
请发表评论