c# - 使用控制反转处理 MVVM 中的数据访问层异常

标签 c# mvvm exception inversion-of-control data-access-layer

我正在用 C# 研究 MVVM。

我想使用控制反转 (IoC)。我使用框架 Unity。

我不明白如何处理可能从数据访问层引发的异常。

这里是我为学习做的一个简单的例子:

-- 我省略了模型验证管理 (IDataErrorInfo) 和 ViewModel 服务(例如:DialogService)--

XAML View

<TextBox ...  Text="{Binding Path=Id}" />
<TextBox ...  Text="{Binding Path=Name}"/>

设计应用

Design Application

模型

{
    public class User : INotifyPropertyChanged
    {
        private int _id;
        public int Id
        {
            get{return _id;}
            set
            {
                _id = value;
                this.OnPropertyChanged("Id");
            }
        }

        private string _name;
        public string Name
        {
            get{return _name;}
            set
            {
                _name = value;
                this.OnPropertyChanged("Name");
            }
        }

        public User(int i, string n)
        {
            _id = i;
            _name = n;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

数据访问层

界面

public interface IDataAccessLayer
{
    Model.User GetUser();
}

具体类

public class ConcreteDataAccessLayer : IDataAccessLayer
{
    public ConcreteDataAccessLayer(){}

    Model.User IDataAccessLayer.GetUser()
    {
        //could throw Exception connecting with data source
    }
}

业务层

public class BusinessLayer
{
    public BusinessLayer(IDataAccessLayer dataAccessLayer)
    {
        if (dataAccessLayer == null)        
        {
            throw new ArgumentNullException("dataAccessLayer");
        }
        this._dataAccessLayer = dataAccessLayer;
    }

    private IDataAccessLayer _dataAccessLayer;

    private QuestionStak.Model.User _user;

    internal QuestionStak.Model.User User
    {
        get 
        {
            if (_user == null)
                _user = _dataAccessLayer.GetUser();
            return _user; 
        }
    }

}

View 模型

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel(BusinessLayer bl)
    {
        if (bl == null)
        {
            throw new ArgumentNullException("BusinessLayer");
        }
        _businessLayer = bl;
    }

    private BusinessLayer _businessLayer;


    public int Id
    {
        get
        {
            return _businessLayer.User.Id;
        }
        set
        {
            _businessLayer.User.Id =  value;
        }
    }

    public string Name
    {
        get
        {
            return _businessLayer.User.Name;
        }
        set
        {
            _businessLayer.User.Name =  value;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

应用

public partial class App : Application
{

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        //Inversion of control
        IUnityContainer container = new UnityContainer();

        //Created as singleton
        container.RegisterType<IDataAccessLayer, ConcreteDataAccessLayer>(new ContainerControlledLifetimeManager());
        container.RegisterType<BusinessLayer, BusinessLayer>(new ContainerControlledLifetimeManager());

        MainWindow win = container.Resolve<MainWindow>();

        win.DataContext = container.Resolve<ViewModel>();
        win.Show();
    }
}

遵循原则

所以我有一个我不明白如何解决的问题:

  • 如果在加载 ViewModel 期间 ConcreteDataAccessLayer 无法加载数据(例如:服务器不可用),语句 _dataAccessLayer.GetUser() 将抛出异常并且无法管理它(由 Unity conteiner 捕获)
  • 如果在加载期间某处我管理异常,数据绑定(bind)会导致抛出空异常,因为 _businessLayer.User 为空(无法加载 View )

拜托,有人能解决这个问题吗?

谢谢!

最佳答案

If ConcreteDataAccessLayer can't load data (Ex: server not available) during loading of ViewModel the statement _dataAccessLayer.GetUser() throw the exception and in could not manage it (catch by Unity conteiner)

我不确定您所说的“无法管理它(由 Unity 容器捕获)”是什么意思,因为如果构建 Unity 正在解析的类型时出现问题,我只会期望包装的 Unity 异常。无论哪种方式,您仍然可以自己处理异常。您可能希望在您的表示层中执行此操作,以便您可以调出一个对话框等。

If somewhere during the loading I manage the exception, the data binding cause the throw of a null exception because _businessLayer.User is null (unable to load the view)

是的,如果您已经在业务层中处理了错误,那么您将需要防止 User 属性为 null。

但是,我认为您的方法应该重新考虑。您的 IDataAccessLayerBusinessLayer 类型看起来像是很大的依赖项,这将最大限度地减少代码重用量,并使单元测试更加困难。

您应该尽量减少依赖性。例如,如果您的 View 模型只对用户感兴趣,那么您可以使用存储库模式(实际上是数据访问对象模式)来注入(inject)用户存储库。

或者,如果您希望使用丰富的业务对象,那么您的 View 模型会将您的用户业务对象作为依赖项。然后,您可以决定将模型直接暴露给 View ,具体取决于您是否希望违反 DRY 原则(您目前正在这样做)或 Demeter 法则。

我也会consider using an MVVM framework if you're using the MVVM design pattern .

关于c# - 使用控制反转处理 MVVM 中的数据访问层异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17008796/

相关文章:

c# - 数组中等于 N 的 K 个元素之和

c# - 使用 WqlEventQuery 检测插入的 USB 设备并检索它们的描述信息

c# - 根据其他线程的当前编程计数器锁定线程

c++ - 如何让C++像python一样给出详细的异常信息?

java - 使用 Class.forName 加载类时出现 ClassNotFoundException

c# - 在 C# 中使用 enum 和 struct 代替 switch 语句

c# - 无法更改DataGrid中的前景

c# - MVVM ViewModel 默认构造函数

wpf - 找不到x :Shared in wpf

java - NullPointerException,使用数组预订座位