我正在用 C# 研究 MVVM。
我想使用控制反转 (IoC)。我使用框架 Unity。
我不明白如何处理可能从数据访问层引发的异常。
这里是我为学习做的一个简单的例子:
-- 我省略了模型验证管理 (IDataErrorInfo) 和 ViewModel 服务(例如:DialogService)--
XAML View
<TextBox ... Text="{Binding Path=Id}" />
<TextBox ... Text="{Binding Path=Name}"/>
设计应用
模型
{
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();
}
}
遵循原则
- 简单的构造函数(Unity 捕获所有异常并遵循 http://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple/ )
- ViewModel 必须隐藏模型结构
所以我有一个我不明白如何解决的问题:
- 如果在加载 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。
但是,我认为您的方法应该重新考虑。您的 IDataAccessLayer
和 BusinessLayer
类型看起来像是很大的依赖项,这将最大限度地减少代码重用量,并使单元测试更加困难。
您应该尽量减少依赖性。例如,如果您的 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/