使用Singleton服务的ServiceProvider.GetRequiredService与ApplicationServies.GetRequiredService

时间:2018-08-28 08:56:08

标签: asp.net-core .net-core

调用单例服务有什么区别。

在app.UseMvc();

app.UseMvc(options =>
{
    options
        .ServiceProvider
        .GetRequiredService<IYamlIndexer>()
        .IndexContentFiles(Constants.ContentPath);
});

或者这个:

app
    .ApplicationServices
    .GetRequiredService<IYamlIndexer>()
    .IndexContentFiles(Constants.ContentPath);

2 个答案:

答案 0 :(得分:1)

简短回答

在大多数情况下,两者之间没有区别。这两个属性都指向相同的IServiceProvider实例,并且都将获得必需的单例服务的相同实例。在边缘情况下,调用的时间可能会有所不同,但我想不到会导致这种情况发生的边缘情况。除非我们做一些不寻常的事情,否则两者都将只运行一次,并且只能在应用程序启动期间运行。

演示实验

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<SomeSingltonService>();
    }

    public void Configure(IApplicationBuilder app)
    {
        var appServices = app.ApplicationServices;
        var appService = appServices.GetRequiredService<SomeSingltonService>();

        Console.WriteLine("=======================");
        Console.WriteLine("Configure");

        app.UseMvc(configureRoutes =>
        {
            var routeServices = routeBuilder.ServiceProvider;
            var routeService = routeServices.GetRequiredService<SomeSingltonService>();

            Console.WriteLine("UseMvc");

            if (appServices == routeServices && appService == routeService)
            {
                Console.WriteLine("They are the same instances.");
            }
        });

        Console.WriteLine("=======================");
    }
}

这是输出:

=======================        
Configure                      
UseMvc                         
They are the same instance.    
=======================        

要演示的源代码

UseMvc在后​​台将IApplicationBulder传递给RouteBuilder构造函数。然后RouteBuilderIApplicationBulder.ApplicationServices分配给它自己的IRouteBuilder.ServiceProvider属性。

来自MvcApplicationBuilderExtensions.cs的代码

public static IApplicationBuilder UseMvc(
    this IApplicationBuilder app,
    Action<IRouteBuilder> configureRoutes)
{
    // ...

    var routes = new RouteBuilder(app) // ln 136
    {
        DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
    };

    configureRoutes(routes);

    // ...
}

来自RouteBuilder.cs的代码

public RouteBuilder(IApplicationBuilder applicationBuilder, IRouter defaultHandler)
{
    // ...

    ServiceProvider = applicationBuilder.ApplicationServices; // ln 36

    // ...
}

答案 1 :(得分:0)

在(2)中,IndexContentFiles将在应用程序启动期间立即启动,而应用程序未“完全运行”。这可能会导致一些问题(取决于IYamlIndexer.IndexContentFiles实际执行的操作)。另外,如果这是同步长时间运行的呼叫-您的应用在启动过程中会变慢。

在(1)中,该方法将在MVC子系统要求它提供选项的某个时间开始。这将在应用启动后的某个地方发生,如果长时间运行,则将再次花费一些时间...

还有一个问题,您应该问自己-选项如何配置-单例或瞬态(以及为什么您信任此知识)?在最坏的情况下,每次请求“ MVC选项”时,您的IndexContentFiles都会被调用,并且您的应用将在每次用户请求时调用IndexContentFiles消失...

也许您需要类似IApplicationLifetime的东西吗?