Search code examples
c#wpfentity-frameworkdatetimetry-catch

How to check a date to make sure it is not in the future tense without dropping the app on WPF with EF


I have an app that maintains the database which contains people with their data. Like phone number, date of birth, address etc. I want to fix one of the bugs... I need to add only existing date of birth(the date must not be in the future tense and must correspond to the required format (format 01.01.0101 drops the app P.S this one is example). I know how to do these restrictions/checks and validate the data, but i have one big problem - my app drops when i throwing the exception... The try-catch construction does not help

this code checks the date of birth so that it cannot be in the future:

private DateTime _dateOfBirth;
public DateTime DateOfBirth
{
    get { return _dateOfBirth; }
    set
    {
        try
        {
            if (DateOfBirth > DateTime.Now)
            {
                throw new Exception("Дата рождения не может быть в будущем.");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Произошла ошибка при записи в базу данных: " + ex.Message);
        }
    }
}

I enter a date in the future and shows an error that the application will be closed for an unknown reason First eception Second exception

This is the WPF app with EF. I am started learning it an dont know how to handle these exceptions..

I tried to use the try-catch construct, but it didn't help Also tried to use a global error handler, but its not working too.

public App()
    {
        this.DispatcherUnhandledException += OnDispatcherUnhandledException;
        AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;
        TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
    }

    void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
    {
        MessageBox.Show("Необработанное исключение: " + e.Exception.Message, "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
        e.Handled = true;
    }

    void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        MessageBox.Show("Необработанное исключение: " + ((Exception)e.ExceptionObject).Message, "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
    {
        MessageBox.Show("Необработанное исключение: " + e.Exception.Message, "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
        e.SetObserved();
    }

Solution

  • You don't seem to set _dateOfBirth at all. So it is always DateTime.MinValue (Jan 1st 0001 0:00:00), which is an illegal value for MS-SQL-Server datatype DATETIME.

    Also you don't notify by raising PropertyChanged. If I were you I'd check the data input to comply to Sql-Server DATETIME value range, make the field/Property nullable - also in the DataBase, just show a MessageBox without try-catch, and raise a property change when value has been set.

    private const DateTime _sqlServerDateMin = new DateTime (1753, 1, 1);
    
    private DateTime? _dateOfBirth;
    public DateTime? DateOfBirth
    {
        get => _dateOfBirth;
        set
        {
            if (value > DateTime.Now)
            {
                // consider communicating input errors with IDataErrorInfo and Validation.ErrorTemplate
                MessageBox.Show("Произошла ошибка при записи в базу данных: " + ex.Message);
                return;
            }
            if (value < _sqlServerDateMin)
            {  
                value = null;
            }
            if (!Nullable.Equals(value, _dateOfBirth))
            { 
                _dateOfBirth = value;
                RaisePropertyChanged();
            }
        }
    }
    // usually in ViewModel base class:
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void RaisePropertyChanged([CallerMemberName] propertyName = "") {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
    }