Wednesday, August 23, 2017

SharePoint Online: New web service to scale images

I guess I was still in my wintersleep in Februari when this was released, but there is a new webservice available in SharePoint Online for rendering optimal-sized images for any device/screen resolution (image renditions don't work well for this )

You can use this in order to minimize the amount of bits sent to your users, especially for mobile users. Or you could use it to minimize the risk of terrible performance when a content editor adds a 6MB image to your site.

The location is https://yourtenantname.sharepoint.com/_layouts/15/getpreview.ashx . This location is virtual so the service exists in any site collection (NB. so also at https://yourtenantname.sharepoint.com/sites/yoursite/_layouts/15/getpreview.ashx )

If you read the following posts you can learn how to use it with a Path query variable pointing to the URL of the image or with three guids that identify the image file.

Image renditions available - this article also contains the available resolution codes.

Generate thrumbnail from URL in SharePoint

This is an example URL: https://MYTENANT.sharepoint.com/_layouts/15/getpreview.ashx?path=https%3A%2F%2FMYTENANT.sharepoint.com%2Fsites%2FJurgenCommSiteTest%2FSiteAssets%2FSitePages%2FTest-nieuws%2F627-large_9051a70d15cd9b67ba2097efb9e6c74c488d7267.jpg&resolution=6

Note the Path query variable that holds a URL encoded locator of the file and the Resolution which should be a value from 0 to 6.

So you can easily use this new webservice in your display templates or other (JavaScript) code to allow a user a fast download of an optimal size image.




Wednesday, August 9, 2017

Run asynchronous code on schedule with Azure WebJobs

This short post describes how you can have a scheduled Azure WebJob that runs an asynchrouns method.

The problem with this scenario is that the WebJob, which is just a regular console application, cannot have an asynchronous Main method. So you need a way around that. Next to that you would to be able to trigger that method with a schedule.

In my solution I use a Settings.job text file that is in the root folder of the WebJob (Set copy to out put directory to 'Copy Always' in the properties of the file in Visual Studio.
The contents of the file contain JSON with a cron expression like so:
{
    "schedule": "0 0 6/12 * * *"
}
This is set to every twelve hours starting from 6:00. So far so good, and nothing you probably havent seen before or in other blogs.

Now suppose you used the Visual Studio template to generate the WebJob Project. This creates the main Program.cs file and also a Functions.cs file. The Functions file is meant for you to register yor methods that serve as triggers. I tried using the TimerTriggered function like below, but the result wasn't that good. If you Run and block the JobHost in the Program.cs (as is done in the VS template), this means that your job will always show a running state and the timertrigger will go off, but only if it's within the time out period of the webjob which is 120 seconds. So that is a crap solution.

Instead, define a manual trigger with the tag [NoAutomaticTrigger]. We will call this method from the Main method. Notice that this method is asynchronous. I use code in there to fetch from a API and save back to a different service that I already wrote and that is asynchronous.

public class Functions
    {
        public static async Task TimerTriggered([TimerTrigger("0 0 6/12 * * *")] TimerInfo timer, TextWriter log)
        {
            await Functions.RunJob(log);
        }

        [NoAutomaticTrigger]
        public static async Task ManualTrigger(TextWriter log)
        {
            await Functions.RunJob(log);
        }

Now, code your Main method in Program.cs to call and await the method, using the JobHost.CallAsync method inside a Task.Run delegate.

class Program
    {
        static void Main()
        {


            var host = new JobHost();
            Task aTask = Task.Run(() => host.CallAsync(typeof(Functions).GetMethod("ManualTrigger")));

            aTask.Wait();          
        }
    }

The solution is to use the Task class to run and await the asynchronous method. With the JobHost.CallSync you can call the method in another class. Parameters like the TextWriter are passed by the JobHost.