20

我真的很想将SharpRepositoryNinject一起使用,但我不明白如何配置 Ninject 以在存储库之间共享 Entity Framework DbContext。

我正在使用实体框架版本 5 和 Ninject 版本 3。

目前我Ef5Repository在我的源代码中使用,但我想用ConfigurationBasedRepository. 但我无法弄清楚如何将 EF 传递(或注入)DbContext到存储库。

示例(当前状态):

using SharpRepository.Repository;

public interface IProductRepository : IRepository<Product>
{
}

using SharpRepository.Ef5Repository;
using System.Data.Entity;

// TODO Tightly coupled to Ef5Repository.
public class ProductRepository : Ef5Repository<Product>, IProductRepository
{
    // TODO The DbContext has to be injected manually.
    public ProductRepository(DbContext context) : base(context)
    {
    }

    // [...]
}

目标:

using SharpRepository.Repository;

public interface IProductRepository : IRepository<Product>
{
}

public class ProductRepository : ConfigurationBasedRepository<Product, int>, IProductRepository
{
    // [...]
}

我已经阅读了两篇博客文章SharpRepository: Getting StartedSharpRepository: Configuration,但它们都对我没有帮助,因为:

  1. 使用的 DIC 是 StructureMap,而不是 Ninject。
  2. 源代码示例不完整(例如使用未声明的变量)。

所以我的问题:有人可以为我提供一些源代码示例如何实现上述目标(DbContext在所有扩展的存储库之间共享一个实体框架实例ConfigurationBasedRepository)吗?

4

2 回答 2

16

首先,您需要安装SharpRepository.Ioc.Ninject NuGet 包。这里有一些扩展方法用于连接 Ninject 以处理加载通用存储库并设置 SharpRepository 使用的依赖解析器。

无论您在哪里设置 Ninject 绑定规则(所有对 kernel.Bind<> 的调用),您都需要添加:

kernel.BindSharpRepository();

接下来,在您的 Global.asax、App_Start 代码或 Bootstrapper 逻辑(无论您在哪里调用应用程序启动代码)中,您需要添加以下内容:

// kernel is the specific kernel that you are setting up all the binding for
RepositoryDependencyResolver.SetDependencyResolver(new NinjectDependencyResolver(kernel));

这将告诉 SharpRepository 在获取新的 DbContext 时使用此 Ninject Kernel。

最后要做的是为 DbContext 本身设置绑定规则。如果您在 Web 应用程序中,您很可能希望 DbContext 的范围是每个请求。我个人不使用 Ninject,但我找到了使用InRequestScope的参考。我相信你的代码看起来像这样:

kernel.Bind<DbContext>().To<MyCustomEfContext>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["MyCustomEfContext"].ConnectionString);

大多数人不需要下一部分,但如果您的 CustomEfContext 中有自定义逻辑(例如,我有一个用于登录 SaveChanges() 调用的覆盖),那么您需要在配置文件中定义您的自定义上下文类型像这样:

<repositories>
  <repository name="ef5Repository" connectionString="CustomEfContext" cachingStrategy="standardCachingStrategy" dbContextType="My.Data.CustomEfContext, My.Data" factory="SharpRepository.Ef5Repository.Ef5ConfigRepositoryFactory, SharpRepository.Ef5Repository" />
</repositories>

其中 dbContextType 使用完整类型命名空间语法定义您正在使用的自定义 DbContext 的类型。如果这样做,则需要通过将 .Bind<DbContext>() 更改为 .Bind<CustomEfContext>(),将 Ninject 设置为在自定义上下文中绑定。但就像我通常所说的那样,您可以直接使用 DbContext 而不会出现问题。

于 2013-04-23T16:15:30.320 回答
6

首先,Jeff T 在答案中提供的解决方案有效!

我将总结我为使Ninject在 ASP.NET MVC 4 + EF 5 项目中工作所采取的步骤。值得一提的是,在以下示例中,特定存储库模式是通过SharpRepository实现的。


所需软件

  1. 通过NuGet安装Ninject和“Ninject.MVC3”(也安装“Ninject.Web.Common”)。
  2. 通过NuGet安装SharpRepository、“SharpRepository for EF5”和“SharpRepository with Ninject IOC” 。

定义存储库

  1. 创建一个DbContext 派生类,例如Domain.EfContext。它是

    “推荐的使用上下文的方式”。

    • 将所有必需的声明DbSet<T>为公共属性,例如public DbSet<Product> Products { get; set; }
    • 在类中声明以下两个构造函数Domain.EfContext

      public EfContext() : base() {}
      public EfContext(string connectionName) : base(connectionName) {}
      

  2. 为特定存储库定义一个接口,例如:

    // TODO By extending IRepository, the interface implements default Create-Read-Update-Delete (CRUD) logic.
    // We can use "traits" to make the repository more "specific", e.g. via extending "ICanInsert".
    // https://github.com/SharpRepository/SharpRepository/blob/master/SharpRepository.Samples/HowToUseTraits.cs
    public interface IProjectRepository : IRepository<Project>
    {
        // TODO Add domain specific logic here.
    }
    
  3. 定义一个实现特定存储库并继承自的类SharpRepository.Repository.ConfigurationBasedRepository<T, TKey>,例如:

    public class ProductRepository : ConfigurationBasedRepository<Product, int>, IProductRepository
    {
        // TODO Implement domain specific logic here.
    }
    

定义消费者

  1. 创建一个控制器,例如Controllers.ProductController.

    public class ProductController : Controller
    {
        private IProductRepository Repository { get; private set; }
    
        // TODO Will be used by the DiC.
        public ProductController(IProductRepository repository)
        {
            this.Repository = repository;
        }
    }
    

通过依赖注入容器 (DiC) Ninject 设置依赖注入 (DI)

该文件App_Start/NinjectWebCommon.cs由 Ninject.Web.Common 自动创建,我们可以RegisterServices(IKernel kernel) : void在类的方法中加载我们的模块并注册我们的服务NinjectWebCommon。以下是该示例方法的完整源代码:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.BindSharpRepository();
        RepositoryDependencyResolver.SetDependencyResolver(
            new NinjectDependencyResolver(kernel)
        );

        string connectionString = ConfigurationManager.ConnectionStrings["EfContext"].ConnectionString;
        kernel.Bind<DbContext>()
            .To<EfContext>()
            .InRequestScope()
            .WithConstructorArgument("connectionString", connectionString);

        kernel.Bind<IProductRepository>().To<ProductRepository>();
    }

在 中定义以下sharpRepository部分Web.config

    <sharpRepository>
        <repositories default="ef5Repository">
            <repository name="ef5Repository"
                connectionString="EfContext"
                cachingStrategy="standardCachingStrategy"
                dbContextType="Domain.EfContext, Domain"
                factory="SharpRepository.Ef5Repository.Ef5ConfigRepositoryFactory, SharpRepository.Ef5Repository"
            />
        </repositories>
    </sharpRepository>

此外,connectionStrings使示例完整的部分(我使用的是 SQL Server LocalDB)。

    <connectionStrings>
        <add name="EfContext" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=Domain;Integrated Security=True" />
    </connectionStrings>

我希望这个结论可以帮助其他人将 ASP.NET MVC 4 与 Entity Framework 5 和 SharpRepository 一起启动并运行!

如果我采取了一个或多个不必要的步骤,或者如果您看到改进示例中描述的架构的可能性,请给我回复。

顺便说一句,我必须dbContextType属性添加到该repository部分以使其工作(与 Jeff T 的答案相反)。


编辑(2013-08-28):删除了不必要的步骤(最新版本的 SharpRepository 不需要)。

于 2013-04-25T09:41:01.250 回答