In my previous post, I had explained the procedure to create custom services. The post contained usage of Basic types for exchanging data. In this post, I will explain the way to use complex data types and exchanging data where we need to provide or receive more than one data field as request/response.
To accomplish this, Dynamics AX provides concept of Data Contracts. Data Contracts are used to specify the input and return parameters for Services. Microsoft Dynamics AX utilizes the WCF data contracts to use .Net and X++ data types (both basic and complex). The serialization and deserialization of Data Contracts is handled by WCF framework itself.
What we as developers need to ensure is that we specify proper attributes to the contract classes and methods to ensure that proper serialization and deserialization happens for our contract classes.
Serialization Attributes
- DataContractAttribute – This attribute specifies that the class should be serialized and can be used as a data contract. It is applied at the class level (specified on classDeclaration).
- DataMemberAttribute – This attribute specifies the serializable methods in the data contract class. The attribute can be applied to public and instance methods, as long as the method uses a get/set pattern that contains one optional parameter (methods similar to the famous ‘parm’ methods of AX Business Classes).
Procedure to create data contract classes
Described below is the procedure to create and use the data contract classes. Note that you will need to first finish the task specified in my previous blog to create custom service to carry on with this procedure.
- In AOT –> Classes node, right click and create new class
- Name it as SamCustomServiceContract
- In method classDeclaration, before the method signature, add the attribute[DataContractAttribute]
/// <summary>
/// Data Contract class for SamCustomServiceTest custom service demo class
/// </summary>
/// <remarks>
/// This is the Data Contract class for the custom service demo class SamCustomServiceTest
/// </remarks>
[DataContractAttribute]
class SamCustomServiceContract
{
CustName custName;
CustGroupId custGroupId;
LanguageId defaultLanguage;
}
- Add three serializable parm methods to the class to get/set customer name, customer group and default language
parmCustGroupId
/// <summary>
/// Gets or sets the value of the datacontract parameter CustGroupId.
/// </summary>
/// <param name=”_custGroupId”>
/// The new value of the datacontract parameter CustGroupId; optional.
/// </param>
/// <returns>
/// The current value of datacontract parameter CustGroupId
/// </returns>
[
DataMemberAttribute('CustGroupId')
]
public CustGroupId parmCustGroupId(CustGroupId _custGroupId = custGroupId)
{
custGroupId = _custGroupId;
return custGroupId;
}
parmCustName
/// <summary>
/// Gets or sets the value of the datacontract parameter CustName.
/// </summary>
/// <param name=”_custName”>
/// The new value of the datacontract parameter CustName; optional.
/// </param>
/// <returns>
/// The current value of datacontract parameter CustName
/// </returns>
[
DataMemberAttribute('CustName')
]
public CustName parmCustName(CustName _custName = custName)
{
custName = _custName;
return custName;
}
parmDefaultLangauge
/// <summary>
/// Gets or sets the value of the datacontract parameter DefaultLanguage.
/// </summary>
/// <param name=”_defaultLanguage”>
/// The new value of the datacontract parameter DefaultLanguage; optional.
/// </param>
/// <returns>
/// The current value of datacontract parameter DefaultLanguage
/// </returns>
[
DataMemberAttribute('DefaultLanguage')
]
public LanguageId parmDefaultLanguage(LanguageId _defaultLanguage = defaultLanguage)
{
defaultLanguage = _defaultLanguage;
return defaultLanguage;
}
The Contract Class is ready for utilization. Now let us go ahead and add a method to our custom service class to utilize this contract class.
For this, select our previously created service class, SamCustomServiceTest and add following method to the class
/// <summary>
/// Gets a list of customer ids from the specified company
/// </summary>
/// <param name=”_custList”>
/// The list of customer ids; Mandatory
/// </param>
/// <returns>
/// List of customer information
/// </returns>
/// <remarks>
/// AifCollectionTypeAttribute is used to define strongly typed containers for data
/// </remarks>
[SysEntryPointAttribute(true),
AifCollectionTypeAttribute('return', Types::Class, classStr(SamCustomServiceContract)),
AifCollectionTypeAttribute('_custList', Types::String)]
public List retrieveCustomerInfo(List _custList)
{
SamCustomServiceContract dataContract;
ListEnumerator listEnum = _custList.getEnumerator();
List resultSet = new List(Types::Class);
CustTable custTable;
while (listEnum.moveNext())
{
select firstOnly custTable
where custTable.AccountNum == listEnum.current();
dataContract = new SamCustomServiceContract();
if (custTable)
{
dataContract.parmCustGroupId(custTable.CustGroup);
dataContract.parmCustName(custTable.name());
dataContract.parmDefaultLanguage(custTable.languageId());
}
resultSet.addEnd(dataContract);
}
return resultSet;
}
Note: The return type is class and we have to provide the name of the serializable class that will be used for returning data. The return type is specified by AifCollectionTypeAttribute attribute.
- Now that the service is ready, select the service group and deploy it again
- Now open the visual studio and the project we created earlier to modify it and use the newly created service operation
- In Visual Studio, under Service Reference node, select our custom service, right click and select “Update Service Reference”
- Open the existing form and add a “List view” type control and a button. The List view type control should have View property set to “Detail” and 4 columns should be added using the “Columns” collection property as shown below
- Now double click on “Get Customer Info” button and add following code
private void button4_Click(object sender, EventArgs e)
{
string[] strItem = null;
int i = 0;
SamCustomAXService.CallContext callContext = new SamCustomAXService.CallContext();
SamCustomAXService.SamCustomServiceClient servClient = newSamCustomAXService.SamCustomServiceClient();
strItem = new string[listBox1.SelectedItems.Count];
//Get selected customer ids and prepare a string array
foreach (Object selecteditem in listBox1.SelectedItems)
{
string item = selecteditem as string;
strItem[i++] = item;
}
//Use the Data Contract array to get the customer information
SamCustomAXService.SamCustomServiceContract[] custInfo = servClient.retrieveCustomerInfo(callContext, strItem);
listView1.Items.Clear();
i = 0;
foreach (SamCustomAXService.SamCustomServiceContract custDet in custInfo)
{
ListViewItem item = listView1.Items.Add(strItem[i++]);
item.SubItems.Add(custDet.CustName);
item.SubItems.Add(custDet.CustGroupId);
item.SubItems.Add(custDet.DefaultLanguage);
}
}
Now save the package, build it and run, first click on button “Get Customers”, then select some customers and click on button “Get Customer Info” this is what you will see
This concludes the post, I will keep on adding more topics on custom services as and when I try them out.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.