无法获取Ninject ConstructorArgument的值(作为参数传递给kernel.Get) [英] Can't get value of Ninject ConstructorArgument (passed in as parameter to kernel.Get)

查看:267
本文介绍了无法获取Ninject ConstructorArgument的值(作为参数传递给kernel.Get)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将ConstructorArgument参数的值传递给kernel.Get()时遇到麻烦。我想使用参数的值来确定将两个字符串值中的哪一个传递给构造函数。这个参数实际上是在预期的时候,我只是不能得到它的价值。调用参数的GetValue方法后,我会得到一个空参数异常:

Having trouble getting the value of a ConstructorArgument parameter passed to kernel.Get(). I want to use the parameter's value to determine which of two string values will be passed into the constructor. The parameter is in fact there when expected, I just can't get at its value. I end up with a null ref exception after calling the parameter's GetValue method:

namespace MyNS.DBProviders {
    public abstract class DBProviderBase {
        private ObjectContext _db;

        public DBProviderBase(ObjectContext db) {
            _db = db;
        }

        ...
        //abstract methods here
        ...
    }

    public class DBProviderB : DBProviderBase {
        public DBProviderB(ObjectContext db) : base(db) {}
        //implementation details... applies to two DBs w/ same schema
    }

    public class DBProviderModule : NinjectModule {
        public override void Load() {
            //Bind DB providers
            Bind<DBProviderBase>().To<DBProviderB>();

            //Bind LINQ contexts to DB providers
            Bind<ObjectContext>().To<EF_DB_b>()
                .When(UseEF_DB_b_conn1).WithConstructorArgument(
                    "connectionString"
                    , ConfigurationManager.ConnectionStrings["EF_DB_b_conn1"]
                        .ToString()
                )
            ;
            Bind<ObjectContext>().To<EF_DB_b>()
                .When(UseEF_DB_b_conn2).WithConstructorArgument(
                    "connectionString"
                    , ConfigurationManager.ConnectionStrings["EF_DB_b_conn2"]
                        .ToString()
                )
            ;
        }

        public static bool UseEF_DB_b_conn1(IRequest req) {
            string idNum = (string)req.Parameters.First(
                p => p.Name == "idNum"
            ).GetValue(null, null);
            //NULL REF EXCEPTION

            return x != null ?  idNum.Substring(0, 1) == "2" : false;
        }

        public static bool UseEF_DB_b_conn2(IRequest req) {
            return !UseEF_DB_b_conn1(req);
        }
    }
}

namespace MyNS {
    public static class DBProviderFactory {

        public static DBProviderBase GetDBProvider(string idNum) {
            var kernel = new Bootstrapper().Kernel;

            return kernel.Get<DBProviderBase>(
                new ConstructorArgument("idNum", idNum)
            );
        }
    }
}

...//idNum received from elsewhere
var db = DBProviderFactory.GetDBProvider(idNum);
var something = db.GetSomethingFromOneOfThreeDBs();


推荐答案

编辑:你的意见和编辑,我重新制定了答案。下面的建议只是一个办法。我正在实现一个提供者< ObjectContextFactory> ,它将使用 kernel.Get< ObjectContextFactory>()。此参数与构造函数无关,仅用作上下文变量,以便您可以决定如何处理。

After your comments and edits, I've reformulated the answer. The suggestion below is just one way to go about this. I'm implementing a Provider<ObjectContextFactory> that will inspect the parameter sent to the request when using kernel.Get<ObjectContextFactory>(). This parameter has nothing to do with constructor, it is only used as a "context variable" so you can decide what to do with it.

这是代码: / p>

Here is the code:

public class ObjectContextFactory
{
    private readonly string _idNum;
    private readonly IResolutionRoot _container;

    public ObjectContextFactory(IResolutionRoot container, string idNum)
    {
        _container = container;
        _idNum = idNum;
    }

    public ObjectContext CreateObjectContext()
    {
        //Use _idNum here as you wish, here is a sample implementation
        ConstructorArgument constructorArgument;
        if (_idNum.Substring(0,1) == "2")
        {
            constructorArgument = new ConstructorArgument("connectionString", "your conn string 1");
        }
        else
        {
            constructorArgument = new ConstructorArgument("connectionString", "your conn string 2");
        }

        return _container.Get<ObjectContext>(constructorArgument);
    }
}

public class ObjectContextFactoryProvider : Provider<ObjectContextFactory>
{
    protected override ObjectContextFactory CreateInstance(IContext context)
    {
        var idNum = context.Parameters.FirstOrDefault(p => p.Name == "idNum");
        var idNumValue = idNum.GetValue(context, null) as string;

        var factory = new ObjectContextFactory(context.Kernel, idNumValue);
        return factory;
    }
}

绑定:

public override void Load()
{
    Bind<DBProviderBase>().To<DBProviderB>();
    Bind<ObjectContextFactory>().ToProvider<ObjectContextFactoryProvider>();
}

检索出厂时:

var factory = kernel.Get<ObjectContextFactory>(new Parameter("idNum", "1", true));

实现此目的的另一种方法是通过命名绑定。只需要将您的 idNum 中的一种翻译器转换为字符串(或直接使用它),并在获取实例时调用它。

Another way to achieve this would be via Named Bindings. Just do a kind of translator from your idNum to a string (or use it directly) and call it when getting an instance.

这篇关于无法获取Ninject ConstructorArgument的值(作为参数传递给kernel.Get)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆