As part of the MVC web application, DbContext works correctly with InRequestScope()
kernel.Bind<DbContext>().ToSelf().InRequestScope(); kernel.Bind<IUnitOfWork<DbContext>>().To<UnitOfWork<DbContext>>();
But from the Task Scheduler, calling DbContext in InRequestScope() failed to update the Db table ( without any error ) until I go to binding to InSingletonScope() OR InThreadScope()
Question:. So they can be changed for the InSingletonScope() / InThreadScope() to call the task scheduler. ?
// For Task Scheduler Call, I tried the binding below, but did not work properly
kernel.Bind<DbContext>().ToSelf() .When(request => request.Target.Type.Namespace.StartsWith("NameSpace.ClassName")) .InSingletonScope();
** And I probably missed something. Help is needed.
Updated code snippet
#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()); } }
In Web.Config
<ScheduleTasks> <Thread seconds="60"> <task name="ExecuteEmailTask" type="namespace.ExecuteEmailTask, AssemblyName" enabled="true" stopOnError="false" maxTries="5"/> </Thread> </ScheduleTasks>
At Global.asax
protected void Application_Start() { TaskConfig.Init(); TaskManager.Instance.Initialize(TaskConfig.ScheduleTasks); TaskManager.Instance.Start(); }
Ninject Binding Syntax
kernel.Bind<DbContext>().ToSelf().InRequestScope(); // Default bind kernel.Bind<DbContext>().ToSelf() .When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any()) .InCallScope(); // For Scheduler
Note: The EmailTask class also has SomeReposity as a constructor argument.
Requests: -
- But what binding syntax
TaskScheduler(IResolutionRoot resolutionRoot) allow? - What is the configuration code to run
TaskScheduler ? - As they say, to put
IFakeDbContext directly into the constructor, can this work with IUnitOfWork<FakeDbContext> ?
Problem
A task that cannot be called using the Overloaded Constructor can only call the TaskScheduler default constructor.
Question 4: Is there any way to call TaskScheduler(IResolutionRoot resolutionRoot) from TaskScheduler default constructor?
Sample code snippet to create a task and run using 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; }
Question 5: Can I enable TaskScheduler(IResolutionRoot resolutionRoot) here?
solvable
public ExecuteEmailTask() : this(DependencyResolver.Current.GetService<IResolutionRoot>())
OR
public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { } public ExecuteEmailTask(IResolutionRoot resolutionRoot) { _resolutionRoot = resolutionRoot; }