0

无法获取传递给 kernel.Get() 的 ConstructorArgument 参数的值。我想使用参数的值来确定两个字符串值中的哪一个将传递给构造函数。该参数实际上在预期的时候就在那里,我只是无法获得它的值。在调用参数的 GetValue 方法后,我得到了一个 null ref 异常:

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();
4

2 回答 2

2

我需要使用ToMethod()它来访问适当的上下文。

Bind<DBProviderBase>().ToMethod(
    ctx => {
        var idNum = ctx.Parameters.First(p => p.Name == "idNum")
            .GetValue(ctx, null) as string
        ;

        if (idNum == 2) {
            return new DBProviderB(new EF_DBEntities(
                ConfigurationManager.ConnectionStrings["EF_DB_b_conn1"]
            .ToString()));
        } else {
            return new DBProviderB(new EF_DBEntities(
                ConfigurationManager.ConnectionStrings["EF_DB_b_conn2"]
            .ToString()));
        }
    };
);

//later...
var db = kernel.Get<DBProviderBase>(
    new Ninject.Parameters.Parameter("idNum", idNum, true)
);
于 2014-04-02T13:08:11.393 回答
1

编辑:在您的评论和编辑之后,我重新制定了答案。下面的建议只是解决此问题的一种方法。我正在实现一个Provider<ObjectContextFactory>将在使用时检查发送到请求的参数kernel.Get<ObjectContextFactory>()。此参数与构造函数无关,它仅用作“上下文变量”,因此您可以决定如何处理它。

这是代码:

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));

实现此目的的另一种方法是通过Named Bindings。只需将您的字符串转换idNum为字符串(或直接使用它)并在获取实例时调用它。

于 2014-03-31T17:40:05.503 回答