In Microsoft Dynamics 365 Business Central we can use Media and MediaSet Data Types to store images, or other types of documents. In this post, you will learn how to use them, and how to create a process to import and export images. Also, you will learn the differences between them and blob types.

  • What Are The Media And MediaSet Data Types?
  • Media And MediaSet Example
  • How To Import Media And MediaSet?
  • How To Export Media And MediaSet?
  • Important Points To Consider

What Are Media And MediaSet Data Types?


The Media data type can be used to store different types of files such as images, documents, texts, etc. It is also known as the MIME type. You can see the full list of supported types here:

Working With Media on Records – Business Central | Microsoft Learn

The MediaSet data type is similar to the Media, the only difference is that you can store multiple files in it. While the Media type can store only one at the same time.

Media And MediaSet Example


We will create a simple example to help understand its use. The objects created will be a table, a list, a card, and a factbox. You will find all the source code at the end of the post.

In order to see the differences between them, in the table there will be a Media, a MediaSet, and a Blob type:


In the card, we have added the three fields:


The resulting page is a card with a factbox, similar to the following image. As you can see, although the Media and MediaSet types were populated on the card, only the blob field can be seen. The same happens on list pages.


How To Import Media And MediaSet?


Blob fields don´t need any code to import an image, it´s built-in. However, media and MediaSets do need personalization to be used.

Media can be imported by using the Instream data type like the following image:


With MediaSet is the same:


Once imported, we can see the result. In the factbox, we can see the Media, MediaSet, and Blob types. And the blob type can be seen also on the card:


How To Export Media And MediaSet?


The way to export a Media type is by retrieving the value in the ‘Tenant Media’ table. This table stores all the media data of Business Central. You can find it by searching for ‘Table Information’ and ‘Tenant Media’.


Here is an example of how to export a Media type, again, using an Instream.


To export a MediaSet we have to use a different approach. The first thought would be to loop through the MediaSet and download each image. But browsers have a limitation that only one file can be handled per request:

https://learn.microsoft.com/en-us/dynamics-nav/downloadfromstream-function–file-#remarks


For that reason, a solution for it is to create a zip file and insert all the media files into it. The code is a little more complex than the previous one. We use the ‘Data Compression’ codeunit for this.

Notice that we loop through the content of the MediaSet field with MediaSet.Item(i).


In this video demo, two images are downloaded in a zip file. Both come from the MediaSet field:


Important Points To Consider


Microsoft recommends the use of Media types over Blob in the documentation.

Using the Media or MediaSet data type provides better performance than using a BLOB data type and is more flexible in its design. With a BLOB data type, each time the media is rendered in the client, it is retrieved from the SQL database server, which requires extra bandwidth and affects performance. With the Media and MediaSet data types, the client uses media ID to cache the media data, which in turn improves the response time for rendering the media in the user interface.

https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/performance/performance-developer#builtindatastructure


Although they have better performance, you should be aware of the limitations of Media types when using them to store images. Because the expected behavior is not the same as Blob fields.

As we have seen, Blob fields don´t need code to import the image, it´s built-in.

Blob fields can be seen on lists as thumbnails, while Media can´t.


Media images, however, can be seen in tiles or tall tiles view:


There is already an idea posted on Microsoft to add some functionality to Media types:


For more information about using Media types follow:

https://learn.microsoft.com/en-us/dynamics-nav/working-with-media-on-records

Also, check the following article for further information about Media handling:

If you want to learn how to create a beautiful role center using blob fields follow the article below:


Source code:

table 50100 "MediaSetExample"
{
    DataClassification = OrganizationIdentifiableInformation;

    fields
    {
        field(1; Code; Code[20])
        {
            DataClassification = OrganizationIdentifiableInformation;
        }

        field(2; Media1; Media)
        {
            DataClassification = OrganizationIdentifiableInformation;
        }

        field(3; MediaSet1; MediaSet)
        {
            DataClassification = OrganizationIdentifiableInformation;
        }

        field(4; Blob; Blob)
        {
            DataClassification = OrganizationIdentifiableInformation;
            Subtype = Bitmap;
        }
    }

    keys
    {
        key(Key1; Code)
        {
            Clustered = true;
        }
    }
}

page 50103 "MediaFactbox"
{
    Caption = 'Caption';
    PageType = CardPart;
    ApplicationArea = All;
    UsageCategory = Administration;
    SourceTable = MediaSetExample;

    layout
    {
        area(Content)
        {
            field(Media1; Rec.Media1)
            {
                ApplicationArea = All;
            }
            field(MediaSet1; Rec.MediaSet1)
            {
                ApplicationArea = All;
            }
            field(Blob1; Rec.Blob)
            {
                ApplicationArea = All;
            }
        }
    }
}

page 50100 "MediaSetExampleList"
{
    ApplicationArea = All;
    Caption = 'MediaSetExampleList';
    PageType = List;
    SourceTable = MediaSetExample;
    UsageCategory = Lists;
    CardPageId = MediaSetExampleCard;

    layout
    {
        area(content)
        {
            repeater(General)
            {
                field(MyField; Rec.Code)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the MyField field.';
                }
                field(Media1; Rec.Media1)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the Media1 field.';
                }
                field(MediaSet1; Rec.MediaSet1)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the MediaSet1 field.';
                }
                field("Blob"; Rec."Blob")
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the Blob field.';
                }
            }
        }

        area(FactBoxes)
        {
            part(MediaFactbox; MediaFactbox)
            {
                ApplicationArea = all;
                SubPageLink = Code = field(Code);
            }
        }
    }
}

page 50101 "MediaSetExampleCard"
{
    Caption = 'MediaSetExampleCard';
    PageType = Card;
    SourceTable = MediaSetExample;

    layout
    {
        area(content)
        {
            group(General)
            {
                field("Code"; Rec."Code")
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the MyField field.';
                }
                field(Media1; Rec.Media1)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the Media1 field.';
                }
                field(MediaSet1; Rec.MediaSet1)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the MediaSet1 field.';
                }
                field("Blob"; Rec."Blob")
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the value of the Blob field.';
                }
            }
        }

        area(FactBoxes)
        {
            part(MediaFactbox; MediaFactbox)
            {
                ApplicationArea = all;
                SubPageLink = Code = field(Code);
            }
        }
    }

    actions
    {
        area(Processing)
        {
            action(ImportMedia)
            {
                ApplicationArea = All;
                Caption = 'Import Media';
                Image = Import;

                trigger OnAction()
                var
                    FromFileName: Text;
                    InStreamPic: Instream;
                begin
                    if UploadIntoStream('Import', '', 'All Files (*.*)|*.*', FromFileName, InStreamPic) then begin
                        Rec.Media1.ImportStream(InStreamPic, FromFileName);
                        Rec.Modify(true);
                    end;
                end;
            }

            action(ExportMedia)
            {
                ApplicationArea = all;
                Caption = 'Export Media';
                Image = Export;

                trigger OnAction()
                var
                    TenantMedia: Record "Tenant Media";
                    InStreamPic: InStream;
                    ImageLbl: Label '%1_Image.jpg';
                    FileName: Text;
                begin
                    if not Rec.Media1.HasValue then
                        exit;

                    if TenantMedia.Get(Rec.Media1.MediaId) then begin
                        TenantMedia.CalcFields(Content);
                        if TenantMedia.Content.HasValue then begin
                            FileName := StrSubstNo(ImageLbl, Rec.TableCaption);
                            TenantMedia.Content.CreateInStream(InStreamPic);
                            DownloadFromStream(InStreamPic, '', '', '', FileName);
                        end;
                    end;
                end;
            }

            action(ImportPicture)
            {
                ApplicationArea = All;
                Caption = 'Import MediaSet';
                Image = Import;

                trigger OnAction()
                var
                    FromFileName: Text;
                    InStreamPic: Instream;
                begin
                    if UploadIntoStream('Import', '', 'All Files (*.*)|*.*', FromFileName, InStreamPic) then begin
                        Rec.MediaSet1.ImportStream(InStreamPic, FromFileName);
                        Rec.Modify(true);
                    end;
                end;

            }

            action(ExportMediaSet)
            {
                ApplicationArea = all;
                Caption = 'Export MediaSet';
                Image = Export;

                trigger OnAction()
                var
                    TenantMedia: Record "Tenant Media";
                    DataCompression: Codeunit "Data Compression";
                    TempBlob: Codeunit "Temp Blob";
                    InStreamPic: InStream;
                    i: Integer;
                    ImageLbl: Label '%1_Image_%2.jpg';
                    OutStream: OutStream;
                    FileName: Text;
                    ZipFileName: Text;
                begin
                    if Rec.MediaSet1.Count = 0 then
                        exit;

                    ZipFileName := 'Images.zip';
                    DataCompression.CreateZipArchive();
                    for i := 1 to Rec.MediaSet1.Count do begin
                        if TenantMedia.Get(Rec.MediaSet1.Item(i)) then begin
                            TenantMedia.CalcFields(Content);
                            if TenantMedia.Content.HasValue then begin
                                Clear(InStreamPic);
                                TenantMedia.Content.CreateInStream(InStreamPic);
                                FileName := StrSubstNo(ImageLbl, Rec.TableCaption, i);
                                DataCompression.AddEntry(InStreamPic, FileName);
                            end;
                        end;
                    end;
                    TempBlob.CreateOutStream(OutStream);
                    DataCompression.SaveZipArchive(OutStream);
                    TempBlob.CreateInStream(InStreamPic);
                    DownloadFromStream(InStreamPic, '', '', '', ZipFileName);
                end;
            }
        }
    }
}


That´s all. Hope you find it helpful.

How To Use Media Data Types In Business Central?

Post navigation


14 thoughts on “How To Use Media Data Types In Business Central?

  1. Nice post, thank you.

    Is it possible to import and export using RecordRef/FieldRef?
    Or is this also a limitation?

  2. How to upload many images in to the Mediaset field and then delete unwanted images.Also is there anyway to see images that we uploaded. Ex: A item has a pictures from different angle and need to upload them and see from card page.

  3. The article provides a useful guide on utilizing Media and MediaSet Data Types in Microsoft Dynamics 365 Business Central for storing and managing images and documents, with insights into import, export, and key considerations.

  4. I’m facing a bit of a challenge.
    I have two tables – Location Master with a Media Type field storing QR Codes and Sales Header where the QR Code is to be referenced.
    When the Location is set on the Sales Header, I can use the Validate trigger to set the /Location QR Code/ field of the Sales Header by assigning the /QR Code/ of the Location record.
    However, when the time comes to change the Location Code on the Sales Header and I try to de-reference the /Location QR Code/ of the Sales Header, I end up deleting the QR Code’s data from the main /Location/ record itself.
    If I use the Import/Export stream methods that creates additional tenant media records which uses up more space than necessary.
    I read in the Microsoft docs that as long as the Tenant Media record is being referenced somewhere, it does not get deleted so I was hoping that would work out.
    Also, this blog here suggests that when we assign a Media field to another, then both reference the same record in the Tenant Media table.
    I want to know how to dereference one of them.
    Any direction is highly appreciated!

Leave a Reply

Your email address will not be published. Required fields are marked *