依赖注入 – Ninject条件自绑定更改范围(For Task-scheduler)无
在MVC Web应用程序中,DbContext绑定与InRequestScope()正常工作
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)的绑定语法是什么? 问题 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??(): 要么 public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { } public ExecuteEmailTask(IResolutionRoot resolutionRoot) { _resolutionRoot = resolutionRoot; }
首先,你应该注意到InSingletonScope()对于DbContext的/ Sessions来说通常是一个坏主意.如果其他服务在此期间更改数据会发生什么?我建议调查一下这有什么影响.
对于您首次描述的场景,正确制定了.When(…)应该有效. 作为.When(…)绑定的替代方法,您还可以使用.Named(“FooBar”)绑定. ctor(Named["FooBar"] DbContext dbContext); 但请注意,这只是(容易)工作,以防您需要将DbContext注入单个构造函数.如果任务具有依赖性,并且这些依赖性也需要相同的DbContext实例,那么它会有点过时. 由于您更新了答案并说是这种情况,我建议采用完全不同的方法:使用请求参数作为When(…)条件与InCallScope绑定相结合的基础.请参阅下面的示例. 支持自己,这是代码:)实现需要ninject.extensions.NamedScope扩展(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(); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |