kernel.Bind<DbContext>().ToSelf().InRequestScope(); kernel.Bind<IUnitOfWork<DbContext>>().To<UnitOfWork<DbContext>>();
但是从任务调度程序调用InRequestScope()中的DbContext无法更新Db表(没有任何错误),直到我将Binding更改为InSingletonScope()或InThreadScope()
问题:他们以任何方式将范围更改为InSingletonScope()/ InThreadScope()以进行任务计划程序调用. ?
//对于任务计划程序调用,我尝试了bellow,但没有正常工作
kernel.Bind<DbContext>().ToSelf() .When(request => request.Target.Type.Namespace.StartsWith("NameSpace.ClassName")) .InSingletonScope();
**可能我想念一些东西.需要帮忙.
代码片段已更新
#region Commented Code public EmailTask() : this ( DependencyResolver.Current.GetService<IMessageManager>(),DependencyResolver.Current.GetService<IUnitOfWork<DbContext>>()) { } #endregion public EmailTask(IMessageManager messageManager,IUnitOfWork<DbContext> unitOfWork) { this._messageManager = messageManager; this._unitOfWork = unitOfWork; ProcessEmail(); } public class NonRequestScopedParameter : IParameter { ... } public void ProcessEmail() { var temp = SomeRepository.GetAll(); SendEmail(temp); temp.Date = DateTime.Now; SomeRepository.Update(temp); unitOfWork.Commit(); } public class ExecuteEmailTask : ITask { private readonly IResolutionRoot _resolutionRoot; private int _maxTries = 5; public ExecuteEmailTask(IResolutionRoot resolutionRoot) { _resolutionRoot = resolutionRoot; } public void Execute(XmlNode node) { XmlAttribute attribute1 = node.Attributes["maxTries"]; if (attribute1 != null && !String.IsNullOrEmpty(attribute1.Value)) { this._maxTries = int.Parse(attribute1.Value); } /// send email messages var task = _resolutionRoot.Get<EmailTask>(new NonRequestScopedParameter()); } }
在Web.Config中
<ScheduleTasks> <Thread seconds="60"> <task name="ExecuteEmailTask" type="namespace.ExecuteEmailTask,AssemblyName" enabled="true" stopOnError="false" maxTries="5"/> </Thread> </ScheduleTasks>
在Global.asax中
protected void Application_Start() { /* intialize Task */ TaskConfig.Init(); TaskManager.Instance.Initialize(TaskConfig.ScheduleTasks); TaskManager.Instance.Start(); }
Ninject绑定语法
kernel.Bind<DbContext>().ToSelf().InRequestScope(); // Default bind kernel.Bind<DbContext>().ToSelf() .When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any()) .InCallScope(); // For Scheduler
注意:EmailTask类也有SomeReposity作为构造函数参数.
查询: –
>但是解析TaskScheduler(IResolutionRoot resolutionRoot)的绑定语法是什么?
>运行TaskScheduler的配置代码是什么?
>如果将IFakeDbContext直接放入构造函数中,可以使用IUnitOfWork< FakeDbContext> ?
问题
Task无法使用重载构造函数调用,它只能调用TaskScheduler的默认构造函数.
问题4:可以以任何方式从TaskScheduler默认构造函数调用TaskScheduler(IResolutionRoot resolutionRoot)吗?
示例代码片段创建任务&使用System.Threading.Timer运行
private ITask createTask() { if (this.Enabled && (this._task == null)) { if (this._taskType != null) { this._task = Activator.CreateInstance(this._taskType) as ITask; } this._enabled = this._task != null; } return this._task; }
问题5:我可以在这里解决TaskScheduler(IResolutionRoot resolutionRoot)吗?
解决了
public ExecuteEmailTask():
此(DependencyResolver.Current.GetService< IResolutionRoot>())
要么
public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { } public ExecuteEmailTask(IResolutionRoot resolutionRoot) { _resolutionRoot = resolutionRoot; }
对于您首次描述的场景,正确制定了.When(…)应该有效.
作为.When(…)绑定的替代方法,您还可以使用.Named(“FooBar”)绑定.
然后,计划任务的构造函数需要如下所示:
ctor(Named["FooBar"] DbContext dbContext);
但请注意,这只是(容易)工作,以防您需要将DbContext注入单个构造函数.如果任务具有依赖性,并且这些依赖性也需要相同的DbContext实例,那么它会有点过时.
由于您更新了答案并说是这种情况,我建议采用完全不同的方法:使用请求参数作为When(…)条件与InCallScope绑定相结合的基础.请参阅下面的示例.
支持自己,这是代码:)实现需要ninject.extensions.NamedScope扩展(nuget).
我还使用xUnit和FluentAssertions nuget包来执行测试.
public class Test { // the two implementations are just for demonstration and easy verification purposes. You will only use one DbContext type. public interface IFakeDbContext { } public class RequestScopeDbContext : IFakeDbContext { } public class CallScopeDbContext : IFakeDbContext { } public class SoMetask { public IFakeDbContext FakeDbContext { get; set; } public Dependency1 Dependency1 { get; set; } public Dependency2 Dependency2 { get; set; } public SoMetask(IFakeDbContext fakeDbContext,Dependency1 dependency1,Dependency2 dependency2) { FakeDbContext = fakeDbContext; Dependency1 = dependency1; Dependency2 = dependency2; } } public class Dependency1 { public IFakeDbContext FakeDbContext { get; set; } public Dependency1(IFakeDbContext fakeDbContext) { FakeDbContext = fakeDbContext; } } public class Dependency2 { public IFakeDbContext FakeDbContext { get; set; } public Dependency2(IFakeDbContext fakeDbContext) { FakeDbContext = fakeDbContext; } } public class TaskScheduler { private readonly IResolutionRoot _resolutionRoot; public TaskScheduler(IResolutionRoot resolutionRoot) { _resolutionRoot = resolutionRoot; } public SoMetask CreateScheduledTaskNow() { return _resolutionRoot.Get<SoMetask>(new NonRequestScopedParameter()); } } public class NonRequestScopedParameter : Ninject.Parameters.IParameter { public bool Equals(IParameter other) { if (other == null) { return false; } return other is NonRequestScopedParameter; } public object GetValue(IContext context,ITarget target) { throw new NotSupportedException("this parameter does not provide a value"); } public string Name { get { return typeof(NonRequestScopedParameter).Name; } } // this is very important public bool ShouldInherit { get { return true; } } } [Fact] public void FactMethodName() { var kernel = new StandardKernel(); // this is the default binding kernel.Bind<IFakeDbContext>().To<RequestScopeDbContext>(); // this binding is _only_ used when the request contains a NonRequestScopedParameter // in call scope means,that all objects built in the a single request get the same instance kernel.Bind<IFakeDbContext>().To<CallScopeDbContext>() .When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any()) .InCallScope(); // let's try it out! var task = kernel.Get<SoMetask>(new NonRequestScopedParameter()); // verify that the correct binding was used task.FakeDbContext.Should().BeOfType<CallScopeDbContext>(); // verify that all children of the task get injected the same task instance task.FakeDbContext.Should() .Be(task.Dependency1.FakeDbContext) .And.Be(task.Dependency2.FakeDbContext); } }
正如您所说,由于任务调度程序不使用IoC来创建任务,因此它只支持无参数构造函数.在这种情况下,您可以使用DependencyResolver.Current(但请注意,我不是asp.net / MVC的专家,所以我没有声称这是线程安全或100%可靠地工作):
public class TaskExecutor : ITask { public TaskExecutor() : this(DependencyResolver.Current.GetService<IResolutionRoot>()) {} internal TaskExecutor(IResolutionRoot resolutionRoot) { this.resolutionRoot = resolutionRoot; } public void Execute() { IFooTask actualTask = this.resolution.Get<IFooTask>(new NonRequestScopedParameter()); actualTask.Execute(); } }