当前位置: 移动技术网 > IT编程>开发语言>.net > <深入理解Abp> 程序启动 - 一切的开始

<深入理解Abp> 程序启动 - 一切的开始

2018年12月05日  | 移动技术网IT编程  | 我要评论

新民事诉讼法全文,结婚证书多少钱,衣服百搭

我们知道net core应用程序的核心配置在项目中的startup.cs 文件.

public class startup
{
    public iserviceprovider configureservices(iservicecollection services)
    {
        //...
        
        return services.addabp<webmodule>(//...);
    }

    public void configure(iapplicationbuilder app)
    {
        app.useabp(//...);

        //...
    }
}
  • public void configureservices(iservicecollection services)方法主要用于将服务添加到di容器中并做一些配置.
  • public void configure(iapplicationbuilder app)配置请求管道.

abp框架使用自己的di容器(主要为了兼容之前的net framework版本和使用一些高级特性,如拦截器),所以我们在configureservices 方法的底部会看到return services.addabp(//...)这时候configureservices的方法返回值也变成了iserviceprovider(关于这点请参考:)

框架与aspnet core深度集成的地方就在addabp方法和useabp的内部:

public static class abpservicecollectionextensions
{
    /// <summary>
    /// integrates abp to aspnet core.
    /// </summary>
    /// <typeparam name="tstartupmodule">startup module of the application which depends on other used modules. should be derived from <see cref="abpmodule"/>.</typeparam>
    /// <param name="services">services.</param>
    /// <param name="optionsaction">an action to get/modify options</param>
    public static iserviceprovider addabp<tstartupmodule>(this iservicecollection services, [canbenull] action<abpbootstrapperoptions> optionsaction = null)
        where tstartupmodule : abpmodule
    {
        var abpbootstrapper = addabpbootstrapper<tstartupmodule>(services, optionsaction);

        configureaspnetcore(services, abpbootstrapper.iocmanager);

        return windsorregistrationhelper.createserviceprovider(abpbootstrapper.iocmanager.ioccontainer, services);
    }

    private static void configureaspnetcore(iservicecollection services, iiocresolver iocresolver)
    {
        //see https://github.com/aspnet/mvc/issues/3936 to know why we added these services.
        services.tryaddsingleton<ihttpcontextaccessor, httpcontextaccessor>();
        services.tryaddsingleton<iactioncontextaccessor, actioncontextaccessor>();
        
        //use di to create controllers
        services.replace(servicedescriptor.transient<icontrolleractivator, servicebasedcontrolleractivator>());

        //use di to create view components
        services.replace(servicedescriptor.singleton<iviewcomponentactivator, servicebasedviewcomponentactivator>());

        //change anti forgery filters (to work proper with non-browser clients)
        services.replace(servicedescriptor.transient<autovalidateantiforgerytokenauthorizationfilter, abpautovalidateantiforgerytokenauthorizationfilter>());
        services.replace(servicedescriptor.transient<validateantiforgerytokenauthorizationfilter, abpvalidateantiforgerytokenauthorizationfilter>());

        //add feature providers
        var partmanager = services.getsingletonserviceornull<applicationpartmanager>();
        partmanager?.featureproviders.add(new abpappservicecontrollerfeatureprovider(iocresolver));

        //configure json serializer
        services.configure<mvcjsonoptions>(jsonoptions =>
        {
            jsonoptions.serializersettings.contractresolver = new abpmvccontractresolver(iocresolver)
            {
                namingstrategy = new camelcasenamingstrategy()
            };
        });

        //configure mvc
        services.configure<mvcoptions>(mvcoptions =>
        {
            mvcoptions.addabp(services);
        });

        //configure razor
        services.insert(0,
            servicedescriptor.singleton<iconfigureoptions<razorviewengineoptions>>(
                new configureoptions<razorviewengineoptions>(
                    (options) =>
                    {
                        options.fileproviders.add(new embeddedresourceviewfileprovider(iocresolver));
                    }
                )
            )
        );
    }

    private static abpbootstrapper addabpbootstrapper<tstartupmodule>(iservicecollection services, action<abpbootstrapperoptions> optionsaction)
        where tstartupmodule : abpmodule
    {
        var abpbootstrapper = abpbootstrapper.create<tstartupmodule>(optionsaction);
        services.addsingleton(abpbootstrapper);
        return abpbootstrapper;
    }
}

abpbootstrapper作为abp核心的引导类,负责初始化abp系统,加载插件,配置abp和模块以及启动模块(preinitialize,initialize, postinitialize). 这个引导类在console应用程序中同样可以启动abp系统.

接下来abp配置和替换了多个mvc的组件,如icontrolleractivator,iviewcomponentactivator,mvcjsonoptions,mvcoptions更多的配置在mvcoptions.addabp(services)方法下:

internal static class 

{
    public static void addabp(this mvcoptions options, iservicecollection services)
    {
        addconventions(options, services);
        addfilters(options);
        addmodelbinders(options);
    }

    private static void addconventions(mvcoptions options, iservicecollection services)
    {
        options.conventions.add(new abpappserviceconvention(services));
    }

    private static void addfilters(mvcoptions options)
    {
        options.filters.addservice(typeof(abpauthorizationfilter));
        options.filters.addservice(typeof(abpauditactionfilter));
        options.filters.addservice(typeof(abpvalidationactionfilter));
        options.filters.addservice(typeof(abpuowactionfilter));
        options.filters.addservice(typeof(abpexceptionfilter));
        options.filters.addservice(typeof(abpresultfilter));
    }

    private static void addmodelbinders(mvcoptions options)
    {
        options.modelbinderproviders.insert(0, new abpdatetimemodelbinderprovider());
    }
}

abpappserviceconvention 主要用于配置动态api,这个后面会有一章单独说明.

abpauthorizationfilter
abpauditactionfilter
abpvalidationactionfilter
abpuowactionfilter
abpexceptionfilter
abpresultfilter

依次添加6个mvc过滤器分别实现授权,审计,参数验证,工作单元,异常处理以及返回内容的包装.(请注意过滤器顺序很重要)

abpdatetimemodelbinderprovider 用作datetime的统一时区处理.

接下来我们再看useabp方法:

public static class abpapplicationbuilderextensions
{
    public static void useabp(this iapplicationbuilder app)
    {
        app.useabp(null);
    }

    public static void useabp([notnull] this iapplicationbuilder app, action<abpapplicationbuilderoptions> optionsaction)
    {
        check.notnull(app, nameof(app));

        var options = new abpapplicationbuilderoptions();
        optionsaction?.invoke(options);

        if (options.usecastleloggerfactory)
        {
            app.usecastleloggerfactory();
        }

        initializeabp(app);

        if (options.useabprequestlocalization)
        {
            //todo: this should be added later than authorization middleware!
            app.useabprequestlocalization();
        }

        if (options.usesecurityheaders)
        {
            app.useabpsecurityheaders();
        }
    }

    public static void useembeddedfiles(this iapplicationbuilder app)
    {
        app.usestaticfiles(
            new staticfileoptions
            {
                fileprovider = new embeddedresourcefileprovider(
                    app.applicationservices.getrequiredservice<iiocresolver>()
                )
            }
        );
    }

    private static void initializeabp(iapplicationbuilder app)
    {
        var abpbootstrapper = app.applicationservices.getrequiredservice<abpbootstrapper>();
        abpbootstrapper.initialize();

        var applicationlifetime = app.applicationservices.getservice<iapplicationlifetime>();
        applicationlifetime.applicationstopping.register(() => abpbootstrapper.dispose());
    }

    public static void usecastleloggerfactory(this iapplicationbuilder app)
    {
        var castleloggerfactory = app.applicationservices.getservice<castle.core.logging.iloggerfactory>();
        if (castleloggerfactory == null)
        {
            return;
        }

        app.applicationservices
            .getrequiredservice<iloggerfactory>()
            .addcastlelogger(castleloggerfactory);
    }

    public static void useabprequestlocalization(this iapplicationbuilder app, action<requestlocalizationoptions> optionsaction = null)
    {
        var iocresolver = app.applicationservices.getrequiredservice<iiocresolver>();
        using (var languagemanager = iocresolver.resolveasdisposable<ilanguagemanager>())
        {
            var supportedcultures = languagemanager.object
                .getlanguages()
                .select(l => cultureinfo.getcultureinfo(l.name))
                .toarray();

            var options = new requestlocalizationoptions
            {
                supportedcultures = supportedcultures,
                supporteduicultures = supportedcultures
            };

            var userprovider = new abpuserrequestcultureprovider();

            //0: querystringrequestcultureprovider
            options.requestcultureproviders.insert(1, userprovider);
            options.requestcultureproviders.insert(2, new abplocalizationheaderrequestcultureprovider());
            //3: cookierequestcultureprovider
            options.requestcultureproviders.insert(4, new abpdefaultrequestcultureprovider());
            //5: acceptlanguageheaderrequestcultureprovider

            optionsaction?.invoke(options);

            userprovider.cookieprovider = options.requestcultureproviders.oftype<cookierequestcultureprovider>().firstordefault();
            userprovider.headerprovider = options.requestcultureproviders.oftype<abplocalizationheaderrequestcultureprovider>().firstordefault();

            app.userequestlocalization(options);
        }
    }

    public static void useabpsecurityheaders(this iapplicationbuilder app)
    {
        app.usemiddleware<abpsecurityheadersmiddleware>();
    }
}

核心initializeabp(app),使用上文之前提到abpbootstrapper引导启动abp系统.(我们知道abp模块有个shutdown()方法,abp使用iapplicationlifetime接口捕获应用程序事件实现模块的shoutdown)

之后按需启动几个中间件,如: requestlocalization,securityheaders等(这些小组件和之前的过滤器后面我会分别详细介绍,这里就不深入讲解)

至此abp已经把框架的相关组件集成到了mvc中.接下来程序启动.请求被各种中间件处理(mvc中间件会调用过滤器).

abp中文网:
abp交流群:735901849(纯技术交流,无广告,不卖课)

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网