【问题标题】:How can I specify an argument for the Repository's constructor from the Controller?如何从控制器中为存储库的构造函数指定参数?
【发布时间】:2014-01-05 16:08:23
【问题描述】:

我对@9​​87654321@ 有一个很好的答案,但我不确定我是否可以将该答案应用到我的项目中,因为我显然需要在我的控制器中使用类似这样的代码:

return DBConnectionStrings[DBSpecifier].Get(ID, CountToFetch);

...(其中 DBConnectionStrings 是字典)而不是:

return deptsRepository.Get(ID, CountToFetch);

真正的问题/挑战是我需要我的存储库的构造函数能够接受一个 arg 以便相应地更改数据库连接字符串。然后,这些构造函数可以使用前面文章中建议的 Dictionary ,而不是像这样开始:

public DuckbillRepository()
{
    using (var conn = new OleDbConnection(
        @"Provider=Microsoft.Jet.OLEDB.4.0;User ID=NRBQ;Password=NRBQRotPS;Data 
           Source=C:\Platypus\DATA\PlatypusFlipper03.MDB;Jet OLEDB:System 
           database=C:\Platypus\Data\duckbill.mdw"))
    {

...应该是这样的:

public DuckbillRepository(string DBToUse)
{
    using (var conn = new OleDbConnection(
        string.Format(@"Provider=Microsoft.Jet.OLEDB.4.0;User 
          ID=NRBQ;Password=NRBQRotPS;Data Source=C:\Platypus\DATA\{0}.MDB;Jet 
          OLEDB:System database=C:\Platypus\Data\duckbill.mdw", DBToUse))
    {

但是我怎样才能从控制器中为存储库的构造函数指定一个 arg(用于填充存储库的方法随后查询的数据存储)?目前,典型的 Controller 如下所示:

static readonly IDuckbillRepository duckbillsRepository = new DuckbillRepository();

public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(int ID, int CountToFetch)
{
    return duckbillsRepository.Get(ID, CountToFetch);
}

目前我能想出的最好的想法/最接近的是我需要这样的东西:

public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(string DBInstance, int ID, int CountToFetch)
{
    IDuckbillRepository duckbillsRepository = new DuckbillRepository(DBInstance);
    return duckbillsRepository.Get(ID, CountToFetch);
}

我是在正确的轨道上,还是在找错树?

【问题讨论】:

  • 使用像 NInject 这样的 DI 容器。实际上,通常的做法是将整个存储库对象传递给您的控制器,而不是将 arg 传递给存储库的构造函数。
  • 客户端通过http向控制器传递一个repository对象?这不是问题的过度复杂化,以及对 DRY 的违反以及对服务器特定实现细节的潜在危险传播吗?我不是说你错了,我只是感到惊讶/困惑。
  • 不,客户端将字符串传递给服务器。 NInject 工厂使用字符串实例化一个 repo 并将其传递给控制器​​。

标签: asp.net-mvc asp.net-web-api controller repository asp.net-web-api-routing


【解决方案1】:

我已经制定了一项计划来完成这项工作,但认为它很笨拙,我正在寻找验证(“是的,它很丑,但这就是你所能做的一切”)或更好的想法。

在控制器中,改变这个:

static readonly IDuckbillRepository deptsRepository = new DuckbillRepository();

...到这个:

static readonly IDuckbillRepository deptsRepository = new DuckbillRepository(string siteVal);

在 Repository 中,从这里更改构造函数:

public DuckbillRepository()
{
    using (var conn = new OleDbConnection(
        @"Provider=Microsoft.ACE.OLEDB.12.0;User ID=NRBQ;Password=NRBQ;Data Source=C:\PlatypusFin\DATA\PlatypusDAT03.MDB;Jet OLEDB:System database=C:\PlatypusFin\Data\nrotps.mdw"))
    {
        using (var cmd = conn.CreateCommand())
        {
            . . .

...到这个:

public DuckbillRepository(string siteVal)
{
    string connStr = string.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;User ID=NRBQ;Password=NRBQ;Data Source=C:\PlatypusFin\DATA\{0}.MDB;Jet OLEDB:System database=C:\PlatypusFin\Data\nrotps.mdw", siteVal);
    using (var conn = new OleDbConnection(connStr))
    {
        using (var cmd = conn.CreateCommand())
        {
             . . .

【讨论】:

  • 使用静态 repo 意味着它将在所有线程之间共享 - 这可能不是一个好主意,具体取决于 repo 是否缓存连接(即每次调用都会获取一个新的连接,例如来自一个连接池)。
【解决方案2】:

如果您想避免使用任何 IoC,您有以下选择。

  1. 如果用户只能将dbInstance 指定为方法参数,那么拥有多个DuckbillRepository 类型的构造函数并简单地调用适当的一个就足够了。

    public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(
        string dbInstance, 
        int id, 
        int countToFetch)
    {
        var duckbillsRepository = new DuckbillRepository(dbInstance);
        return duckbillsRepository.Get(id, countToFetch);
    }
    
  2. 如果可以在DuckbillItemsController 的构造函数中获取dbInstance,那么我将实现duckbillRepository 字段并在构造函数中对其进行初始化。

    /// <summary>
    /// Dependency Injection friendly controller.
    /// </summary>
    public class DuckbillItemsController : ControllerBase
    {
        public readonly DuckbillRepository duckbillRepository;
    
        public IEnumerable<Duckbill> GetBatchOfDuckbillsByStartingID(
            int id, 
            int countToFetch)
        {
            return duckbillRepository.Get(id, countToFetch);
        }
    
        /// <summary>
        ///     <see cref="HttpContext.Current"/> can be a source 
        ///     of 'dbInstance' variable.
        /// </summary>
        public DuckbillItemsController()
            : this(HttpContext.Current.Request["dbInstance"])
        {
        }
    
        public DuckbillItemsController(string dbInstance)
            : this(new DuckbillRepository(dbInstance))
        {
        }
    
        public DuckbillItemsController(DuckbillRepository duckbillRepository)
        {
            this.duckbillRepository = duckbillRepository;
        }
    }
    

如果可以使用 IoC,那么您可以在 Castle Windsor IoC 中阅读有关 Passing Arguments 的信息。

var repository = 
    container.Resolve<DuckbillRepository>(new Arguments(new { dbInstance }));

这种方法对于在 组合根,例如您的 Program.Main 方法。虽然它看起来 一开始很简单,实际上经常被新手使用 Windsor,它的适用性一般是相当有限的,其他的 两种方式的使用频率更高。

  1. Registration time - DependsOn 和 DynamicParameters
  2. Resolution time - 类型化工厂

【讨论】:

    猜你喜欢
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 2013-07-01
    • 2016-08-22
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    相关资源
    最近更新 更多