问题
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();
回答1:
Edit: 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.
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;
}
}
And the bindings:
public override void Load()
{
Bind<DBProviderBase>().To<DBProviderB>();
Bind<ObjectContextFactory>().ToProvider<ObjectContextFactoryProvider>();
}
When retrieving the factory:
var factory = kernel.Get<ObjectContextFactory>(new Parameter("idNum", "1", true));
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.
回答2:
I needed to use ToMethod()
to get access to the appropriate context.
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)
);
来源:https://stackoverflow.com/questions/22766200/cant-get-value-of-ninject-constructorargument-passed-in-as-parameter-to-kernel