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

.NET Core开发日志——Controller

程序员文章站 2022-06-30 18:15:26
在理清 "路由" 的工作流程后,接下来需要考虑的,是MVC框架如何生成Controller以及它的生成时机。 根据以前ASP.NET MVC的经验,Controller应该是由一个ControllerFactory构建的。查看ASP.NET Core MVC的源码,果然是有一个DefaultCont ......

在理清的工作流程后,接下来需要考虑的,是mvc框架如何生成controller以及它的生成时机。

根据以前asp.net mvc的经验,controller应该是由一个controllerfactory构建的。查看asp.net core mvc的源码,果然是有一个defaultcontrollerfactory类,并且不出意外的,它拥有一个createcontroller方法。

public virtual object createcontroller(controllercontext context)
{
    ...

    var controller = _controlleractivator.create(context);
    foreach (var propertyactivator in _propertyactivators)
    {
        propertyactivator.activate(context, controller);
    }

    return controller;
}

但细推其使用的场合,只出现在controllerfactoryprovider的构造方法内部,且仅是用于判断所传入的controllerfactory类型是否是defaultcontrollerfactory。

public controllerfactoryprovider(
    icontrolleractivatorprovider activatorprovider,
    icontrollerfactory controllerfactory,
    ienumerable<icontrollerpropertyactivator> propertyactivators)
{
    ...

    _activatorprovider = activatorprovider;

    // compat: delegate to the icontrollerfactory if it's not the default implementation.
    if (controllerfactory.gettype() != typeof(defaultcontrollerfactory))
    {
        _factorycreatecontroller = controllerfactory.createcontroller;
        _factoryreleasecontroller = controllerfactory.releasecontroller;
    }

    _propertyactivators = propertyactivators.toarray();
}

再看controllerfactoryprovider内部的createcontrollerfactory方法。这更像是一个真正创建controller的工厂方法。

public func<controllercontext, object> createcontrollerfactory(controlleractiondescriptor descriptor)
{
    ...

    if (_factorycreatecontroller != null)
    {
        return _factorycreatecontroller;
    }

    var controlleractivator = _activatorprovider.createactivator(descriptor);
    var propertyactivators = getpropertiestoactivate(descriptor);
    object createcontroller(controllercontext controllercontext)
    {
        var controller = controlleractivator(controllercontext);
        for (var i = 0; i < propertyactivators.length; i++)
        {
            var propertyactivator = propertyactivators[i];
            propertyactivator(controllercontext, controller);
        }

        return controller;
    }

    return createcontroller;
}

创建方式分为两种,一种是使用自定义的工厂方法,另一种是通过controlleractivatorprovider的createactivator方法。

public func<controllercontext, object> createactivator(controlleractiondescriptor descriptor)
{
    ...

    var controllertype = descriptor.controllertypeinfo?.astype();
    ...

    if (_controlleractivatorcreate != null)
    {
        return _controlleractivatorcreate;
    }

    var typeactivator = activatorutilities.createfactory(controllertype, type.emptytypes);
    return controllercontext => typeactivator(controllercontext.httpcontext.requestservices, arguments: null);
}

明白了如何创建controller,下面开始调查创建controller的时机。

controllerfactoryprovider类的createcontrollerfactory方法是被controlleractioninvokercache类的getcachedresult方法调用。

public (controlleractioninvokercacheentry cacheentry, ifiltermetadata[] filters) getcachedresult(controllercontext controllercontext)
{
    var cache = currentcache;
    var actiondescriptor = controllercontext.actiondescriptor;

    ifiltermetadata[] filters;
    if (!cache.entries.trygetvalue(actiondescriptor, out var cacheentry))
    {
        var filterfactoryresult = filterfactory.getallfilters(_filterproviders, controllercontext);
        filters = filterfactoryresult.filters;

        var parameterdefaultvalues = parameterdefaultvalues
            .getparameterdefaultvalues(actiondescriptor.methodinfo);

        var objectmethodexecutor = objectmethodexecutor.create(
            actiondescriptor.methodinfo,
            actiondescriptor.controllertypeinfo,
            parameterdefaultvalues);

        var controllerfactory = _controllerfactoryprovider.createcontrollerfactory(actiondescriptor);
        var controllerreleaser = _controllerfactoryprovider.createcontrollerreleaser(actiondescriptor);
        var propertybinderfactory = controllerbinderdelegateprovider.createbinderdelegate(
            _parameterbinder,
            _modelbinderfactory,
            _modelmetadataprovider,
            actiondescriptor);

        var actionmethodexecutor = actionmethodexecutor.getexecutor(objectmethodexecutor);

        cacheentry = new controlleractioninvokercacheentry(
            filterfactoryresult.cacheablefilters, 
            controllerfactory, 
            controllerreleaser,
            propertybinderfactory,
            objectmethodexecutor,
            actionmethodexecutor);
        cacheentry = cache.entries.getoradd(actiondescriptor, cacheentry);
    }
    else
    {
        // filter instances from statically defined filter descriptors + from filter providers
        filters = filterfactory.createuncachedfilters(_filterproviders, controllercontext, cacheentry.cachedfilters);
    }

    return (cacheentry, filters);
}

其值作为controlleractioninvokercacheentry对象的一部分被方法返回。

getcachedresult方法的上层调用者是controlleractioninvokerprovider类的onprovidersexecuting方法。

public void onprovidersexecuting(actioninvokerprovidercontext context)
{
    ...

    if (context.actioncontext.actiondescriptor is controlleractiondescriptor)
    {
        var controllercontext = new controllercontext(context.actioncontext);
        // perf: these are rarely going to be changed, so let's go copy-on-write.
        controllercontext.valueproviderfactories = new copyonwritelist<ivalueproviderfactory>(_valueproviderfactories);
        controllercontext.modelstate.maxallowederrors = _maxmodelvalidationerrors;

        var cacheresult = _controlleractioninvokercache.getcachedresult(controllercontext);

        var invoker = new controlleractioninvoker(
            _logger,
            _diagnosticsource,
            controllercontext,
            cacheresult.cacheentry,
            cacheresult.filters);

        context.result = invoker;
    }
}

controlleractioninvokercacheentry对象又被作为controlleractioninvoker对象的一部分为actioninvokerprovidercontext的result属性赋值。

再往上跟踪,到了actioninvokerfactory类的createinvoker方法。

public iactioninvoker createinvoker(actioncontext actioncontext)
{
    var context = new actioninvokerprovidercontext(actioncontext);

    foreach (var provider in _actioninvokerproviders)
    {
        provider.onprovidersexecuting(context);
    }

    for (var i = _actioninvokerproviders.length - 1; i >= 0; i--)
    {
        _actioninvokerproviders[i].onprovidersexecuted(context);
    }

    return context.result;
}

而它的调用者便是mvcroutehandler或者mvcattributeroutehandler。

public task routeasync(routecontext context)
{
    ...

    context.handler = (c) =>
    {
        var routedata = c.getroutedata();

        var actioncontext = new actioncontext(context.httpcontext, routedata, actiondescriptor);
        if (_actioncontextaccessor != null)
        {
            _actioncontextaccessor.actioncontext = actioncontext;
        }

        var invoker = _actioninvokerfactory.createinvoker(actioncontext);
        if (invoker == null)
        {
            throw new invalidoperationexception(
                resources.formatactioninvokerfactory_couldnotcreateinvoker(
                    actiondescriptor.displayname));
        }

        return invoker.invokeasync();
    };

    ...
}

到了这里创建controller的工厂方法还没有被实际调用,此时controller还是不存在的。所以还需要完成执行controlleractioninvoker的invokeasync方法,或者更准确地说是其基类resourceinvoker的invokeasync方法。

public virtual async task invokeasync()
{
    try
    {
        ...

        using (_logger.actionscope(_actioncontext.actiondescriptor))
        {
            ...

            try
            {
                await invokefilterpipelineasync();
            }
            ...
        }
    }
    ...
}

从invokefilterpipelineasync方法开始,一系列的处理流程将依据不同状态逐步展开。

private async task invokefilterpipelineasync()
{
    var next = state.invokebegin;

    var scope = scope.invoker;

    var state = (object)null;

    var iscompleted = false;

    while (!iscompleted)
    {
        await next(ref next, ref scope, ref state, ref iscompleted);
    }
}

而到了state.actionbegin这一步(controlleractioninvoker类的next方法),终于能找到controller工厂方法被执行的场合。

private task next(ref state next, ref scope scope, ref object state, ref bool iscompleted)
{
    switch (next)
    {
        case state.actionbegin:
            {
                var controllercontext = _controllercontext;

                _cursor.reset();

                _instance = _cacheentry.controllerfactory(controllercontext);

                _arguments = new dictionary<string, object>(stringcomparer.ordinalignorecase);

                var task = bindargumentsasync();
                if (task.status != taskstatus.rantocompletion)
                {
                    next = state.actionnext;
                    return task;
                }

                goto case state.actionnext;
            }
        ...
        }            
    }
}            

最后以一张流程图总结上面的探寻过程。

.NET Core开发日志——Controller