【问题标题】:Runtime datacontext with Castle Windsor温莎城堡的运行时数据上下文
【发布时间】:2012-05-28 17:12:29
【问题描述】:

我正在努力将 Windsor IoC 容器添加到使用 MVP UI 设计模式的现有 WinForms 应用程序中。我正在尝试确定一种重新注册数据上下文的好方法,该数据上下文取决于运行时提供的连接字符串。问题是在用户选择数据库之前我无法创建数据上下文,即应用程序加载后的“连接字符串”。通常只使用一个数据上下文,但有时用户需要切换到不同的数据库,即创建不同的数据上下文。这也会导致额外的运行时依赖。

public interface IProductsView
{
    event EventHandler<ProductSelectedEventArgs> ProductSelectedEvent;
    event EventHandler<StringEventArgs> ProductStatusEvent;
    void ClearProductList();
    void DisplayProductList(IList<Product> products);
    Control Control { get; }
    IProductsPresenter Presenter { get; set; }
}

public class ProductsPresenter : IProductsPresenter
{
    public IProductsView View { get; set; }
    private IProductRepository Repository { get; set; }

    public ProductsPresenter(IProductsView view, IProductRepository repository)
    {
        View = view;
        View.Presenter = this;
        Repository = repository;
    }

    public void ProductSelected(IList<Product> products)
    {
        throw new NotImplementedException();
    }

    public void ShowProductList(string name)
    {
        IList<Product> productList;

        if (string.IsNullOrEmpty(name))
            productList = Repository.GetProducts();
        else
            productList = Repository.GetProductsByName(name);

        View.DisplayProductList(productList);
    }
}

public class ProductDao : IDisposable, IProductRepository
{
    private MeasurementDataContext dataContext;

    public ProductDao(MeasurementDataContext context)
    {
        dataContext = context;
    }

    public List<Product> GetProducts()
    {
        return dataContext.Products.Select(p => Mapper.Map(p)).ToList().OrderBy(x => x.Name).ToList();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
            if (dataContext != null)
            {
                dataContext.Dispose();
                dataContext = null;
            }
    }

    ~ProductDao()
    {
        this.Dispose(false);
    }
}

所以这意味着我的View 中的Presenter 在创建IProductRepository 之前为空,而这又取决于创建MeasurementDataContext。我在IWindsorInstaller 中注册了这些组件,如下所示:

container.Register(Component.For<IProductsView>()
            .ImplementedBy<ViewProductsControl>());
        container.Register(Component.For<IProductsPresenter>()
            .ImplementedBy<ProductsPresenter>());

我是否需要使用 NamedDependsOn 为每个数据上下文提供唯一的名称和 connectionString 参数?

我目前在用户选择数据库后在运行时注册数据上下文的操作

kernel.Register(Component.For<MeasurementDataContext>()
               .UsingFactoryMethod(() => new MeasurementDataContext(conn)));

然后“解决”我的视图并设置它们的演示者。我知道这不是好的设计,但它是解决我的依赖的蛮力方式。

谢谢

更新:

我将我在安装程序中注册数据上下文的方式更改为:

container.Register(Component.For<DataContext>().ImplementedBy<MeasurementDataContext>().Named("Localhost").DependsOn(new { connectionString = conn }));

然后将我模型的构造函数修改为:

public ProductDao(DataContext context)
    {
        dataContext = context as MeasurementDataContext;
    }

所有组件都将使用右键解析:

kernel.Resolve<DataContext>(cbo.SelectedItem.ToString());

【问题讨论】:

  • 与您的问题无关,但没有理由实现 Dispose 模式的完整终结器版本,因为您只是在释放托管资源。如果你的终结器执行它不会做任何事情(在你的 Dispose() 方法中处理 = false 不会产生任何结果);这只是不必要的性能损失。

标签: winforms dependency-injection inversion-of-control castle-windsor ioc-container


【解决方案1】:

注入一个包装类来保存连接字符串并让数据上下文对象使用它呢?大致如下:

public class ConnectionStringProvider : IConnectionStringProvider
{
    private string _value;

    public event EventHandler ConnectionStringChanged;

    public string ConnectionString
    {
        get { return _value; }
        set
        {
            _value = value;

            var del = ValueChanged;
            if (del != null)
                del(this, EventArgs.Empty);
        }
    }
}

以单身生活方式注册。这样,您的应用程序可以设置或更新单个对象上的连接字符串,并且依赖它的每个人都会收到更改通知。

【讨论】:

  • 感谢您的建议!我结束了更改我在安装程序中注册数据上下文的方式,如上面我编辑的帖子所示。
  • 我不确定如何注册我的数据上下文,因此它取决于包装类。你有例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多