File upload and download in AX 7

New Dynamics AX is a web application running in cloud, so how can users work with files in such an environment? The answer is: in the same way as with other web applications. If you know how to add and download attachments in your webmail client, you can do it in AX 7 as well.

And it’s not too difficult for developers either.

Let me demonstrate it on a simple form I’ve built.


When you click the Upload button, a dialog opens where you can pick a file on your computer and upload it. It even shows progress of uploading.


The whole upload is triggered by a single statement: File::GetFileFromUser(). You don’t have to deal with any details.

By default, the file is uploaded to a temporary blob storage and can be accessed through some ugly URL such as this:


If you click the download button, it will navigate to the URL and your browser will do the rest:


Code of Download button is again a one-liner: new Browser().navigate(fileUrl).

This is the complete code of the form, showing also how to get the URL of the uploaded file:

public class UploadDownloadForm extends FormRun
    str fileUrl;
    class UploadButton
        public void clicked()
            FileUploadTemporaryStorageResult result = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
            if (result && result.getUploadStatus())
                fileUrl = result.getDownloadUrl();
    class DownloadButton
        public void clicked()
            new Browser().navigate(fileUrl);

Your files typically aren’t accessible by URL, because they’re in database or in a secured storage. But that’s not a problem. Just load the content of your file to a stream and pass it to File::SendFileToUser(). It will put the file to the temporary blob storage and navigate to the URL, therefore users can download the file in the same way as above.


      • You can just use the code in this example, with small tweaks, for a simple file upload.

        Create a contract with FileUploadTemporaryStorageResult as a data member, which SysOp will handle as it will look for nested contracts.

        Construct the AsciiStreamIO object in you processing class.

        If you leave the data member as visible you get to see how SysOp expands nested data contracts on to the dialog.

        • Hi Simon,
          what do you mean by “Create a contract with FileUploadTemporaryStorageResult as a data member”?
          Do I have to add FileUploadTemporaryStorageResult as a parm method to the contract? In this case it shows all parameters but no Upload Button.
          Could vou please show me a ode example?

  1. Hi Martin, great article!

    I have a situation where I need to download a file (image) from Azure Blob Storage (as a stream, byte array or physical file) and attach the image to a record (lets say a case for example). Any tips on creating the attachment manually through code?


  2. Hi Martin,

    Thanks for such a great article. In 2012, I have a batch job designed to export all the images, documents in a specific format from docuval table to a local folder. now that the file is no more a container, Is there a way where I can download all files(documents/images) from docuval to a folder directory?

    • If you mean a directory on some local machine (not in Azure), run an app from the local machine that connects to AX in Azure and get the data through a web service.

      • would it be possible to drop files to a folder on another VM (in Azure) without using any app? May be establishing some kind of trust between these VMs/folders OR authenticating every time they communicate …


        • No, I can’t imagine how it should work. How do you want to set up a trust on a machine you have no access to? Don’t forget, production environments are deployed to Microsoft subscription and managed by Microsoft staff; you can’t connect there.
          Web services are the right way to communicate with cloud applications.

  3. Hi Martin, great post! I used it a while ago to show an xml file I stored in the database in the browser, which worked, but now (maybe through the upgrade to 7.2) I get the following error in the browser when opening the file:


    Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:319ab7fb-0001-0003-502f-341600000000 Time:2016-11-01T11:04:11.9893250Z

    sp is mandatory. Cannot be empty

    Any idea how to fix this? I tried to find an answer myself, but I came up empty.

      • It’s the “new Browser().navigate(fileUrl);” that gives the error. What I basically do is teh following. I have an xml string in my database, and I want to present that in a new browser tab.

        void show(str _xml)
        System.IO.MemoryStream xmlStream;
        System.Byte[] byteArray;

        // convert string to stream
        byteArray = System.Text.Encoding::UTF8.GetBytes(_xml);
        xmlStream = new System.IO.MemoryStream(byteArray);
        FileUploadTemporaryStorageResult result = File::SendFileToTempStore_GetResult(xmlStream, “XMLView.xml”) as FileUploadTemporaryStorageResult;
        if (result && result.getUploadStatus())
        url = result.getDownloadUrl();

        public void openUrl(DocuPath _path)
        Browser br = new Browser();

        if (_path == ”)

        if (DocumentFileHelper::checkUrl(_path))
        // navigate
        // URL format is not supported

  4. Hi Martin

    Thanks for the code, it is very useful

    But I’m facing a problem, I’ve create a text file, with a stream, I store the file with the function File::SendFiletoTempStore, the function returns the url, when use the line Browser().navigate(url), my browser open in a new tab the file, there is another way to Download as a file.

    WebClient.DowloadFile no works too,

    Thanks and Regards

    • Jose, it’s not clear to me what’s the problem. What you describe sounds correct, so it’s likely about what you *expected* instead. WebClient is a very different topic, because this blog post is about the server side, not client side.
      I suggest you elaborate your question in a forum, where you’ll also get a few thousand of potential advisors.

    • Hi Jos,
      Did you manage to resolve the issue if yes please give me the code. I have a XML string stored in container in Ax table. Trying to show XML to user from a form and open as URL in browser.

  5. Hi Martin,
    I need to save the attachment (say a report ) generated at runtime to a invoice journal record. I am trying to use the same code as print archive functionality in ax7. The records are stored in docuref and docuvalue tables but when I click on attachment icon , attachments doesn’t show up.
    I verified adding attachment of type notes. I am able to see notes in attachment form but not the documents attached in PDF format.
    I also noticed that the ‘location’ field is empty in the table record.
    please let me know your suggestions

    • It depends on what you mean by that; please elaborate your question.
      By the way, you’ll reach many more people if you ask in a discussion forum (I contribute to and

  6. Hi Martin,
    Scenario = A batchjob ( SysOperation framework ) runs at night and polls a local folder for flat files that come from my payroll provider. AX processes these files and stores resulting files in another local folder where they are picked up by separate HR-application. Is this scenario still possible with Dynamics 365 ?

    • Your goal is achievable, but how depends on many variables. For example, if “local folder” means local to the AOS server or to you (so you would need an Azure application actively connecting to your computer). Also, it depends on if you insist making the connection from AX, which is the opposite way how it’s usually done. Or if you insist on using a local folder instead of a network one.
      I suggest you create a thread in a discussion forum (I contribute to and; it’s a more suitable place for long discussions.

  7. Hi Martin,
    thanks for the post. The Command “File::GetFileFromUser()” uses the “FileUploadTemporaryStorageStrategy” as Default Strategy. The “FileUploadTemporaryStorageStrategy” gets the Destination for the File from SharedServiceUnitStorage::GetDefaultStorageContext(). In my Case the ConnectionString of the Default storage context is “UseDevelopmentStorage=true”. I now want to stop using the Emulator and start using the Blob Storage in the Azure Cloud. My Question: Do you know how I can alter the Default Connection String or what it depends on?

    (SharedServiceUnitStorage is part of the Microsoft.DynamicsOnline.Infrastructure.Components.SharedServiceUnitStorage Namespace, which is a member of the Microsoft.Dynamics.Clx.ServicesWrapper Assembly, which is a member of the Microsoft.Dynamics.Clx.ServicesWrapper.dll, stored at C:\AOSService\PackagesLocalDirectory\bin\Microsoft.Dynamics.Clx.ServicesWrapper.dll (In Case it helps))

    • So I just fixed it:
      “SharedServiceUnitStorage::GetDefaultStorageContext()” gets it´s Value from the web.config file in the Directory ‘C:\AOSService\webroot’. The StorageConnectionString “AQAAAHNm4l3JT6ikAPoAN//zuzANlILUc2biXclPqKQA+gA3//O7MA2UgtR3NT3UDbgMyD1HIznpaNDGEFF1PsxJvUQm15MUIpNU4ypDHRSbzymhBnCXnfGWB9EyazceEBSrGtaW2Ol/iy+JdI0u0iqDpdVDZiPvX17eG+NW3lpuhazhV8PP/ChOBg5YUs3Nre4WnyHZok2UxnAJfazwf0tiz17lDzV6acH+3VrmTDEhnjxg4z3kicquPm7qUA/bFO1Hr3ejZoubPYsVSulUiAwAN8xlQKYIJN3f9mzhZKyA+6rUWp9LP/c1FLQ5EFUiJE7Md3ft8qWjxGBCHYSYb7qvQUN9QuQVRdxg69lQ2dgXDDS/ylNqlCJYX4+PMq6K8yIq12qeH4X5cEvPHh2q1wNpqzvomS7m5P7KbdkWBKgBmoD+wYAimt8EIPGq0O7E2XhoOTg/fL3RaVxvlP4lOfa5GJUnTf34HRFocby9Yy3lJiYwpKWr94yHp6zmVx9vhLLGOlsb2GiKwAYyA6j9xLEUyW8j1I/WJ58OHs53G+93Q3COyaQao1yfYQu8X8JiwXN62GinsKxA3ysPED3HnaIINW1mb2Z19+30n6b8WDI3kQioMRhMJuom/IpHN1Nb0lbWK1yrmB5HbLlMClYesdXrqI2ogD0JTAGzEaXTsTMG/BBupE5kqcQJyZps5qkumR7C8bt95ExuhYUMrDXwcT6rDFO/fr915pUM9jTjryKwDrI0uhykTyRuqnAzfsvkO3Tjkwr09ntwgZbr0IH/DH3fF68EWJzqXE5cZw==” seems to reference “UseDevelopmentStorage=true”. When you change this ConnectionString to your custom ConnectionString “SharedServiceUnitStorage::GetDefaultStorageContext()” also uses your custom ConnectionString.

      Hope it helps someone who had the same Problems 🙂

Leave a Reply

Your email address will not be published.