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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 27.01.2014, 13:11   #1  
Blog bot is offline
Blog bot
Участник
 
25,475 / 846 (79) +++++++
Регистрация: 28.10.2006
goshoom: Data contract serialization from X++
Источник: http://dev.goshoom.net/en/2014/01/da...serialization/
==============

You can decorate classes in AX2012 with DataContractAttribute in much the same way as in .NET with System.Runtime.Serialization.DataContractAttribute. The same is true also for DataMemberAttribute.

This is a simple data contract class in X++:

[DataContractAttribute]class ItemContract{ str name; [DataMemberAttribute("Name")] public str parmName(str _name = name) { name = _name; return name; }}
In .NET, you can serialize data contracts to XML (and deserialize from XML) with DataContractSerializer. What if you want to do the same with data contracts in X++?

I’m not aware of any such serializer in X++. You could write one, but it wouldn’t be a five-minute job. But there is a way how to actually use the .NET serializer.

As you surely know, AX2012 is able to compile X++ types to the Common Intermediate Language (CIL). Other “.NET” languages are compiled to CIL as well, which allows all of them to work together seamlessly. You can save a class written in a different language to a variable, call its methods, inherit from it and so on. (Don’t worry too much about differences between .NET, CLR, CIL, CLI etc. You just need to know that it’s all related to the same thing, usually called .NET).

When AX2012 generates CIL, .NET types for X++ classes and tables are created in Dynamics.Ax.Application assembly. For example, PriceDisc class is turned to Dynamics.Ax.Application.PriceDisc. If a piece of X++ code is executed in a CLR session, CIL types from Dynamics.Ax.Application are transparently used instead of original X++ types.

However, classes decorated by DataContractAttribute won’t be decorated by Dynamics.Ax.Application.DataContractAttribute in CIL. The X++ attribute is actually replaced by System.Runtime.Serialization.DataContractAttribute, therefore you’ll get a proper .NET data contract that can be serialized by DataContractSerializer. That’s likely what happens somewhere in AX kernel when you pass a data contract with parameters from AX to a report server, for instance.

By the way, I really like this approach. People from Microsoft managed to provide an easy way to define data contracts in X++ and still benefit from everything related to data contracts in .NET. Now it looks like an obvious solution, but who would have thought it about before?

Nevertheless what if we want to use the serializer from our own X++ code? First of all, let me introduce a C# method that will do all the serialization. All we have to do is to pass a data contract and we’ll get back the object serialized to XML.

using System;using System.Runtime.Serialization;using System.IO;using System.Xml; namespace Demo{ public class ContractSerializer { public static string Serialize(Object o) { Type type = o.GetType(); if (!Attribute.IsDefined(type, typeof(DataContractAttribute))) { throw new ArgumentException(String.Format("{0} is not a data contract", type.FullName)); } using (var stringWriter = new StringWriter()) using (var xmlWriter = new XmlTextWriter(stringWriter) { Formatting = Formatting.Indented }) { new DataContractSerializer(type).WriteObject(xmlWriter, o); return stringWriter.GetStringBuilder().ToString(); } } }}
You can put the class to a class library, add it to AOT and deploy it to both client and server.

Then we need to ensure ourselves that our X++ code will run in CIL. We’ll utilize SysOperation framework for that purpose:

class SerializationDemo extends SysOperationServiceController{ public static void main(Args args) { SerializationDemo demo = new SerializationDemo(); demo.parmClassName(classStr(SerializationDemo)); demo.parmMethodName(methodStr(SerializationDemo, serializeToInfolog)); demo.parmExecutionMode(SysOperationExecutionMode::Synchronous); demo.run(); } [SysEntryPointAttribute] public void serializeToInfolog() { if (!xSession::isCLRSession()) { throw error("Must run CIL!"); } // Here we'll do the job }}
Do not omit the verification that we’re really in a .NET session. If the code ran in X++, it wouldn’t work, because we can’t simply pass an X++ object to a .NET method. If the code don’t execute in CIL, go to Tools > Options > Development and tick Execute business operations in CIL. Also, don’t forget to generate CIL.

If we’re in a .NET session, we can simply create an instance of a data contract class and send it to our method. Let’s create some data:

private DirPersonInfoData getPersonData(){ DirPersonInfoData person = new DirPersonInfoData(); person.parmPersonName("John Doe"); person.parmPersonPrimaryEmail("john(at)doe.com"); person.parmPersonUserId("jdoe"); return person;}
Unfortunately, if you try to pass it directly to the serialization method:

DirPersonInfoData person = this.getPersonData();Demo.ContractSerializer::Serialize(person);
it will fail with the error “Microsoft.Dynamics.AX.ManagedInterop.Object is not a data contract”.

The problem here is that the generated code uses a proxy class, which is not what we need, because proxy classes are not generated with attributes. Let’s tell AX that we’re working with a .NET object:

DirPersonInfoData person = this.getPersonData();System.Object clrPerson = CLRInterop::getObjectForAnyType(person);;Demo.ContractSerializer::Serialize(clrPerson);
Now let’s put it together and finalize serializeToInfolog() method by adding exception handling and output to infolog:

[SysEntryPointAttribute]public void serializeToInfolog(){ DirPersonInfoData person = this.getPersonData(); System.Object clrPerson; System.Exception ex; str serialized; if (!xSession::isCLRSession()) { throw error("Must run CIL!"); } try { clrPerson = CLRInterop::getObjectForAnyType(person); serialized = Demo.ContractSerializer::Serialize(clrPerson); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); throw error(ex.ToString()); } info(serialized);}
And this is how DirPersonInfoData will be serialized:

John Doe john(at)doe.com jdoe The fact that the same X++ code can be executed once in a native AX session and once in a CLR session is very powerful and you usually don’t have to care about how it works. Of course, it may be sometimes confusing. For example, you need to know how your code is executed in a given moment to use the right debugger.

Here I showed how to leverage it even more. The solution works because we can define a type in X++ and use it later as a CLR type. But it also depend on the fact how the CIL generator deals with DataContractAttribute, which is something you can only find by looking into CIL. A CIL decompiler comes handy if you want to play with these things.



Источник: http://dev.goshoom.net/en/2014/01/da...serialization/
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору.
Теги
ax2012

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
emeadaxsupport: SEPA affected objects Blog bot DAX Blogs 0 29.11.2013 13:11
dynamicscare: Using Power BI to Analyze Your Dynamics AX Data Blog bot DAX Blogs 1 06.10.2013 18:11
atinkerersnotebook: Using PowerPivot to Analyze Dynamics AX Data Blog bot DAX Blogs 1 05.10.2013 07:23
ax-erp: Walkthrough: Creating a Report Bound to a Report Data Provider Class (X++ Business Logic) [AX 2012] Blog bot DAX Blogs 0 20.09.2012 11:11
Microsoft Dynamics CRM Team Blog: Data Migration Manager Tips and Tricks Blog bot Dynamics CRM: Blogs 0 02.09.2008 22:05

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

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

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