欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

asp.net mvc-Controllerl篇 ControllerDescriptor

程序员文章站 2024-03-05 12:55:18
现在我们首先来看看actioninvoker属性的定义吧: 复制代码 代码如下: public iactioninvoker actioninvoker { get { i...
现在我们首先来看看actioninvoker属性的定义吧:
复制代码 代码如下:

public iactioninvoker actioninvoker {
get {
if (_actioninvoker == null) {
_actioninvoker = createactioninvoker();
}
return _actioninvoker;
}
set {
_actioninvoker = value;
}
}
protected virtual iactioninvoker createactioninvoker() {
return new controlleractioninvoker();
}

和tempdataprovider属性定义一样,大家一定要习惯这些代码啊。
而controlleractioninvoker的定义也很简单,但是这个类却不简单啊。
让我们来看看你invokeaction的定义吧:
复制代码 代码如下:

public virtual bool invokeaction(controllercontext controllercontext, string actionname) {
if (controllercontext == null) {
throw new argumentnullexception("controllercontext");
}
if (string.isnullorempty(actionname)) {
throw new argumentexception(mvcresources.common_nullorempty, "actionname");
}

controllerdescriptor controllerdescriptor = getcontrollerdescriptor(controllercontext);
actiondescriptor actiondescriptor = findaction(controllercontext, controllerdescriptor, actionname);
if (actiondescriptor != null) {
filterinfo filterinfo = getfilters(controllercontext, actiondescriptor);

try {
authorizationcontext authcontext = invokeauthorizationfilters(controllercontext, filterinfo.authorizationfilters, actiondescriptor);
if (authcontext.result != null) {
// the auth filter signaled that we should let it short-circuit the request
invokeactionresult(controllercontext, authcontext.result);
}
else {
if (controllercontext.controller.validaterequest) {
validaterequest(controllercontext);
}

idictionary<string, object> parameters = getparametervalues(controllercontext, actiondescriptor);
actionexecutedcontext postactioncontext = invokeactionmethodwithfilters(controllercontext, filterinfo.actionfilters, actiondescriptor, parameters);
invokeactionresultwithfilters(controllercontext, filterinfo.resultfilters, postactioncontext.result);
}
}
catch (threadabortexception) {
// this type of exception occurs as a result of response.redirect(), but we special-case so that
// the filters don't see this as an error.
throw;
}
catch (exception ex) {
// something blew up, so execute the exception filters
exceptioncontext exceptioncontext = invokeexceptionfilters(controllercontext, filterinfo.exceptionfilters, ex);
if (!exceptioncontext.exceptionhandled) {
throw;
}
invokeactionresult(controllercontext, exceptioncontext.result);
}

return true;
}

// notify controller that no method matched
return false;
}

这个方法里面的内容不可能一次讲完的,我们看看 controllerdescriptor controllerdescriptor = getcontrollerdescriptor(controllercontext);
很明显controllerdescriptor是controller实例的一个包装类。
复制代码 代码如下:

protected virtual controllerdescriptor getcontrollerdescriptor(controllercontext controllercontext) {
type controllertype = controllercontext.controller.gettype();
controllerdescriptor controllerdescriptor = descriptorcache.getdescriptor(controllertype, () => new reflectedcontrollerdescriptor(controllertype));
return controllerdescriptor;
}

从这个方法中,我们可以知道实际返回的是一个reflectedcontrollerdescriptor实例,它是controllerdescriptor的子类,descriptorcache.getdescriptor(...)好像是从缓存中获取的啊,让我们证实一下吧,先来看看controllerdescriptorcache的getdescriptor方法:
复制代码 代码如下:

internal sealed class controllerdescriptorcache : readerwritercache<type, controllerdescriptor> {
public controllerdescriptor getdescriptor(type controllertype, func<controllerdescriptor> creator) {
return fetchorcreateitem(controllertype, creator);
}
}

fetchorcreateitem方法很简单,从缓存中获取controllerdescriptor ,如果没有就创建并加入缓存然后在返回,缓存实现方式其实就是一个字典dictionary<tkey, tvalue>。
现在看看reflectedcontrollerdescriptor的够着函数是否有什么特别之处:
_controllertype = controllertype;
_selector = new actionmethodselector(_controllertype);
怎么又有actionmethodselector这个东东啊,其构造函数如下
复制代码 代码如下:

public actionmethodselector(type controllertype) {
controllertype = controllertype;
populatelookuptables();
}
private void populatelookuptables() {
methodinfo[] allmethods = controllertype.getmethods(bindingflags.invokemethod | bindingflags.instance | bindingflags.public);
methodinfo[] actionmethods = array.findall(allmethods, isvalidactionmethod);
aliasedmethods = array.findall(actionmethods, ismethoddecoratedwithaliasingattribute);
nonaliasedmethods = actionmethods.except(aliasedmethods).tolookup(method => method.name, stringcomparer.ordinalignorecase);
}

这个方法很简单,找出controllertype的所有实例、共有方法,然后在过滤调不是action的,最后吧这些action方法分成两部分,一部分有别名,一部分没有别名。
现在我们已经得到了controllerdescriptor实例,下面应该来看看actiondescriptor actiondescriptor = findaction(controllercontext, controllerdescriptor, actionname);这句代码了;同样我们可以确认actiondescriptor实际上一个action的包装类。
protected virtual actiondescriptor findaction(controllercontext controllercontext, controllerdescriptor controllerdescriptor, string actionname)这个方法实际上就是调用
controllerdescriptor类findaction方法,让我们看看你reflectedcontrollerdescriptor的findaction方法,该方法很简单,组要就2句代码:
复制代码 代码如下:

methodinfo matched = _selector.findactionmethod(controllercontext, actionname);
return new reflectedactiondescriptor(matched, actionname, this);

_selector.findactionmethod(controllercontext, actionname); 这句就是找到我们需要action对应的methodinfo。
复制代码 代码如下:

public methodinfo findactionmethod(controllercontext controllercontext, string actionname) {
list<methodinfo> methodsmatchingname = getmatchingaliasedmethods(controllercontext, actionname);
methodsmatchingname.addrange(nonaliasedmethods[actionname]);
list<methodinfo> finalmethods = runselectionfilters(controllercontext, methodsmatchingname);

switch (finalmethods.count) {
case 0:
return null;

case 1:
return finalmethods[0];

default:
throw createambiguousmatchexception(finalmethods, actionname);
}
}

循环每个methodinfo,查找它们的自定义的actionmethodselectorattribute特性,如果有只返回验证通过的特性。看到reflectedattributecache.getactionmethodselectorattributes(methodinfo)这样的代码感觉由于缓存有关,
复制代码 代码如下:

private static readonlycollection<tattribute> getattributes<tmemberinfo, tattribute>(concurrentdictionary<tmemberinfo, readonlycollection<tattribute>> lookup, tmemberinfo memberinfo)
where tattribute : attribute
where tmemberinfo : memberinfo {
return lookup.getoradd(memberinfo, mi => new readonlycollection<tattribute>((tattribute[])memberinfo.getcustomattributes(typeof(tattribute), inherit: true)));
}

reflectedattributecache这个类有几个缓存字典:
concurrentdictionary<methodinfo, readonlycollection<actionmethodselectorattribute>>
concurrentdictionary<methodinfo, readonlycollection<actionnameselectorattribute>>
concurrentdictionary<methodinfo, readonlycollection<filterattribute>>
concurrentdictionary<type, readonlycollection<filterattribute>>
默认实现actionmethodselectorattribute类主要有以下几个
acceptverbsattribute
httpdeleteattribute
httpgetattribute
httppostattribute
httpputattribute
nonactionattribute
acceptverbsattribute
剩下的就是直接实例一个reflectedactiondescriptor对象了,这个也没什么特殊,只是里面有一个验证方法
复制代码 代码如下:

if (validatemethod) {
string failedmessage = verifyactionmethodiscallable(methodinfo);
if (failedmessage != null) {
throw new argumentexception(failedmessage, "methodinfo");
}
}

用来验证该方法是否可以执行,以下几种情况经不会通过,(1)方法是静态方法(2)方法的实例类型不是controllerbase(3)是否包含泛型参数如 public actionresult index<t>()是非法的,但 public actionresult index(list<string> aa)是合法(4)参数中不能含有ref和out。
这篇文章说的很散,我们需要注意一点微软在mvc里面缓存做的很好了,在前面个将获取controllertyper时它是有缓存的,一次读取当前程序集所有的controllertype,在这里提到了一个descriptorcache 缓存每次调用的controllertype->reflectedcontrollerdescriptor,而reflectedcontrollerdescriptor实例会一次去读该controller的所有action方法;这里还有一个reflectedattributecache,缓存每次调用methodinfo的所有特性(actionmethodselectorattribute、actionnameselectorattribute、filterattribute),当然filterattribute特性还可以在类上面。