【发布时间】:2014-09-05 20:16:54
【问题描述】:
我有一个控制台应用程序,我编写了一个私有构造的 Bootstrapper 类,它公开了一个 Default 属性,该属性允许访问 Bootstrapper,只有一个可用的公共方法。我有一个问题,即我无法解析从同名的 NamedScope 注册为 InNamedScope 的实例的 NamedScope。代码如下:
public class Bootstrapper
{
private const string SCOPENAME = "BOOTSTRAPPED";
private static object KernelConstructionLocker = new object();
private StandardKernel Kernel;
private readonly Bootstrapper defaultBootstrapper = new Bootstrapper();
private Bootstrapper Default {get { return defaultBootstrapper; }}
private Bootstrapper()
{ }
public GetResolutionRoot()
{
if (Kernel == null)
{
//Kernel ctor not thread safe
lock(KernelConstructionLocker)
{
//double locked incase thread created while locked
if (Kernel == null)
{
Kernel = CreateKernel();
}
}
}
return new TaskExecutionScope(Kernel.CreateNamedScope(SCOPENAME));
}
private CreateKernel()
{
Kernel = new StandardKernel();
//bindings, etc...
}
}
public class TaskExecutionScope : IResolutionRoot, IDisposable
{
private readonly NamedScope scope;
internal TaskExecutionScope(NamedScope scope)
{
this.scope = scope;
}
public bool CanResolve(Ninject.Activation.IRequest request, bool ignoreImplicitBindings)
{
var canResolve = scope.CanResolve(request, ignoreImplicitBindings);
return canResolve;
}
public bool CanResolve(Ninject.Activation.IRequest request)
{
var canResolve = scope.CanResolve(request);
return canResolve;
}
public Ninject.Activation.IRequest CreateRequest(Type service, Func<Ninject.Planning.Bindings.IBindingMetadata, bool> constraint, System.Collections.Generic.IEnumerable<Ninject.Parameters.IParameter> parameters, bool isOptional, bool isUnique)
{
var request = scope.CreateRequest(service, constraint, parameters, isOptional, isUnique);
return request;
}
public bool Release(object instance)
{
var release = scope.Release(instance);
return release;
}
public System.Collections.Generic.IEnumerable<object> Resolve(Ninject.Activation.IRequest request)
{
var resolve = scope.Resolve(request);
return resolve;
}
public void Dispose()
{
scope.Dispose();
}
}
然后,当我尝试将在 CreateKernel 方法中注册的绑定解析为
kernel.Bind<IUnitOfWorkService>()
.To<UnitOfWorkService>()
.InNamedScope(SCOPENAME);
无法解决并出现错误:
Error activating IUnitOfWorkService
The scope BOOTSTRAPPED is not known in the current context.
No matching scopes are available, and the type is declared InNamedScope(BOOTSTRAPPED).
Activation path:
1) Request for IUnitOfWorkService
Suggestions:
1) Ensure that you have defined the scope BOOTSTRAPPED.
2) Ensure you have a parent resolution that defines the scope.
3) If you are using factory methods or late resolution, check that the correct IResolutionRoot is being used.
堆栈跟踪:
at Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.GetNamedScope(IContext context, String scopeParameterName)
at Ninject.Extensions.NamedScope.NamedScopeExtensionMethods.<>c__DisplayClass1`1.<InNamedScope>b__0(IContext context)
at Ninject.Planning.Bindings.BindingConfiguration.GetScope(IContext context)
at Ninject.Planning.Bindings.Binding.GetScope(IContext context)
at Ninject.Activation.Context.GetScope()
at Ninject.Activation.Context.Resolve()
at Ninject.KernelBase.<>c__DisplayClass15.<Resolve>b__f(IBinding binding)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters)
at SomeConsoleApp.Work.ScheduledWork.ScheduledWork.Quartz.IJob.Execute(IJobExecutionContext context) in ***
在这一点上,我不知道还有什么可以尝试的,任何帮助将不胜感激。
编辑
抱歉,我以为我知道我在这里是如何使用它的。这是一个关于如何使用它的 sn-p:
using (TaskExecutionScope scope = Bootstrapper.Default.GetResolutionRoot())
{
var unitOfWork = scope.Get<IUnitOfWorkService>();
//do things with unit of work service
}
这是一个简单的使用示例。对Get<IUnitOfWorkService> 的调用失败。现在,虽然这个 WAS 失败了,但我能够通过包含 Context Preservation 插件并稍微更改 TaskExecutionScope 来使其工作(仅更改了上面代码中的 Resolve(IRequest request) 方法:
public System.Collections.Generic.IEnumerable<object> Resolve(Ninject.Activation.IRequest request)
{
var attempt = request.ParentContext.GetContextPreservingResolutionRoot().Resolve(request);
return attempt;
}
虽然这可行,但我讨厌在我的代码中包含一些我不知道为什么必须在我的代码中包含它的东西,这就是其中一个示例。我希望在我直接在NamedScope 上调用Resolve 之前,它应该可以运行,因为它是一个解析根 - 我不明白NamedScope 的解析根是如何不知道自己的名字???所以,我也很想知道-
A) 为什么我必须这样做才能让它工作?
B) 这是有史以来最糟糕的事情 - 你应该这样做!
C) 这可行,但有一个小错误...
编辑 2
所以,我尝试了@BatteryBackupUnit 的建议,但失败并出现与以前相同的错误...我将此行添加到 CreateKernel 方法:
kernel.Bind<TaskExecutionScope>().ToSelf().DefinesNamedScope(SCOPENAME);
并将 GetResolutionRoot 方法更改为 return Kernel.Get<TaskExecutionScope>(); 。在这一点上,我正在恢复到下面提到的工作代码。
【问题讨论】:
-
你是如何解析对象的?使用
NamedScope.Get,.. 或如何?请也显示那段代码。 -
@BatteryBackupUnit 添加了一个示例,说明我是如何使用它的,以及我是如何让它工作的。请仍然查看它并给我任何反馈 - 它是错误的、错误的、正确的和/或为什么我必须这样做......
标签: scope ninject named-scope ninject-extensions