在这里运行示例时出现以下错误。
Cannot resolve scoped service 'IPersonService' from root provider.
我想将服务IPersonService注入到规则MalePersonRule
请注意,同样的服务IPersonService被注入到HomeController中。
我已将此 IPersonService 注册为Startup.cs类中的范围服务。
我使用了这个NRules.Integration.AspNetCore nuget 包并得到了错误。因此,为了了解更多信息,我将这个 git hub repo 中的那个 nuget的来源包含在我的解决方案中的这个文件夹中。
如何在请求范围内注册服务,以便将该服务也注入到具有相同范围的规则中?这可能吗?
我知道该规则不能在请求范围内。该规则在应用程序开始时被实例化,然后在所有请求的剩余生命周期中使用相同的规则。我希望服务依赖项处于请求范围内,这意味着要为每个新请求重新实例化该服务。这可能吗?
但我猜规则会话是为每个请求重新创建的。
到目前为止,我还不能令人满意地将 NRules 集成到 AspNetCore 项目中。我研究了这个NRules.Demo 项目也是为了了解如何集成,但面临类似的问题。如果有任何显示如何集成的 aspnet 核心演示项目,请分享。
我错过了什么?
重现该问题的工作解决方案在这里供您参考。
NRules.RuleRhsExpressionEvaluationException
HResult=0x80131500
Message=Failed to evaluate rule action
(ctx, serviceProvider) => WriteLine(Convert(Convert(serviceProvider.GetService(NRulesWithAspNetCore.Services.IPersonService), IPersonService).Id, Object))
NRulesWithAspNetCore.Rules.MalePersonRule
Source=NRules
StackTrace:
at NRules.ActionExecutor.Execute(IExecutionContext executionContext, IActionContext actionContext)
at NRules.Session.Fire(Int32 maxRulesNumber, CancellationToken cancellationToken)
at NRules.Session.Fire(CancellationToken cancellationToken)
at NRules.Session.Fire()
at NRulesWithAspNetCore.Controllers.HomeController.Index() in D:\Trials\WorkFlow\ElsaBugReports\src\NR1003002NRulesAspNetCore\NR1003002NRulesAspNetCore\Controllers\HomeController.cs:line 46
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeActionMethodAsync>g__Logged|12_1>d.MoveNext()
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
InvalidOperationException: Cannot resolve scoped service 'NRulesWithAspNetCore.Services.IPersonService' from root provider.
更新:
嗨,谢尔盖,
谢谢你。您的解决方案正在运行。但我找到了另一种方法。
这是使用中间件。我得到了阅读这个 SO 答案的线索。
所以我创建了一个中间件如下。
public class NRulesMiddleWare
{
private readonly RequestDelegate _next;
public NRulesMiddleWare(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context,
ISessionFactory sessionFactory, IDependencyResolver dependencyResolver)
{
// Reference: https://stackoverflow.com/a/48591356/1977871
// Note 1. sessionFactory object is singleton meaning, its created at the start of the application.
// Then its the same instance is used throughout the applicatioin life cycle.
// But then the dependency resolver needs to be assigned everytime a request arrives.
// If dependencyResolver is assigned rigth in the beginning at the time of registration of
// sessionFactory, then its not working. I am Not sure why. But using this middleware, its working.
// Note 2. Here the dependency resolver instance is assigned afresh for each request.
sessionFactory.DependencyResolver = dependencyResolver;
await _next.Invoke(context);
}
}
注意上面的invoke方法对IDependencyResolver有依赖,所以需要注册。当然,中间件本身也必须注册。
总而言之,3个变化
- 在解决方案中包含上述中间件。
- 注册它的启动类配置方法。app.UseMiddleware();
- 最后,使用 ConfigureServices 中的服务集合注册 IDependencyResolver。services.AddScoped<IDependencyResolver, AspNetCoreDependencyResolver>();
您的方法使用 new 关键字来实例化解析器。在 DI 世界中,我在某处读到,这种更新是大罪。对象创建必须由 DI 容器(ServiceCollection)对象负责。所以我觉得中间件方法更好。