seesharper / LightInject

An ultra lightweight IoC container
http://www.lightinject.net
MIT License
618 stars 121 forks source link

Blazor integration #468

Open jesuslpm opened 5 years ago

jesuslpm commented 5 years ago

Would it be possible integrating LightInject with Blazor?

I tried the following in a server side Blazor app:

    public class Startup
    {

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            var container = new LightInject.ServiceContainer();
            container.Register<Services.WeatherForecastService>(new PerContainerLifetime());
            return container.CreateServiceProvider(services);
        }

        public void Configure(IBlazorApplicationBuilder app)
        {
            app.AddComponent<App>("app");
        }
    }

But I get the following exception when clicking on "Fetch data":

System.InvalidOperationException: Cannot provide a value for property 'ForecastService' on type 'BlazorServer.App.Pages.FetchData'. There is no registered service of type 'BlazorServer.App.Services.WeatherForecastService'. at Microsoft.AspNetCore.Blazor.Components.ComponentFactory.<>c__DisplayClass6_0.b__2(IComponent instance) at Microsoft.AspNetCore.Blazor.Components.ComponentFactory.PerformPropertyInjection(IComponent instan .......

There is no reference to LightInject in the stack trace. Blazor is not using the service provider returned from ConfigureServices.

How can I use LightInject on Blazor?

seesharper commented 5 years ago

Could you try to set up your Startup according to this?

https://www.lightinject.net/microsoft.aspnetcore.hosting/

jesuslpm commented 5 years ago

I get:

System.InvalidOperationException: Attempt to end a scope before all child scopes are completed.

Reproduction steps:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates
dotnet new blazorserverside -o BlazorServer

On BlazorServer.Server project:

install-package LightInject
install-package LightInject.Microsoft.AspNetCore.Hosting -Version 1.0.0

I didn't installed LightInject.Microsoft.AspNetCore.Hosting version 1.1.0 because BlazorServer project is netcore 2.1 app.

BlazorServer.Server.Program:

    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)

                .UseConfiguration(new ConfigurationBuilder()
                    .AddCommandLine(args)
                    .Build())
                .UseLightInject()
                .UseStartup<Startup>()
                .Build();
    }

BlazorServer.Server.StartUp:

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            // Adds the Server-Side Blazor services, and those registered by the app project's startup.
            services.AddServerSideBlazor<App.Startup>();

            services.AddResponseCompression(options =>
            {
                options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
                {
                    MediaTypeNames.Application.Octet,
                    WasmMediaTypeNames.Application.Wasm,
                });
            });
        }

        public void ConfigureContainer(IServiceContainer container)
        {
            container.Register<BlazorServer.App.Services.WeatherForecastService>(new PerContainerLifetime());
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseResponseCompression();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // Use component registrations and static files from the app project.
            app.UseServerSideBlazor<App.Startup>();
        }
    }

I think this is not the only problem. A server side blazor app has another project BlazorServer.App, this is a .net standard 2.0 project that has its own StartUp class:

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IBlazorApplicationBuilder app)
        {
            app.AddComponent<App>("app");
        }

        public void ConfigureContainer(IServiceContainer container)
        {
            container.Register<BlazorServer.App.Services.WeatherForecastService>(new PerContainerLifetime());
        }
    }

I'm not sure but I think this uses another DI container instance that is not the same as the one used on the other project.

jesuslpm commented 5 years ago

I forgot to say that BlazorServer.App.StartUp.ConfigureContainer is never called.