Мое мнение таково, что подход MS к локализации свойства сообщения об исключениях совершенно неверен.Поскольку существуют языковые пакеты для .NET Framework, вы получаете из загадочных (например, Mandarin) китайских сообщений об установке.Как я должен отлаживать это как разработчик, который не является носителем языка развернутого продукта?Я бы зарезервировал свойство сообщения об исключении для текста сообщения, ориентированного на технического разработчика, и добавил бы пользовательское сообщение в его свойство Data.
Каждый слой вашего приложения может добавить сообщение пользователя со своей точки зрения к текущему выброшенному исключению.Если вы предполагаете, что первое исключение точно знает, что пошло не так и как это можно исправить, вы должны отобразить первое добавленное сообщение пользователя.Все вышеперечисленные архитектурные уровни будут иметь меньше контекста и знаний о конкретной ошибке нижнего уровня.Это приведет к менее полезным сообщениям об ошибках для пользователя.Поэтому лучше всего создать пользовательское сообщение в слое, где у вас все еще достаточно контекста, чтобы иметь возможность сообщить пользователю, что пошло не так, и если и как это можно исправить.
В качестве иллюстрации приведем программное обеспечение, в котором у вас есть форма для входа, веб-служба, серверная часть и база данных, в которой хранятся учетные данные пользователя.Где бы вы создали пользовательское сообщение при обнаружении проблемы с базой данных?
- Форма входа
- Веб-служба
- Серверная часть
База данныхУровень доступа
- IResult res = WebService.LoginUser ("user", "pwd");
- IResult res = RemoteObject.LoginUser ("user", "pwd");
- string pwd = QueryPasswordForUser ("user");
- User user = NHibernate.Session.Get ("user");-> SQLException выбрасывается
База данных выдает SQLException, поскольку БД находится в режиме сопровождения.
В этом случаеbackend (3) все еще имеет достаточно контекста для решения проблем с БД, но он также знает, что пользователь попытался войти в систему.
Пользовательский интерфейс получит через веб-сервис другой объект исключения, поскольку идентификация типа не можетбыть сохраненным через границы AppDomain / Process.Более глубокая причина заключается в том, что на удаленном клиенте не установлены NHibernate и SQL-сервер, что делает невозможным передачу стека исключений посредством сериализации.
Вы должны преобразовать стек исключений в более общее исключение, которое является частью контракта данных веб-службы, что приводит к потере информации на границе веб-службы.
Если вы попробуете на самом высоком уровне пользовательский интерфейс, попытайтесь сопоставить все возможные системные ошибки с осмысленным пользовательским сообщением, которое вы связываете свою логику пользовательского интерфейса с внутренней работой ваших бэкэндов.Это не только плохая практика, это также трудно сделать, потому что вам будет не хватать контекста, необходимого для полезных пользовательских сообщений.
catch(SqlException ex)
{
if( ex.ErrorCode == DB.IsInMaintananceMode )
Display("Database ??? on server ??? is beeing maintained. Please wait a little longer or contact your administrator for server ????");
....
Из-за границы веб-сервиса в действительности это будет больше похоже на
catch(Exception ex)
{
Excepton first = GetFirstException(ex);
RemoteExcepton rex = first as RemoteExcepton;
if( rex.OriginalType == "SQLException" )
{
if( rex.Properties["Data"] == "DB.IsMaintainanceMode" )
{
Display("Database ??? on server ??? is beeing maintained. Please wait a little longer or contact your administrator for server ????");
Поскольку исключение будет заключено в другие исключения из других уровней, вы кодируете на уровне пользовательского интерфейса внутренние компоненты вашего бэкэнда.
С другой стороны, если вы делаете это на бэкэнд-уровне, вы знаете, какое у вас имя хоста, вы знаете, к какой базе данных вы пытались получить доступ.Все становится намного проще, когда вы делаете это на правильном уровне.
catch(SQLException ex)
{
ex.Data["UserMessage"] = MapSqlErrorToString(ex.ErrorCode, CurrentHostName, Session.Database)'
throw;
}
Как правило, вы должны добавлять свои пользовательские сообщения в исключение в самом глубоком слое, где вы все еще знаете, что пользователь пытался сделать.
Ваш, Алоис Краус