Today, when updating some records through AIF I got the following error :

AIF Stacktrace
This is definitely not a clear error
since the only thing was wrong is that the Update property was set to No instead of Yes on the Query’s datasource.

Update Property on the query's datasource
Thanks to a collegue of mine (from artofcreation) to point this one out !
Today I experienced that when using AIF through web services, you have to pay attention to the difference between an empty string and a null value.
We created a service for inventory locations and we had the InventLocationId filled in by the AIF. But when calling the service we received an error everytime telling us that the InventLocationId was mandatory but missing. (Although it was in the exemption list and there was code to fill it in)
Then we discovered that the calling .NET application specified the “” value on the inventLocationId instead of the NULL value. This results in a different XML file and the AIF thinks that the InventLocationId is filled in but with an empty value.
XML file when using null value :

AIF NULL Value
XML file when using empty string value :

AIF Empty String Value
Today I created an AIF web service to expose the Working times functionality in Ax 2009. The service itself is quite simple but there was the issue with the workTimeId. The application on the other side doesn’t care about the Id of the working times and wants Dynamics to use a number sequence for the workTimeId field. This post will not deal with the creation of a number sequence reference but shows how you can fill in the WorkTimeId automatically and especially how you can link the WorkTimeLine to the WorkTimeTable via the WorkTimeId.
First things first, we create a query which contain the two tables.

AxdWorkTime Query Object
Since we are planning on updating / deleting through the service, we must not forget to set the properties on the datasources. Properties Delete and Update must be set to Yes.
Then we create the AIF service by using the Wizard available in AX 2009. Afterwards we have the following objects available :
- AIF Service object
- AIF Service class
- AxWorkTimeTable entity class
- AxWorkTimeLine entity class
- AxdWorkTime document classWorkTimeDocument / WorkTimeDocument_WorkTimeTable / WorkTimeDocument_WorkTimeLine Classes
- Some datacontainertype macros stuff

Created project
Now we are going to make sure the WorkTimeId is fetched from a number sequence and inserted automatically. For this we need to do 2 things :
- Set the WorkTimeId as not mandatory (Both on the axWorkTimeTable and axWorkTimeLine entities)
- Modify the setWorkTimeId method on the axWorkTimeTable entity to use the number sequence
protected void initMandatoryFieldsExemptionList()
{
super();
this.setParmMethodAsNotMandatory(methodstr(AxWorkTimeTable,parmWorkTimeId));
}
protected void setWorkTimeId()
{
NumberSequenceReference numberSequenceReference;
;
if (this.isMethodExecuted(funcName(), fieldNum(WorkTimeTable, WorkTimeId)))
{
return;
}
if (this.isSetMethodsCalledFromSave())
{
if (this.isFieldSetExternally(fieldnum(WorkTimeTable, WorkTimeId)))
{
if (!this.workTimeTable())
{
numberSequenceReference = NumberSeqReference::findReference(typeId2ExtendedTypeId(typeid(WorkTimeId)));
this.checkNumber(numberSequenceReference.numberSequenceTable(),fieldNum(WorkTimeTable, WorkTimeId),this.parmWorkTimeId());
if (numberSequenceReference.NumberSequence && numberSequenceReference.numberSequenceTable().Continuous)
{
NumberSeq::newReserveNum(numberSequenceReference).reserve(this.parmWorkTimeId());
}
}
}
else
{
if (this.isFieldSet(fieldnum(WorkTimeTable, WorkTimeId)))
{
return;
}
if (!this.parmWorkTimeId())
{
this.parmWorkTimeId(NumberSeq::newGetNum(NumberSeqReference::findReference(typeId2ExtendedTypeId(typeid(WorkTimeId)))).num());
}
}
}
}
And last but not least we need to link the AxWorkTimeLine to the AxWorkTimeTable via the WorkTimeId. The wizard already did some action to achieve this by putting the prepareForSave method on the AxdWorkTime document class.
public boolean prepareForSave(AxdStack _axdStack, str _dataSourceName)
{
AxWorkTimeTable AxWorkTimeTable;
AxWorkTimeLine AxWorkTimeLine;
;
switch (classidget(_axdStack.top()))
{
case classnum(AxWorkTimeTable) :
AxWorkTimeTable = _axdStack.top();
return true;
case classnum(AxWorkTimeLine) :
AxWorkTimeLine = _axdStack.top();
AxWorkTimeTable = AxWorkTimeLine.parentAxBC();
AxWorkTimeLine.parmWorkTimeId(AxWorkTimeTable.parmWorkTimeId());
return true;
default :
error(strfmt("@SYS88979",classId2Name(classidget(_axdStack.top()))));
return false;
}
return false;
}
Since the parm method will call the setWorkTimeId method once, we still need to place some code there :
The code will call the parent entity’s parmWorkTimeId method.
protected void setWorkTimeId()
{
if (this.isMethodExecuted(funcName(), fieldNum(WorkTimeLine, WorkTimeId)))
{
return;
}
if (!this.parmWorkTimeId())
{
this.parmWorkTimeId(this.axWorkTimeTable().parmWorkTimeId());
}
}
The only thing still needed now is pointing out who is the parent entity. Therefore I’ve created a method that creates an axWorkTimeTable entity.
public AxWorkTimeTable axWorkTimeTable(AxWorkTimeTable _axWorkTimeTable = null)
{
AxWorkTimeTable axWorkTimeTable;
if (!prmisdefault(_axWorkTimeTable))
{
axWorkTimeTable = _axWorkTimeTable;
}
else
{
this.setWorkTimeId();
axWorkTimeTable = WorkTimeTable::find(this.parmWorkTimeId()).axWorkTimeTable();
}
return axWorkTimeTable;
}
public AxWorkTimeTable axWorkTimeTable()
{
AxWorkTimeTable axWorkTimeTable = AxWorkTimeTable::newWorkTimeTable(this);
return AxWorkTimeTable;
}
If someone wants to add something, be my guest… comments are welcome !
When using AIF through web services, you can be in the dark when you want to know what’s really going on in there. Additionally you can have trouble debugging the thing when you are running a Windows 2008 box. (Contacted Microsoft last week and the response was that debuggin AIF webservices does not work on a Win2k8 box but they are developing a hotfix as we speak)
There is a possibility to have some tracing of what is happening there. I found this on MSDN and will show an example here of what the result of the tracing shows.
First, head over to the folder where the Dynamics Ax web services are generated. There you should find a web.config file. To enable tracing you need to make sure this tag is present
<system.diagnostics>
<!-- This is used for enabling tracing in retail and debug builds.
AIF Service processing stack outputs and information
messages used for debugging.
Possible values for the switch are Off, Warning,
Information, Critical, Verbose.
Change the switchValue to Information to enable tracing.
-->
<sources >
<source name="AifServiceProcessing" switchValue="Information">
<listeners >
<add name="TextWriterListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="AifServiceTrace.webinfo" >
</add>
<remove name="Default" />
</listeners>
</source>
</sources>
</system.diagnostics>
After invoking the service, there should be a file named AifServiceTrace.Webinfo present with the tracing information :
The following information can be viewed :
- UserId’s
- Message ID
- Source and destination endpoint
- Key Data XML
- Return Data from Ax
