Search code examples
c#filedynamics-crmdataversedynamics-365-ce

Upload PDF ( > 4 MB) to File datatype in D365 CRM


I'm trying to upload a PDF file to a CRM record. I've used a File type field in the entity that can hold my uploaded file. I've done this by using this code:

UploadBlockRequest blockRequest = new UploadBlockRequest();
blockRequest.BlockData = Convert.FromBase64String(documentBody);
blockRequest.BlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
blockRequest.FileContinuationToken = initResponse.FileContinuationToken;

var blockResponse = (UploadBlockResponse)service.Execute(blockRequest);

It is working fine for PDF files that are under 4 MB. However, If I try to upload a PDF that's more than 4 MB, I get the following error:

Invalid file chunk size: 4 MB. Maximum chunk size supported: 4 MB.

Is there a way to upload large PDF files to CRM record?

using (var stream = new MemoryStream(Convert.FromBase64String(Base64)))
                    {
                        InitializeFileBlocksUploadRequest initializeUploadRequest = new InitializeFileBlocksUploadRequest();
                        initializeUploadRequest.FileAttributeName = "my_fileTypeField";
                        initializeUploadRequest.FileName = "Test.pdf";
                        initializeUploadRequest.Target = new EntityReference("my_entity", new Guid("my_guid"));

                        var initializeUploadResponse = (InitializeFileBlocksUploadResponse)service.Execute(initializeUploadRequest);
                        var uploadRequest = new UploadBlockRequest { FileContinuationToken = initializeUploadResponse.FileContinuationToken };

                        const int blockSize = 4194304; // 4MB
                        int byteCount;
                        var blockList = new List<string>();

                        do
                        {
                            
                            //uploadRequest.BlockData = Convert.FromBase64String(documentBody);
                            byteCount = stream.Read(uploadRequest.BlockData, 0, blockSize);
                            uploadRequest.BlockId = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
                            service.Execute(uploadRequest);
                            blockList.Add(uploadRequest.BlockId);
                            Console.WriteLine(size + " == " + blockSize);
                        } while (size == blockSize);

                        var commitRequest = new CommitFileBlocksUploadRequest
                        {
                            BlockList = blockList.ToArray(),
                            FileContinuationToken = initializeUploadResponse.FileContinuationToken,
                            FileName = initializeUploadRequest.FileName,
                            MimeType = "application/pdf"
                        };
                        var commitResponse = (CommitFileBlocksUploadResponse)service.Execute(commitRequest);
                    }

Solution

  • The UploadBlockRequest is one piece in the file upload procedure. You need 3 distinct requests:

    1. InitializeFileBlocksUploadRequest
    2. UploadBlockRequest
    3. CommitFileBlocksUploadRequest

    The UploadBlockRequest can hold a chunk of 4 MB of data at a maximum. Your file can be as large as 128 MB and it can be uploaded using multiple upload requests.

    A basic upload method could look like this:

    private static Guid UploadFile
        (
            Stream stream,
            string fileName,
            string mimeType,
            EntityReference target,
            string fileAttributeName,
            IOrganizationService organizationService
        )
    {
        var initializeUploadRequest = new InitializeFileBlocksUploadRequest
        {
            FileAttributeName = fileAttributeName,
            FileName = fileName,
            Target = target
        };
    
        var initializeUploadResponse = (InitializeFileBlocksUploadResponse)organizationService.Execute(initializeUploadRequest);
    
        const int blockSize = 4194304; // 4 MB
        int byteCount;
        var blockList = new List<string>();
    
        do
        {
            var buffer = new byte[blockSize];
            byteCount = stream.Read(buffer, 0, blockSize);
    
            if (byteCount < blockSize)
                Array.Resize(ref buffer, byteCount);
    
            var uploadRequest = new UploadBlockRequest
            {
                BlockData = buffer,
                BlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("N"))),
                FileContinuationToken = initializeUploadResponse.FileContinuationToken
            };
    
            organizationService.Execute(uploadRequest);
            blockList.Add(uploadRequest.BlockId);
        } while (byteCount == blockSize);
    
        var commitRequest = new CommitFileBlocksUploadRequest
        {
            BlockList = blockList.ToArray(),
            FileContinuationToken = initializeUploadResponse.FileContinuationToken,
            FileName = initializeUploadRequest.FileName,
            MimeType = mimeType
        };
    
        var commitResponse = (CommitFileBlocksUploadResponse)organizationService.Execute(commitRequest);
        return commitResponse.FileId;
    }
    

    The method uploads the file and returns the ID of the file.