2

I'm studding MVVM in C#.

I want to use Inversion of Control (IoC). I use the framework Unity.

I don't understand how to handling exception that could be raised from Data Access Layer.

Here a little easy example I do for study:

-- i have omitted the manage of Model validation (IDataErrorInfo) and Services for ViewModel (ex: DialogService) --

XAML View

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

DESIGN APPLICATION

Design Application

MODEL

{
    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));
            }
        }
    }
}

DATA ACCESS LAYER

Interface

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

Concrete class

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

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

BUSINESS LAYER

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; 
        }
    }

}

VIEWMODEL

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;
}

APPLICATION

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();
    }
}

Principles follow

So I have a problem that I don't understands how to solve:

  • 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)
  • 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)

Please, have someone a clean solution for this problem?

Thanks!

devdigital
  • 34,151
  • 9
  • 98
  • 120
Caesar
  • 281
  • 4
  • 13

1 Answers1

0

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)

I'm not sure what you mean by 'in could not manage it (catch by Unity container)', as I would only expect a wrapped Unity exception if there was a problem constructing the types that Unity is resolving. Either way, you would still be able to handle the exception yourself. You would probably want to do this in your presentation layer, so that you could bring up a dialog etc.

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)

Yes, if you've handled the error in your business layer, then you would need to guard against the User property being null.

However, I think your approach should be reconsidered. Your IDataAccessLayer and BusinessLayer types seem like big dependencies which is going to minimise the amount of code reuse, as well as making unit testing more difficult.

You should try and minimise the dependencies. If your view model is only interested in users for example, then you could use the repository pattern (well really a data access object pattern) to inject a user repository.

Alternatively if you wish to use rich business objects, then your view models would take your user business object as the dependency. You may then decide to expose the model directly to the view, depending on if you wish to violate the DRY principle (which you are currently doing), or the Law of Demeter.

I would also consider using an MVVM framework if you're using the MVVM design pattern.

devdigital
  • 34,151
  • 9
  • 98
  • 120
  • Thanks for your answer. I try to catch unity exception, but isn't possible during loading ([link]http://stackoverflow.com/questions/7165439/unity-wraps-exception-to-the-resolutionfailedexception-how-to-avoid[link]) In the small project I have in mind, I will reuse the BusinessLayer between several ViewModel. In that small project the DataAccessLayer will be a Repository (a DAO with DDD). But also if I use a direct connection between Repository (past by DI) and ViewModel, when View request the Properies, if there has been problem during load of data I could not handling it. – Caesar Jun 09 '13 at 13:43
  • Because I'm studing MVVM I don't use a framework for not hiding part of design. But for real implementation I will. Thanks for suggestion – Caesar Jun 09 '13 at 13:44
  • You could re-architect your code so that the data access is performed when the view is activated, rather than during the binding stage. This would allow you to handle any repository/unit of work exceptions and also allow you to pop up busy indication etc. if the process is lengthy. – devdigital Jun 09 '13 at 14:37