Passing CLR-object between an Ax-client and the AOS

As explained on msdn you can’t pass an CLR-object between a Ax-client and the AOS. So the following example will work for the client-to-client but will fail for the client-to-server scenario:

The code for the CLR-class:

    1:  using System;
    2:   
    3:  namespace Samples
    4:  {
    5:      public class Customer
    6:      {
    7:          private string _name;
    8:   
    9:          [XmlElement("Name")]
   10:          public string Name
   11:          {
   12:              get { return _name; }
   13:              set { _name = value; }
   14:          }
   15:      }
   16:  }

And the X++ for Dynamics Ax 2009:

    1:  public static void main(Args _args)
    2:  {
    3:      Samples.Customer c;
    4:      ;
    5:   
    6:      c = new Samples.Customer();
    7:      c.set_Name("sample Name");
    8:      A02::clt_Call(c);
    9:      A02::srv_Call(c);
   10:  }
   11:   
   12:  public static client void  clt_Call(Samples.Customer customer)
   13:  {
   14:      str name;
   15:      boolean isInitialized;
   16:      boolean isNull;
   17:      ;
   18:   
   19:      isInitialized = CLRInterop::isInitialized(customer);
   20:      isNull = CLRInterop::isNull(customer);
   21:   
   22:      if (!isNull)
   23:      {
   24:          name =  customer.get_Name();
   25:          print name;
   26:      }
   27:  }
   28:   
   29:  public static server void srv_Call(Samples.Customer customer)
   30:  {
   31:      str name;
   32:      boolean isInitialized;
   33:      boolean isNull;
   34:      ;
   35:      new InteropPermission(InteropKind::ClrInterop).assert();
   36:      isInitialized = CLRInterop::isInitialized(customer);
   37:      isNull = CLRInterop::isNull(customer);
   38:   
   39:      if (!isNull)
   40:      {
   41:          name =  customer.get_Name();
   42:          print name;
   43:      }
   44:  }
   45:   

So the client-call (line 8) will succeed, while the call to the server will fail. I added a null-verification to the server-call (line 37) because as we saw in the msdn-article Ax can’t pass CLR-objects between different tiers. This is not very surprising, since you have to serialize and deserialize in order to pass complex class between tires, and that is not done automatically for CLR-classes by Ax for you. If you now need to pass such kind of object between tires nevertheless, there is fortunately a solution: You can serialize your class to XML by using the System.Xml.Serialization.XmlSerializer and then pass the object as Xml-text across the tire. Unfortunately this isn’t possible for all CLR-objects (especially for complex collections) but it’s a solution that works for most cases.

Here’s the modified code for this scenario:

    1:  public static void main(Args _args)
    2:  {
    3:      Samples.Customer c;
    4:      System.Xml.Serialization.XmlSerializer serializer;
    5:      System.IO.StringWriter xml = new System.IO.StringWriter(new System.Text.StringBuilder());
    6:      str xmlText;
    7:      ;
    8:   
    9:      c = new Samples.Customer();
   10:      c.set_Name("sample Name");
   11:      A02::clt_Call(c);
   12:      //A02::srv_Call(c);
   13:      
   14:      serializer = new System.Xml.Serialization.XmlSerializer(c.GetType());
   15:      serializer.Serialize(xml, c);
   16:      xmlText = xml.ToString();
   17:      info( xmlText);
   18:      A02::srv_Xml_Call(xmlText);
   19:  }
   20:   
   21:  public static server void srv_Xml_Call(str customerInXml)
   22:  {
   23:      System.Xml.Serialization.XmlSerializer serializer;
   24:      System.IO.StringReader xml;
   25:      Samples.Customer customer;
   26:      str name;
   27:      ;
   28:      new InteropPermission(InteropKind::ClrInterop).assert();
   29:      
   30:       customer = new Samples.Customer();
   31:       xml = new System.IO.StringReader(customerInXml);
   32:   
   33:      serializer = new System.Xml.Serialization.XmlSerializer(customer.GetType());
   34:      customer = serializer.Deserialize(xml);
   35:   
   36:      name =  customer.get_Name();
   37:      print name;
   38:  }

 

Here we are serializing the Customer object (from the first example) to a flat Xml-string (line 15) and on the server we are deserializing this Xml-string back to the Customer object (line 34). The Xml-string that is passed between the tiers is the following:

 <?xml version="1.0" encoding="utf-16"?>
 <Customer xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema">
        <Name>sample Name</Name>
 </Customer>