Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于字符串的Ninject绑定_C#_Ninject - Fatal编程技术网

C# 基于字符串的Ninject绑定

C# 基于字符串的Ninject绑定,c#,ninject,C#,Ninject,我有一个web服务,它将处理传入的一些数据(特别是来自SharePoint文档库的InfoPath xml)。我目前正在使用Ninject处理要加载的表单数据“策略”。下面是一些代码(问题如下): Web服务(入口点) FormBStrategy与我没有列出的其他7种策略基本相同。我试图找到一种方法,将表单xml传递给Web服务,并根据即将到来的表单类型调用正确的表单反序列化 上述代码“有效”;但我感觉我在Ninject做某种服务定位,从我的阅读来看,这是一件坏事。但我想不出一个合适的方法来实现

我有一个web服务,它将处理传入的一些数据(特别是来自SharePoint文档库的InfoPath xml)。我目前正在使用Ninject处理要加载的表单数据“策略”。下面是一些代码(问题如下):

Web服务(入口点) FormBStrategy与我没有列出的其他7种策略基本相同。我试图找到一种方法,将表单xml传递给Web服务,并根据即将到来的表单类型调用正确的表单反序列化

上述代码“有效”;但我感觉我在Ninject做某种服务定位,从我的阅读来看,这是一件坏事。但我想不出一个合适的方法来实现这一点。我并没有死心塌地地使用Ninject或任何IOC/DI框架


是我正在做的。。。错了吗?能给我指出正确的方向吗?

有两件事我不喜欢:

  • AddForm
    方法中创建内核。这不应该发生,因为它反转了IoC模式——相反,
    AddForm
    所属的类应该请求它所需的任何依赖项
  • 魔术弦的使用。要求
    AddForm()
    的使用者发送一个命名策略的字符串似乎是不对的
  • 我不太清楚如何解决这个问题;我想到的一件事是将
    Func
    依赖项添加到拥有
    AddForm
    的类中(称之为class X)。我在想象这样的事情:

    namespace Web.Services
    {
        public class X
        {
            private readonly Func<string, IPFormDataStrategy> _strategyResolver;
    
            public X(Func<string, IPFormDataStrategy> strategyResolver)
            {
                _strategyResolver = strategyResolver;
            }
    
            public bool AddForm(XmlDocument form, string formName)
            {
                return _strategyResolver(formName).DoWork(form);
            }
        }
    }
    
    你可能会发现这不必要的复杂,也许它是。。。我喜欢它,因为它使类X的依赖关系显式(即,获取给定表单名称的策略),而不是让它访问整个内核。这种方法还将策略整合到单个switch语句中。它仍然依赖于神奇的字符串,但我不知道如何绕过它,而不知道更多的上下文…

    服务定位器是,但重要的是要理解为什么它是一种反模式。原因通常与重构和类型安全有关。我认为判断你是否做错了事情的最好方法是将问题简化为最简单的要求,然后判断最简单的方法

    据我所知,您的要求是:

  • 在Web服务中接收xml表单数据
  • 根据表单类型,调用适当的逻辑
  • 我还想问你以下问题:

  • 如何识别表单类型?它是xml文档中的一个字段吗?(如果是,请使用该选项)
  • 表单类型是否可能经常更改
  • 归根结底,您必须使用某种标识符。正如@McGarnagle所指出的,魔术字符串可能与代码不同步。您可以使用Strategy类的类型名称,但它也有相同的“可能会失去同步”问题

    如果表单类型不太可能更改,只需使用switch语句并自己实例化策略实例即可。简单性是可维护性的最佳设计模式

    若它们可能会改变,服务定位器就可以工作。如果您的服务定位器实现仅限于此代码,那么维护起来就不会那么糟糕了


    在Ninject上,我不确定这是否仍然有效,但速度要快得多,我更喜欢它的语法。(如果您决定使用DI容器)

    如果您在示例代码中提供的类是准确的(即没有更多的方法和属性)。然后,最简单的解决方案可能会起作用,您可以摆脱许多类/对类的依赖关系

    一个不依赖框架/容器的简单解决方案是:

    public static class FormsProcessing
    {
        private static ConcurrentDictionary<string, Func<FormProcessor>> _registeredProcessors = new ConcurrentDictionary<string, Func<FormProcessor>>();
    
        public delegate bool FormProcessor(XmlDocument form);
    
        public static void RegisterProcessor(string formKey, Func<FormProcessor> formsProcessorFactory)
        {
            _registeredProcessors.AddOrUpdate(formKey, formsProcessorFactory, (k, current) => formsProcessorFactory);
        }
    
        public static FormProcessor GetProcessorFor(string formKey)
        {
            Func<FormProcessor> processorFactory;
            if (_registeredProcessors.TryGetValue(formKey, out processorFactory);
                return processorFactory();
            return null;
        }
    
        public static bool Process(string formKey, XmlDocument form)
        {
            var processor = GetProcessorFor(formKey);
            if (null == processor)
                throw new Exception(string.Format("No processor for '{0}' forms available", formKey));
            return processor(form);
        }
    }
    
    它简单而明确,不需要或公开对
    IPFormDataContext
    IPFormDataStrategy
    类的某些结构的任何依赖。唯一明确的依赖关系是具有
    FormProcessor
    签名的委托

    与容器类似,您需要在以下位置执行注册:

    FormsProcessing.RegisterProcessor("FormA", () => new FormAStrategy().DoWork);
    FormsProcessing.RegisterProcessor("FormB", () => new FormBStrategy().DoWork);
    

    或者,通过扫描约定的程序集(例如接口签名),可以很容易地添加某种形式的(基于约定的)自动注册。

    这似乎是一个通用的好地方:您是否可以执行类似于
    IPFormDataContext的操作,其中T:IPFormDataStrategy
    来清理它?我对ninject不是很熟悉。调用web服务的应用程序是一个SharePoint列表事件处理程序。我想让事件处理程序尽可能的基本,因此是神奇的字符串。该项目的要求包括能够在未来以最小的影响添加其他表单。我可以随时更新web服务,但是升级列表事件处理程序非常痛苦。
    namespace Web.Services
    {
        public class X
        {
            private readonly Func<string, IPFormDataStrategy> _strategyResolver;
    
            public X(Func<string, IPFormDataStrategy> strategyResolver)
            {
                _strategyResolver = strategyResolver;
            }
    
            public bool AddForm(XmlDocument form, string formName)
            {
                return _strategyResolver(formName).DoWork(form);
            }
        }
    }
    
    public class FormsModule : NinjectModule
    {
        public override void Load()
        {
            Bind<FormAStrategy>().ToSelf();
            Bind<FormBStrategy>().ToSelf();
    
            Bind<Func<string, IPFormDataStrategy>>().ToMethod(context => 
                new Func<string, IPFormDataStrategy>(formName => {
                    switch (formName)
                    {
                        case "FormA": 
                            return context.Kernel.Get<FormAStrategy>();
                            // Note, could also simply "return new FormAStrategy()" here.
                        case "FormB": 
                            return context.Kernel.Get<FormBStrategy>();
                        default: 
                            throw new InvalidOperationException(formName + " is unrecognized");
                    }
                })
            );
        }
    }
    
    public static class FormsProcessing
    {
        private static ConcurrentDictionary<string, Func<FormProcessor>> _registeredProcessors = new ConcurrentDictionary<string, Func<FormProcessor>>();
    
        public delegate bool FormProcessor(XmlDocument form);
    
        public static void RegisterProcessor(string formKey, Func<FormProcessor> formsProcessorFactory)
        {
            _registeredProcessors.AddOrUpdate(formKey, formsProcessorFactory, (k, current) => formsProcessorFactory);
        }
    
        public static FormProcessor GetProcessorFor(string formKey)
        {
            Func<FormProcessor> processorFactory;
            if (_registeredProcessors.TryGetValue(formKey, out processorFactory);
                return processorFactory();
            return null;
        }
    
        public static bool Process(string formKey, XmlDocument form)
        {
            var processor = GetProcessorFor(formKey);
            if (null == processor)
                throw new Exception(string.Format("No processor for '{0}' forms available", formKey));
            return processor(form);
        }
    }
    
    namespace Web.Services
    {
        public class MyServiceClass
        {
            public bool AddForm(XmlDocument form, string formName)
            {
                return FormsProcessing.Process(formName, form);
            }
        }
    }
    
    FormsProcessing.RegisterProcessor("FormA", () => new FormAStrategy().DoWork);
    FormsProcessing.RegisterProcessor("FormB", () => new FormBStrategy().DoWork);