【问题标题】:Pass constructor with Ninject使用 Ninject 传递构造函数
【发布时间】:2013-01-30 22:12:04
【问题描述】:

我有一个基本的通用存储库和许多继承自基本存储库的类存储库。我也需要将字符串值传递给通用存储库。

这是我的通用存储库

public class Repository<T> where T : EntityBase
    {
        private string SessionId;

        public Repository(string sessionId)
        {
            this.SessionId = sessionId;
        }

        protected virtual IDbConnection GetCn()
        {
            return new SqlConnection(ConfigurationManager.ConnectionStrings["SalesDb"].ConnectionString);
        }

        public virtual int Insert(T entity)
        {
            entity.ChUser = "anders.persson";
            entity.ChTime = DateTime.Now;

            using (IDbConnection cn = GetCn())
            {
                cn.Open();

                return cn.Insert(entity);
            }
        }

        // MORE CODE
        }
    }

还有界面

public interface IRepository<T>
{
    int Insert(T entity);

}

我的班级资料库

public class MarketRepository : Repository<Market>, IMarketRepository
    {

    }

还有界面

public interface IMarketRepository : IRepository<Market>
{

}

现在我想将 sessionId 传递给 Generic Repositories 构造函数。 我怎样才能做到这一点。在这种情况下,我必须在每个类存储库中实现一个构造函数并将其传递给基础存储库。而且接口甚至不知道那个构造函数。

这是 Ninject 绑定

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
    kernel.Bind<ILeadRepository>().To<LeadRepository>();
    kernel.Bind<IPricelistRepository>().To<PricelistRepository>();
    kernel.Bind<IOptionalGroupRepository>().To<OptionalGroupRepository>();
    kernel.Bind<IProductGroupRepository>().To<ProductGroupRepository>();
    kernel.Bind<IProductRepository>().To<ProductRepository>();
    kernel.Bind<IMarketRepository>().To<MarketRepository>();
    kernel.Bind<IModelRepository>().To<ModelRepository>();
    kernel.Bind<IOrderRepository>().To<OrderRepository>();
}  

【问题讨论】:

    标签: c# asp.net-mvc ninject


    【解决方案1】:

    您可以将其添加到绑定中:

    Bind<IMarketRepository>().To<MarketRepository>().WithConstructorArgument("sessionId", "Session ID here");
    

    【讨论】:

    • 这会将连接字符串放到“sessionId”参数中,这似乎不正确。这是静态连接字符串的正确解决方案,但那里不知道“sessionId”,因为它是运行时值。
    • 这只是一个示例(使用 OP 识别的代码)。我可能会更新它以随机传递一些东西。此外,OP 没有提到如何找到 sessionId。它可以是任何东西..
    【解决方案2】:

    sessionId 将是一个运行时值,因此您需要在解析时将其传递给 ctor。
    这样做的语法是:

    var reposetory 
        = kernel.Get<IMarketRepository>(new ConstructorArgument("sessionId", sessionId));
    

    鉴于您不想使用Service Locator,直接调用Get,而是使用ctor注入,您可以将其封装在工厂中。

    配置:

    kernel.Bind<IRepositoryFactory>().To<RepositoryFactory>()
          .WithConstructorArgument("kernel", kernel);
    

    工厂:

    public class RepositoryFactory : IRepositoryFactory
    {
        private IKernel _kernel;
    
        public RepositoryFactory(IKernel kernel)
        {
            _kernel = kernel;
        }
    
        public T CreateNew<T>(string sessionId)
        {
            return
                _kernel.Get<T>(new ConstructorArgument("sessionId", sessionId));
        }
    }
    

    用法:

    var repository = _repositoryFactory.CreateNew<IMarketRepository>(sessionId);
    

    【讨论】:

    • 这假定 kernel 正在应用程序周围传递.. 它不应该是。您需要在Composition Root 附近执行此操作。你可以在 Ninject 绑定中做到这一点..
    • @Simon:确实应该是,我还在完成答案的过程中。我不确定您将如何在绑定中执行此操作,因为“sessionId”是运行时值。
    • OP 在哪里说它是运行时值?无论哪种方式,它都可以在运行时静态检索..
    • +1 是一个有趣的解决方案,但不知何故违背了 DI 的目的,因为应用程序与 Ninject 紧密耦合。我会使用WithConstructorArgument 方法。
    • @danradu:谢谢。工厂将与其他 DI 内容和 abstract factories 一起存在于应用程序的 Composition Root 中。应用程序的其余部分不了解工厂实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多