Tuesday, February 27, 2024

D365FO - Calling external RESTful API via POST to download a file and send to the user

 

I have recently found a mixture of AX 2012 / D365 code online when it comes to calling external REST web API’s directly from AX/D365FO. It seems as though in today’s world the majority of people only care about calling and receiving JSON or XML or some type of text-based object which the majority of time holds true. But what happens when that API should return some type of file or object rather than raw text where we want to save or serve up the file?

This is where it gets tricky because the System.IO.StreamReader like shown within the majority of examples online doesn’t provide the structure that we need in order to access binary objects to be able to send a file to the user or display something on the screen. It is however great when it comes to reading text based responses.

The key to understanding  the framework is once we are able to put the main System.IO.Stream into a System.IO.MemoryStream then we are easily able to convert the binary objects to various output's.

 

The best way to describe is that System.IO.Stream operates much like a FormRun object. It is the top most level and once we get access to that then we can access any child objects like StreamReader or MemoryStream which can then be handled differently based on the scenario.


Below is an example how to call a generic RESTful API via a post (the request structure may change based on your specific API being called)



 
	    System.Exception clrError;
            InteropPermission interopPermission;
            System.Net.HttpWebRequest request;
            System.IO.Stream stream;
            System.Byte[] zpl = System.Text.Encoding::UTF8.GetBytes("post body");

            request = System.Net.WebRequest::Create("API URL") as System.Net.HttpWebRequest;
            request.Method = 'POST';
            request.Accept = "image/png"; //document type to generate
            request.ContentType = 'application/x-www-form-urlencoded';
  
            try
            {
                interopPermission = new InteropPermission(InteropKind::ComInterop);
                interopPermission.assert();

                // send out the payload
                using (System.IO.Stream dataStream = request.GetRequestStream())
                {
                    dataStream.Write(zpl, 0, zpl.Length);
                }

                
                using (System.Net.HttpWebResponse response = request.GetResponse() as System.Net.HttpWebResponse)
                {
                    stream = response.GetResponseStream();
                    System.IO.MemoryStream filestream = new System.IO.MemoryStream();
                    
                    //we need to convert the main stream to a memory stream in order to access the binary objects
                    stream.CopyTo(filestream);
     
                    //send the memory stream directly to the user which now contains a file object
                    File::SendFileToUser(filestream, "test.png");
                }
            }
            catch (Exception::CLRError)
            {
                //catch any clr error
                clrError = CLRInterop::getLastException();
                if (clrError != null)
                {
                    clrError = clrError.InnerException;
                    throw error(clrError.ToString());
                }
            }
            finally
            {
                CodeAccessPermission::revertAssert();
            }




No comments:

Post a Comment