Open EricMKaufman opened 3 years ago
I have related issue:
I use IHostedService. all services registered with ConfigureContainer extension of IHostBuilder. SimpleSingletone registered as Singleton lifestyle. Service IAnyScopedService as Scoped
public class SimpleSingletone
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public SimpleSingletone(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(IServiceScopeFactory ))
}
public string Get()
{
var scope = _serviceScopeFactory.CreateScope();
try
{
var scopedService = scope.ServiceProvider.GetService<IAnyScopedService>();
return scopedService.Get(userId);
}
finally
{
scope.Dispose();
}
}
}
scope.ServiceProvider.GetService<> was throw No Scope.
if i replace IServiceScopeFactory IWindsorContainer all works perfectly.
I was able to come up with a work around, but I think it's a bit of a hack and I'm unsure how it will effect releasing scoped resources.
The below creates a class that derives from WindsorServiceProviderFactoryBase
so it can create a root scope on the executing thread.
namespace WebApplication1
{
public class Global : System.Web.HttpApplication
{
public static WindsorServiceProviderFactoryCustom ServiceProviderFactory;
protected void Application_Start(object sender, EventArgs e)
{
Console.WriteLine("Hello World!");
var container = new WindsorContainer();
ServiceProviderFactory = new WindsorServiceProviderFactoryCustom(container);
var host = new HostBuilder()
.UseWindsorContainerServiceProvider(ServiceProviderFactory)
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<SomeService>();
})
.Build();
//Note: This works great
var resolved = ServiceProviderFactory.Container.Resolve<SomeService>();
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
public class SomeService
{
}
public class HttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//This fixes the error, but I am too unfamiliar with the internals of this library to understand if this is a reasonable workaround. Will the component be scoped to `scope` below?
Global.ServiceProviderFactory.CreateRootScope();
using (var scope = Global.ServiceProviderFactory.Container.BeginScope())
{
//this no longer errors, but at what cost.
var someService = Global.ServiceProviderFactory.Container.Resolve<SomeService>();
}
}
public bool IsReusable => false;
}
public sealed class WindsorServiceProviderFactoryCustom : WindsorServiceProviderFactoryBase
{
public WindsorServiceProviderFactoryCustom(IWindsorContainer container)
{
CreateRootScope();
SetRootContainer(container);
}
public new void CreateRootScope()
{
base.CreateRootScope();
}
}
}
I think this has been fixed as CreateRootScope
is called in WindsorServiceProviderFactory
constructor.
I think the cleanest way to do it though is:
host
static variablehost.Services
using (var scope = host.Services.CreateScope())
{
scope.GetService<SomeService>();
}
I have this issue with the latest versions of Castle.Windsor
6.0.0 and Castle.Windsor.Extensions.Hosting
6.0.0.
I call this code on my ASP.NET
6.0 server:
var builder = WebApplication.CreateBuilder();
var container = new WindsorContainer();
builder.Host.UseWindsorContainerServiceProvider(container);
And when running my server (with gRPC services, and a Yarp reverse proxy configured), I get this error:
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: No scope available
at Castle.Windsor.Extensions.DependencyInjection.Scope.ExtensionContainerScopeCache.get_Current()
at Castle.Windsor.Extensions.DependencyInjection.Scope.ForcedScope..ctor(ExtensionContainerScopeBase scope)
at Castle.Windsor.Extensions.DependencyInjection.WindsorScopedServiceProvider.GetRequiredService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Routing.Matching.DfaMatcherFactory.CreateMatcher(EndpointDataSource dataSource)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.InitializeCoreAsync()
--- End of stack trace from previous location ---
I have checked the method CreateRootScope
is indeed called in the underlying WindsorServiceProviderFactory
.
Any idea? 😄
Addendum: The exact same code used to work with the previous version / package Caste.Windsor.Extensions.DependencyInjection
5.1.1.
I am using this nuget package to configure Castle Windsor as the DI container. https://www.nuget.org/packages/Castle.Windsor.Extensions.DependencyInjection/
This works fine except for when I try to resolve scoped classes with an IHttpHandler. I get the error: InvalidOperationException: No scope available
What is the correct way to create scope for an HttpHandler?
Here's a sample application reproducing the issue:
Web.config: