AL Extensions: Accessing the Device Camera

If you’ve been doing any V2 extension development, you like are aware that we cannot use any .Net interop in our code.

While on premise V2 development will eventually gain access to .Net variable types, if you’re coding your extension to run in AppSource, you will remain locked away from using .Net interop in your code because the risk of these external components is too large for shared cloud servers.

Unfortunately this means that we lost the ability to interact with the device camera, as it was accessed using .Net.

In C/AL, the code to take a picture with the device camera looked like this:

TakeNewPicture()
   IF NOT CameraAvailable THEN
      EXIT;
   CameraOptions := CameraOptions.CameraOptions;
   CameraOptions.Quality := 50;
   CameraProvider.RequestPictureAsync(CameraOptions);

It’s simple enough code, but the problem in the above example is that both CameraProvider and CameraOptions are .Net variables, and therefore cannot be used in V2 extension development.

I’m happy to say though that this problem has been resolved. Yes, the underlying architecture still uses .Net controls, but Microsoft has introduced a new Camera Interaction page which acts basically like an api layer. Through this api layer you can interact with the .Net camera components just as you did in C/AL.

Not a huge change to wrap your head around at all. In your extension you will code against the Camera Interaction page instead of against the .Net controls directly. Inside the page are all the original camera functions that you were used to using before.

This greatly simplifies our extension code and allows us now to use the camera from our extensions.

The code to take a picture would now look like this:

local procedure TakePicture();
    var
        CameraInteraction: Page "Camera Interaction";
        PictureStream: InStream;
    begin
        CameraInteraction.AllowEdit(true);
        CameraInteraction.Quality(100);
        CameraInteraction.EncodingType('PNG');
        CameraInteraction.RunModal;
        if(CameraInteraction.GetPicture(PictureStream)) then begin
            Picture.ImportStream(PictureStream, CameraInteraction.GetPictureName());
        end;
    end;

That’s it! Now you can use the device camera from your V2 extensions.

Happy coding!

Advertisements

Enable Personalization in the Dynamics NAV 2018 Web Client

The recent release of Microsoft Dynamics NAV 2018 has brought a lot of improvements to the Web Client, one of those being the ability for users to (finally!) do personalization directly in the client. No longer do they need to jump over to the Windows Client for that!

If you have installed NAV 2018 though, you might be wondering how you do the personalization. Well….it’s not enabled by default.

To enable it, you need to modify the Web Client configuration, which is done within the new navsettings.json file. Yes, out with the old web.config and in with the new json-based file! Read more about this here.

You have 2 options for changing the configuration:

Edit Configuration File Directly

To edit the Web Client configuration directly, open the navsettings.json file and add the following line:

"PersonalizationEnabled": "True"

The default location for the json file is here:
%systemroot%\inetpub\wwwroot\[WebServerInstanceName]

After you have changed the file, save it, and then restart the Web Client website via IIS, or by executing iisreset at the command prompt.

Using PowerShell

As I’m a huge fan of PowerShell, this is my preferred method of doing pretty much anything. Using the Dynamics NAV 2018 Development Shell (in admin mode of course), you can use the Set-NAVWebServerInstanceConfiguration commandlet to update Web Client configuration.

To enable personalization, you would run the commandlet like this:

Set-NAVWebServerInstanceConfiguration `
     -Server [MyComputer] `
     -ServerInstance [NAVServerInstanceName] `
     -WebServerInstance [MyNavWebServerInstance] `
     -KeyName PersonalizationEnabled `
     -KeyValue True

For more details on the full commandlet syntax, look here.

Performing Personalization

Once you do one of the above steps, you’ll be able to log into the Web Client and select the Personalize action, which is found at the top of the Web Client under the settings cog:

EnablePersonalization1

That’s all there is to it.

Happy coding!

AL Extensions: Importing and Exporting Media Sets

One of the things that has changed when you are building V2 extensions for a cloud environment is that you cannot access most functions that work with physical files.

This presents a bit of a challenge when it comes to working with the media and media set field types, as the typical approach is to have an import and export function so that a user can get pictures in and out of the field.

An example of this is the Customer Picture fact box that’s on the Customer Card:

WorkingWithMediaFields1

As you can see, the import and export functions in C/Side leverage the FileManagement codeunit in order to transfer the picture image to and from a physical picture file. These functions are now blocked.

So…..we have got to take another approach. Enter streams.

Using the in and out stream types we can recreate the import and export functions without using any of the file based functions.

An import function would look like the following. In this example, the Picture field is defined as a Media Set field.

local procedure ImportPicture();
var
   PicInStream: InStream;
   FromFileName: Text;
   OverrideImageQst: Label 'The existing picture will be replaced. Do you want to continue?', Locked = false, MaxLength = 250;
begin
   if Picture.Count > 0 then
     if not Confirm(OverrideImageQst) then
       exit;

  if UploadIntoStream('Import', '', 'All Files (*.*)|*.*', FromFileName, PicInStream) then begin
    Clear(Picture);
    Picture.ImportStream(PicInStream, FromFileName);
    Modify(true);
  end;
end;

The UploadIntoStream function will prompt the user to choose a local picture file, and from there we upload that into an instream. At no point do we ever put the physical file on the server. Also note that the above example will always override any existing picture. You do not have to do this as media sets allow for multiple pictures. I’m just recreating the original example taken from the Customer Picture page.

For the export we have to write a bit more code. When using a Media Set field, we do not have access to any system function that allows us to export to a stream. To deal with this all we need to do is loop through the media set and get each of the corresponding media records. Once we have that then we can export each of those to a stream.

That would look like this:

local procedure ExportPicture();
var
   PicInStream: InStream;
   Index: Integer;
   TenantMedia: Record "Tenant Media";
   FileName: Text;
begin
   if Picture.Count = 0 then
      exit;

   for Index := 1 to Picture.Count do begin
      if TenantMedia.Get(Picture.Item(Index)) then begin
         TenantMedia.calcfields(Content);
         if TenantMedia.Content.HasValue then begin
            FileName := TableCaption + '_Image' + format(Index) + GetTenantMediaFileExtension(TenantMedia);
            TenantMedia.Content.CreateInStream(PicInstream);
            DownloadFromStream(PicInstream, '', '', '', FileName);
         end;
      end;
   end;
end;

We use the DownloadFromStream function to prompt the user to save each of the pictures in the media set. As in our first example, there are no physical files ever created on the server, so we’re cloud friendly!

You may notice that I use the function GetTenantMediaFileExtension in the export example to populate the extension of the picture file. Since the user can upload a variety of picture file types, we need to make sure we create the file using the correct format.

The function to do this is quite simple, however there is no current function in the product to handle it, so you’ll have to build this yourself for now. Hopefully in the near future this function will be added by Microsoft.

local procedure GetTenantMediaFileExtension(var TenantMedia: Record "Tenant Media"): Text;
begin
   case TenantMedia."Mime Type" of
      'image/jpeg' : exit('.jpg');
      'image/png' : exit('.png');
      'image/bmp' : exit('.bmp');
      'image/gif' : exit('.gif');
      'image/tiff' : exit('.tiff');
      'image/wmf' : exit('.wmf');
   end;
end;

Until next time, happy coding!

 

Dynamics NAV 2018 Available Now

Microsoft Dynamics NAV 2018 is now available for download!! You can download it here, or visit the Get Ready For Dynamics NAV site for more information.

Other resources of interest:

Happy coding!

 

Dynamics NAV 2018 on the way!

After delivering a message at Directions NA 2017 that the typical October release if Dynamics NAV would be delayed until spring if 2018, an article posted by Alysa Taylor (GM of Global Marketing) confirms now that there will be a release of Dynamics NAV 2018 by the end of the current center year.

Check out the full article here.

This is a great response by Microsoft to address what was largely a negative reaction to the Directions announcement, and confirms that they are listening to our feedback!