注入属性(递归)而不将其作为参数

时间:2017-04-03 15:12:31

标签: c# asp.net-mvc design-patterns asp.net-mvc-5 ninject

我试图实现可能无法实现的目标。

我们有一个很棒的MVC 5应用程序。我创建了一个小型MVC项目来模拟和解释我想要应用到那个大型MVC项目中的内容。

我有一个具有唯一ID的控制器。在此示例项目中,为每个请求重新生成唯一ID。在MVC项目中,它有点复杂和不同。但是,它与此示例的范围无关。

public class FooController : Controller
{
    public string UniqueId = Guid.NewGuid().ToString("N");
    public ActionResult Index()
    {
        var worker = new WorkerA();
        worker.DoWork();
        return View();
    }
}

FooController创建WorkerA,创建WorkerB,创建WorkerC,依此类推。工人不一样。他们没有相同的界面/实现。为了使示例简单,我使它们看起来很相似。

这里是工人:

public class WorkerA
{
    public string UniqueId = string.Empty;

    public void DoWork()
    {
        var worker = new WorkerB();
        worker.DoWork();
        //...
        //...

    }
}
public class WorkerB
{
    public string UniqueId = string.Empty;

    public void DoWork()
    {
        var worker = new WorkerC();
        worker.DoWork();
    }
}

我希望将属性UniqueId注入到worker中,而不必将其作为参数传递。

我想避免这样做:

public WorkerA(string uniqueId)
{
    UniqueId = uniqueId;
}

但我需要为所有其他工人做同样的事情。

修改

有没有办法用ninject来实现这个目标?

4 个答案:

答案 0 :(得分:1)

您可以通过以下方式使用Microsoft.Practices.Unity实现所需目的:

 public class WorkerA
    {
        [Dependency]
        public string UniqueId { get; set; }

    }

    public class WorkerB
    {
        [Dependency]
        public string UniqueId { get; set; }
    }

之后:

 var container = new UnityContainer();
            container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerA.UniqueId),"WorkerAValue"));
            container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerB.UniqueId), "WorkerBValue"));

稍后,您可以从容器中请求配置了所需属性的实例:

var workerA = container.Resolve<WorkerA>();
var workerB = container.Resolve<WorkerB>();

答案 1 :(得分:0)

您可以执行以下操作:

from tkinter import *

答案 2 :(得分:0)

您可以创建一个单例类来管理GUID并以这种方式将其传递给子类。这样你仍然可以在构造函数中执行它,但不必将其作为参数传递

public class GUIDManager
{

    private static GUIDManager _instance;
    private Guid _activeGuid;

    public Guid ActiveGuid {
        get { return _activeGuid; }
        set { _activeGuid = value; }

    }

    private GUIDManager()
    {
        if (_activeGuid == null)
            _activeGuid = new Guid();
    }

    public static GUIDManager GetInstance()
    {

        if(_instance == null)
        {
            _instance = new GUIDManager();
        }

        return _instance;
    }

}

public class WorkerB
{

    public string UniqueId = string.Empty;

    public WorkerB()
    {
        var manager = GUIDManager.GetInstance();
        UniqueId = manager.ActiveGuid.ToString();
    }

    public void DoWork()
    {
        var worker = new WorkerC();
        worker.DoWork();
    }
}

答案 3 :(得分:0)

根据您的问题,我不完全清楚同一个请求中的所有工作人员是否获得相同的ID。如果他们都应该获得相同的ID,那么这很简单:

将ID包装在课堂中并使用InRequestScope()

public class BrowserTabId 
{
    public string browserTabId;
    public BrowserTabId(string tabId)
    {
        if(string.IsNullOrEmpty(tabId))
        {
            throw new NullArgumentException();
        }
        this.browserTabId = tabId;
    }

    public string Id { get { return this.browserTabId; } }
}

Bind<BrowserTabId>()
    .ToMethod(ctx => 
        new BrowserTabId(HttpContext.Items["BrowserTabId"] as string)))
    .InRequestScope();

出于可测试性原因,您还可以打开接口IUniqueRequestId并为其创建绑定。

这将导致在同一请求期间创建的所有工作人员/对象都收到相同的BrowserTabId。如果您不想使用c-tor注射,可以使用属性注入。如果您不想注入所有类型的值,则使用When(..)条件指定何时注入以及何时不注入。将此与null-object pattern相结合,以防止ninject抱怨它无法注入请求的类型。

物业注入

按如下方式调整工人:

public class WorkerA
{
    [Inject]
    public BrowserTabId BrowserTabId { get; set; }

    ....
 }

但是,请注意,为了使其正常工作,就像正常的构造函数注入一样,有必要由{ninject实例化WorkerA或者通过Ninject.Inject(workerAInstance)

通知Ninject存在它

作用域

由于您提到实际应用程序中ID的生命周期稍微复杂一些,我猜您将不得不使用与InRequestScope不同的内容 - 可能会推出自己的范围(使用InScope(...) )。或许,InCallScope()是可行的选择。但是,如果不知道你需要什么,那么建议你就有点困难了。