AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX Blogs
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 21.06.2017, 23:18   #1  
Blog bot is offline
Blog bot
Участник
 
25,459 / 846 (79) +++++++
Регистрация: 28.10.2006
goshoom: Catching exceptions in AX 7
Источник: http://dev.goshoom.net/en/2017/06/ca...tions-in-ax-7/
==============

In this blog post, I briefly recapitulate how to throw and catch exceptions in X++ and introduce a new way of handling CLR exceptions in AX 7.

X++ exceptions

When you want to throw an exception in X++, you typically do it by something like this:

throw error("It's broken!");






It’s a functional equivalent of adding a message to infolog and throwing Exception::Error.

infolog.add(Exception::Error, "It's broken");throw Exception::Error; // number 3






As you see, an exception in X++ is (or used to be, as I’ll discuss later) just a number, because enums are backed by integer values. It doesn’t come with any extra information, not even the message. Adding messages to infolog is a separate process; you can add error messages to infolog without throwing any exceptions and throwing exceptions without adding anything to infolog.

When you want to catch an exception, you’ll use a catch clause with the right value of Exception enum (usually Exception::Error) or you’ll handle all exceptions (by a catch clause without any type).

The following statement will work for all errors, but you don’t get any information about what error it was:

catch (Exception::Error) { … }






Just knowing that there is an error doesn’t allow you to react differently to different errors, therefore you’ll rarely see code in AX trying to recover from a particular error.

CLR exceptions (in general)

It’s very different in Common Language Runtime (CLR). Exceptions there are objects (instances of classes extending System.Exception) and they contain a lot of information that can help you to identify what happened. For example, you can look at the type of exception (e.g. ArgumentNullException or FileNotFoundException) and react accordingly. The error message is a part of the object too, not just lying somewhere in infolog. The exception also comes with the stack trace, so you can easily see where it was thrown from.

Because the classes form a hierarchy, you can also handle exceptions in a hierarchic way. This is what you can write in C#:

catch (FileNotFoundException ex) { … }catch (Exception ex) { … }






The system will try catch clauses one by one, going from the top down, and will use the first compatible clause it finds. If a FileNotFoundException is thrown, the first block will be used, but all other exceptions will go to the latter one, because they’re not FileNotFoundException but they’re all compatible with System.Exception, which its their common base class.

Exception::CLRError

Sometimes you have to handle CLR exception in X++, because you can use .NET libraries from X++ and such libraries can throw their usual (CLR) exceptions. The traditional approach is catching Exception::CLRError, getting the exception object from CLRInterop::getLastException() and extracting information from it. It’s further complicated by the fact that the actual error is usually wrapped in TargetInvocationException.

This is how you can handle FileNotFoundException in X++:

try{ System.IO.File::ReadAllText('c:\\nothing.here');}catch (Exception::CLRError){ System.Exception wrapperEx = CLRInterop::getLastException() as System.Reflection.TargetInvocationException; if (wrapperEx) { if (wrapperEx.InnerException is System.IO.FileNotFoundException) { warning(wrapperEx.InnerException.Message); } }}






It works, but it’s cumbersome and hard to understand.

Catch with object reference

Fortunately AX 7 offers a new, much better option. Let me start by refactoring the previous example:

System.IO.FileNotFoundException fileNotFoundEx; try{ System.IO.File::ReadAllText('c:\\nothing.here');}catch (fileNotFoundEx){ warning(fileNotFoundEx.Message);}






This is obviously much shorter and easier to follow. In catch, I don’t have to use only values of the Exception enum anymore, I can also use exception objects. The system checks the type, selects the right catch clause and passes the exception object there. It’s almost the same as in C#, except of the fact that you can’t define the exception type directly in the catch condition; you have to declare a variable in an outer scope.

As in C#, you may have several catch clauses for different types of exceptions and benefit from the hierarchical nature of exception types. For example, the following snippet handles two types of exceptions in a special way and all remaining exceptions go to the last catch clause.

System.Exception generalEx;System.FieldAccessException accessEx;System.IO.FileNotFoundException fileNotFoundEx; try{ …}catch (accessEx){ warning("Field access");}catch (fileNotFoundEx){ warning("File not found");}catch (generalEx){ warning(ex.Message);}






ErrorException

All right, so X++ errors can be caught with catch (Exception::Error) and CLR exceptions by their particular type, but isn’t all code now executed by CLR? Does it mean that X++ exceptions use a different mechanism than CLR exceptions, or they’re just normal CLR exceptions under the hood?

You can find the answer in debugger, which reveals that “native” AX exceptions are indeed implemented as CLR exceptions:



The object (as you can see in debugger) has all usual properties, such as Message, Source, StackTrace and so on. Note that you can see the same behavior in AX 2012 if you debug CIL generated from X++.

Now what if you want to access the properties when handling an exception, e.g. to include the stack trace in a log? If you catch Exception::Error, you won’t get any details, but what if you try to catch ErrorException in the same way as any other CLR exception? If you think it should be possible, you’re right – the following piece of code successfully catches an X++ exception and shows how you can access its properties.

Microsoft.Dynamics.Ax.Xpp.ErrorException xppEx; try{ throw error("It's broken!");}catch (xppEx){ this.log(xppEx.StackTrace);}






The problem that all X++ errors have the same exception type (ErrorException) is still there, therefore handling different errors in different ways is still hard, but you can now easily find which message belongs to the exception (without digging into infolog), where it was thrown from and so on.

By the way, I also wondered what would happen if I tried to catch both Exception::Error and ErrorException, because they’re internally the same thing.

Microsoft.Dynamics.Ax.Xpp.ErrorException xppEx; try { throw Exception::Error;} catch (Exception::Error){ info("Exception::Error");}catch (xppEx){ info("ErrorException");}






Such code compiles without any problem and the resulting CIL will actually contains two catch clauses for the same exception type (ErrorException). It means that the top one always wins, regardless whether it’s catch (Exception::Error) or catch (xppEx). Using both for the same try statement makes little sense, but at least we now know that nothing catastrophic happens if somebody does it by mistake.

Conclusion

The native implementation of exceptions in X++ is very limited in comparison to CLR exceptions. The inability to distinguish between different kinds of errors makes meaningful recovery from errors virtually impossible and the lack of associated information (such as the message) makes even mere logging quite cumbersome. This doesn’t apply to CLR exceptions and their handling in X++ is even easier than before, thanks to the new ability of catch clauses. The fact that we can use this approach for X++ exception as well means that we can easily work around one of the limitations and access properties such as message and stack trace even for them.

It seems that we’re just a small step from being able to work with exceptions in X++ in the same way as in .NET. If we could throw exception objects (e.g. throw new MissingRecordException()), we would be able catch this particular type of exception and implement more robust logic for recovery from errors.

It would also help if X++ was extended to support declaration of the exception type directly in catch (e.g. catch (MissingRecordException ex)).



Источник: http://dev.goshoom.net/en/2017/06/ca...tions-in-ax-7/
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору.
За это сообщение автора поблагодарили: Logger (1).
Старый 22.06.2017, 09:11   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
да, я видел документ со сравнением X++ и C#
да, я понимаю различия. да, я понимаю какой огромный труд был бы при конвертации на c#. да, понимаю авторов документа, которые колебались - переводить платформу на c# или оставить X++ и совместимость.

но иногда мне очень жаль, что таки не перевели на C# сразу, одним махом.
а полной совместимости все равно нет.
__________________
полезное на axForum, github, vk, coub.
Старый 22.06.2017, 11:12   #3  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Кстати, можно в Info.Add() сохранять тип исключения, стек вызовов, текст исключения в переменные класса info.
Тогда даже при исполнении в p-code в большинстве случаев эти сохраненные значения будут доступны из блока Catch. Очень удобно.
Старый 22.06.2017, 11:44   #4  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2922 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Цитата:
Сообщение от mazzy Посмотреть сообщение
но иногда мне очень жаль, что таки не перевели на C# сразу, одним махом.
а полной совместимости все равно нет.
Мне кажется, C# из коробки не потянет Application Suite одним проектом. То есть для практической работы надо либо рефакторить AppSuite либо как-то допиливать C# чтобы он могу работать с такими большими кусками.
Старый 22.06.2017, 12:49   #5  
trud is offline
trud
Участник
Лучший по профессии 2017
 
1,038 / 1629 (57) ++++++++
Регистрация: 07.06.2003
Записей в блоге: 1
а я кстати вообще не понял зачем это сделали, какая цель?
т.е. вот раньше, хочешь вывести ошибку - не настроен какой-то счет при разноске. при выводе ошибки можно указать форму где эти счета настраиваются, т.е. пользователь получив ошибку имеет возможность кликнуть на нее и настроить счет.
теперь это убрали, более того, при открытии новых форм текущий инфолог вообще закрывается, т.е. пользователь его куда-то должен скопировать, чтобы посмотреть что была за ошибка
при этом добавили классы исключения(потратив несомнено огромные усилия), без собственно готовых сценариев использований
Теги
exception

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
goshoom: Code snippets in AX 7 – Introduction Blog bot DAX Blogs 0 29.06.2016 23:13
goshoom: New X++ features in AX 7 Blog bot DAX Blogs 0 19.02.2016 01:13
patrickmouwen: Dynamics AX Retail 3rd party POS and E-commerce integration – Solution Design Blog bot DAX Blogs 0 26.10.2015 12:11
DAX: Official Dynamics AX 2012 R2 Content (update) - Where is it, and how can you find out about updates? Blog bot DAX Blogs 0 03.12.2012 11:11
Arijit Basu: AX 2009 - Quick Overview Blog bot DAX Blogs 4 19.05.2008 14:47
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 21:19.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.