Dependency injection Ninject条件自绑定更改范围(用于任务计划程序)工作不正常?

Dependency injection Ninject条件自绑定更改范围(用于任务计划程序)工作不正常?,dependency-injection,ninject,inversion-of-control,ninject.web.mvc,ninject-extensions,Dependency Injection,Ninject,Inversion Of Control,Ninject.web.mvc,Ninject Extensions,在MVC Web应用程序中,DbContext绑定可以与InRequestScope()一起正常工作 **也许我错过了一些东西。我需要帮助 代码片段已更新 #region Commented Code public EmailTask() : this ( DependencyResolver.Current.GetService<IMessageManager>(), , DependencyResolver.Current.GetService<IUnitOfWork

在MVC Web应用程序中,DbContext绑定可以与
InRequestScope()一起正常工作

**也许我错过了一些东西。我需要帮助

代码片段已更新

#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());
        }
}
Ninject绑定语法

protected void Application_Start()
{
   /* intialize Task */
            TaskConfig.Init();

            TaskManager.Instance.Initialize(TaskConfig.ScheduleTasks);
            TaskManager.Instance.Start();
}
kernel.Bind<DbContext>().ToSelf().InRequestScope(); // Default bind

kernel.Bind<DbContext>().ToSelf()
                  .When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
                  .InCallScope();  // For Scheduler
问题5:我可以在这里解析任务调度器(IResolutionRoot resolutionRoot)

已解决

#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());
        }
}
public ExecuteEmailTask():
这(DependencyResolver.Current.GetService())

 public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { }

        public ExecuteEmailTask(IResolutionRoot resolutionRoot)
        {
            _resolutionRoot = resolutionRoot;
        }

首先,您应该注意到,
InSingletonScope()
对于DbContext的/Sessions通常是个坏主意。如果其他服务同时更改数据,会发生什么情况?我建议调查这有什么影响


对于您第一次描述的场景,正确制定的
.When(…)
应该可以工作

作为
.When(…)
绑定的替代方法,您还可以使用名为(“FooBar”)的
.binding。
计划任务的构造函数需要如下所示:

ctor(Named["FooBar"] DbContext dbContext);
但是,请注意,只有在需要将
DbContext
注入单个构造函数的情况下,这才(容易)起作用。如果任务具有依赖项,并且这些依赖项也需要相同的
DbContext
实例,那么它就有点麻烦了

由于您更新了答案并说情况就是这样,我建议使用完全不同的方法:使用请求参数作为
When(…)
条件与
InCallScope
绑定的基础。请参见下面的示例

振作起来,这是一段代码:)实现需要ninject.extensions.NamedScope扩展()。 我还使用了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);
    } 
}

是的
.Named()
是一个很好的方法,我也这么认为。但是,
.InCallScope()
它是如何与调度程序任务一起工作的,这需要检查。我也更新了我的帖子。BatteryBackupUnit:我更新了我的代码,需要你的建议。任务未执行。您好,获取了您的概念
Ninject.Parameters.ipParameter
以强制将IFakeDbContext加载到
InCallScope()
。我更新了我的postBatteryBackupUnit:好的。最终我解决了它。我更新我的帖子。感谢您的帮助空EmailTask构造函数用于什么?你试过移除它吗?我不知道web是如何实例化的,所以我不知道这是否是一个问题。你可以发布(上传,链接)一个最小的解决方案,这样我就可以解决这个问题了吗?不需要实际的DbContext,只需要一些空的FakeDbContext类,…我可以理解为什么它不起作用
DbContext
被注入到
IUnitOfWork
,而不是直接注入
EmailTask
。因此,您必须相应地调整
.When()
。但也有其他方法。一些更具可扩展性;-)如果您提供了一个带有调度器的演示解决方案(如前所述,仅限于假DbContext),我可以看一看。BatteryBackupUnit:empty EmailTask实际上,调用它可以运行任务。我更新我的帖子。在这种情况下,请选择OK-在任务对象图的多个实例中需要使用相同的
DbContext
-我建议使用完全不同的解决方案。但我不知道这对于您正在使用的任务调度器是否可行。任务是如何开始的?BatteryBackupUnit:我更新了我的帖子,看看。您可以了解我的任务调度程序是如何工作的。
 public ExecuteEmailTask() : this(new Bootstrapper().Kernel) { }

        public ExecuteEmailTask(IResolutionRoot resolutionRoot)
        {
            _resolutionRoot = resolutionRoot;
        }
ctor(Named["FooBar"] DbContext dbContext);
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);
    } 
}
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();
    }
}