加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

依赖注入 – Ninject条件自绑定更改范围(For Task-scheduler)无

发布时间:2020-12-13 20:08:42 所属栏目:百科 来源:网络整理
导读:在MVC Web应用程序中,DbContext绑定与InRequestScope()正常工作 kernel.BindDbContext().ToSelf().InRequestScope(); kernel.BindIUnitOfWorkDbContext().ToUnitOfWorkDbContext(); 但是从任务调度程序调用InRequestScope()中的DbContext无法更新Db表(没有任
在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)的绑定语法是什么?
>运行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;
        }
首先,你应该注意到InSingletonScope()对于DbContext的/ Sessions来说通常是一个坏主意.如果其他服务在此期间更改数据会发生什么?我建议调查一下这有什么影响.

对于您首次描述的场景,正确制定了.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();
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读