AIF Error: Activity not found & Service Re-Deployment fails

A customer recently reported a problem with AIF services. The AIF log at System Administration > Periodic > AIF > Exceptions shows failed AIF calls from an external system resulting in an exception “Activity … not found”. However, the service seems to be active and online.

Default Voodoo here is to deactivate and reactive the service. However, it turned out that the service could not be reactivated. Dynamics AX reported an error that no activities were found. A detailed look revealed that all activities for this service somehow disappeared

Missing activities in Dynamics AX AIF service

The solution is to open a development workspace, navigate to the service node in the AOT and (re-) register the service.

Re-register AIF service

After re-register the service from the AOT, all missing activities were available again within the service configuration. The service could be activated without any problems.

Activities in Dynamcis AX AIF service

Be aware that other services may also be affected by the same problem. Check if your reports are working, and if not check the BI Service. In case the BIService can not be activated, navigate in the AOT to the service node and re-register the SRSFrameworkService and SSASFrameworkService.

AIF Error Microsoft.Dynamics.Ax.Xpp.InvalidRemoteCallException

There are many reasons why an AIF Service call might fail, and I also ran into one. The task was to refactor existing code that processes some business logic and renames a file to .OLD. The original code looked like this

public class ERPProcessFile
{
    Filename fileName;

    public static void main(Args args) 
    { 
        ERPProcessFile pf = new ERPProcessFile(args);
        pf.run();
    }

    public void new(Args _args)
    {
        if(_args && _args.parm())
            fileName = _args.parm();
        else
            throw error(error::missingParameter(null));
    }

    private void run()
    {
        #File
        FileIOPermission permission;

        if(fileName != "")
        {
            permission = new FileIOPermission(fileName,#io_write);
            permission.assert();       
            WinAPI::moveFile(fileName,strFmt(‚%1.old‘,fileName));        
            CodeAccessPermission::revertAssert();
        }
    }
}

The code above was tested using a Job

static void Job1(Args _args)
{
    Args args = new Args();
    args.parm(@"C:\Users\Public\Documents\textfile.txt");

    ERPProcessFile::main(args);
}

The code was wrapped in a service class and published as AIF HTTP web service

class ERPProcessFileService
{
    [SysEntryPointAttribute]
    public void processFile(Filename _localFile)
    {
        Args args = new Args();
        args.parm(_localFile);

        ERPProcessFile::main(args);
    }
}

The service was published to IIS, and imported in Visual C# as Ax2012 namespace

var context = new Ax2012.CallContext();
context.MessageId = Guid.NewGuid().ToString();

var client = new Ax2012.ERPProcessFileServiceClient();
client.ClientCredentials.Windows.ClientCredential =
new System.Net.NetworkCredential("USER", "PW", "DOMAIN");
client.processFile(context,@"C:\Users\Public\Documents\textfile.txt");

The service call resulted in an exception

{"Exception of type ‚Microsoft.Dynamics.Ax.Xpp.InvalidRemoteCallException‘ was thrown."}

The reason was the use of WinAPI class which does not work when executed on the AOS. However, the code works fine when tested using a Job, or called within a Form. The solution was easy; Checking if the code is executed on Server or Client and using WinAPI or WinAPIServer class.

public class ERPProcessFile
{
    Filename fileName;

    public static void main(Args args) 
    { 
        ERPProcessFile pf = new ERPProcessFile(args);
        if(xGlobal::clientKind() == ClientType::Client) 
            pf.run();
        if(xGlobal::clientKind() == ClientType::Server)
            pf.runServer();
    }

    public void new(Args _args)
    {
        if(_args && _args.parm())
            fileName = _args.parm();
        else
            throw error(error::missingParameter(null));
    }

    private void run()
    {
        #File
        FileIOPermission permission;

        if(fileName != "")
        {
            permission = new FileIOPermission(fileName,#io_write);
            permission.assert();       
            WinAPI::moveFile(fileName,strFmt(‚%1.old‘,fileName));        
            CodeAccessPermission::revertAssert();
        }
    }

    private void runServer()
    {
        #File
        FileIOPermission permission;

        if(fileName != "")
        {
            permission = new FileIOPermission(fileName,#io_write);
            permission.assert();       
            WinAPIServer::copyFile(fileName,strFmt(‚%1.old‘,
                                                   fileName));         
            WinAPIServer::deleteFile(fileName)
            CodeAccessPermission::revertAssert();
        }
    }

}