Wednesday, November 27, 2019

How to specify BindingRedirects in Azure functions app settings via ARM template in automatic provisioning scenarios

If you face with famous problem with Newtonsoft.Json version mismatch in Azure functions (when Azure functions SDK requires one specific version and e.g. OfficeDevPnP requires other – you get error in runtime that Newtonsoft.Json.dll of version x.x.x.x is not found). There is solution for this issue posted here: Performing a binding redirect in Azure Functions. With this solution we have to add new app setting for Azure function which is string representation of JSON array:

{
    "BindingRedirects": "[ { \"ShortName\": \"Newtonsoft.Json\", \"RedirectToVersion\": \"11.0.0.0\", \"PublicKeyToken\": \"30ad4fe6b2a6aeed\" } ]"
}

It works but if you use automatic provision of Azure functions using template json file (see Azure Resource Manager template functions) and will want to specify it there like this:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "BindingRedirects": {
            "type": "string",
            "defaultValue": "[{ \"ShortName\": \"Newtonsoft.Json\", \"RedirectToVersion\": \"12.0.0.0\", \"PublicKeyToken\": \"30ad4fe6b2a6aeed\" }]"
        }
    }
}

you will see the following error:

Error occured when try to create Function app (error code 1):
Error: Code=InvalidTemplate; Message=Deployment template language expression evaluation failed: 'The language expression '{ "ShortName": "Newtonsoft.Json", "RedirectToVersion": "12.0.0.0", "PublicKeyToken": "30ad4fe6b2a6aeed" }
' is not valid: the string character '{' at position '0' is not expected.'. Please see https://aka.ms/arm-template-expressions for usage details.

The problem here is that BindingRedirects app setting use square brackets which at the same time are used by ARM template engine for specifying calculated values. Solution for this problem is to escape square brackets by double them i.e. instead of [ use [[ and instead of ] use ]]. Final version will look like this:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "BindingRedirects": {
            "type": "string",
            "defaultValue": "[[{ \"ShortName\": \"Newtonsoft.Json\", \"RedirectToVersion\": \"12.0.0.0\", \"PublicKeyToken\": \"30ad4fe6b2a6aeed\" }]]"
        }
    }
}

After that provision of ARM template for Azure functions will go well.

Monday, November 25, 2019

Authentication when publish nuget package to internal Azure packages feed

If you  want to use Azure packages feed for storing internal packages of your organization (https://{tenant}.pkgs.visualstudio.com) you will have to use nuget client as usual and authenticate yourself against Azure packages feed using your Azure AD credentials. However by default nuget.exe doesn’t support Azure authentication: it will ask you to enter username and password inside console Windows which will fail (it will just ask you to enter username and password again and again).

In order to enable Azure AD authentication with nuget client you will need to install authentication provider first. This page contains instructions how to do that: Azure Artifacts Credential Provider. Basically you need to download installcredprovider.ps1 PowerShell script to local machine and run it with “-AddNetfx” param:

installcredprovider.ps1 -AddNetfx

Note that “-AddNetfx” switch param is mandatory in most cases – otherwise credentials providers will be added only to .Net core and won’t work in regular Windows console client or PowerShell window.

After it will be done when you will run command to publish nuget package to Azure:

nuget push -Source "MySource" -ApiKey az PackageName.nupkg

it should show standard authentication popup window where you will be able to enter your Azure AD credentials. And after that publish to Azure nuget packages should succeed (of course if you have permission to push packages to this feed).

Tuesday, November 12, 2019

Why you should be careful with /groups/{id}/photo and /users/{id}/photo endpoints in MS Graph or unintentional getting photos of big sizes in Graph

As you probably know we may retrieve groups and users photos via Graph API using the following endpoints (see Get photo):

GET /users/{id | userPrincipalName}/photo/$value
GET /groups/{id}/photo/$value

Note however that Graph stores photos of different sizes:

The supported sizes of HD photos on Office 365 are as follows: 48x48, 64x64, 96x96, 120x120, 240x240, 360x360, 432x432, 504x504, and 648x648.

and if we use default /photo endpoint it will return biggest available photo, i.e. 648x648. Depending on your scenario it may not be what you actually need as if you just need to display group logo or group member photo smaller images e.g. of 64x64 pixels size will be enough. And if you work with big photos of 648x648 size and reduce its size by css – page size may be very big and browser memory consumption will be much bigger:

So instead of using default /photo endpoint in MS Graph you may consider using of endpoints which return photo of specified smaller size:

GET /groups/{id}/photos/64x64//$value

or with Graph client library in .Net app:

var stream = Task.Run(async () =>
{
 var photo = await graphClient.Groups[groupId].Photos[Constants.GRAPH_IMAGES_CACHE_PHOTO_ID].Content.Request().GetAsync();
 return photo;
}).GetAwaiter().GetResult();

This code will return small image which may be more appropriate for your scenario:

Compare also sizes for big 648x648 image and small 64x64 image: 10Kb vs 2Kb.

Thursday, November 7, 2019

Quick way to upload user photo for making it available through Graph API /user/{id}/photo endpoint

If you want to test fetching of users photos via Graph API you may need to upload this photos so they will become available through Graph endpoints (see Get photo):

GET /me/photo/$value
GET /users/{id | userPrincipalName}/photo/$value
GET /groups/{id}/photo/$value

Of course you may do that programmatically using PUT requests like shown here:

PUT /me/photo/$value
PUT /users/{id | userPrincipalName}/photo/$value
PUT /groups/{id}/photo/$value

but if you need to do it quickly without developing tool for that you may use standard UI and upload photo from user’s Delve profile page:

1. Click icon with your account in top right corner and select My Office profile:

2. You will be redirected to your accounts Delve profile page:

3. On this page click “Upload a new photo” icon and upload photo of the user.

After that it will be possible to get users photos via Graph endpoints including photos with different sizes.

Friday, October 11, 2019

Problem with creating new content database for web application in Sharepoint and Full recovery mode

If you want to create new content database for web application using New-SPContentDatabase cmdlet you should be aware of one side effect related with this action: new content database will be created with Full recovery mode by default even if your basic content database has Simple recovery mode:

With Full recovery mode transaction log will grow quite fast until you will do full backup. It may be significant consideration for large content databases. So before to start using it you may want to change recovery mode of additional content database to Simple. If you moved existing site collection there using Move-SPSite – transaction log already may be quite big. So after changing recovery mode you may also need to shrink log file.

Friday, October 4, 2019

How to test and debug Timer triggered Azure functions running locally on localhost

With Azure function project type we may create many types of Azure functions. One of them is Timer triggered Azure function which is triggered by scheduler (CRON expression is specified during function creation and may be modified later in Azure function attribute):

When you will run this function locally (on locahost) you will notice thatt it won’t be listed under

http://localhost:7071/api/*

address together with Http triggered Azure function. Runtime will call your function automatically when schedule time will come. But this is not very convenient since during development you would probably like to have possibility to call it synchronously on demand.

In order to call Timer triggered Azure function you may use Postman tool. You have to construct URL little bit different from Http triggered functions: instead of /api you should send POST request to http://localhost:7071/admin/functions/* base url and send the following request body:

{
    "input": ""
}

Using this technique you may debug your Timer triggered Azure functions synchronously.

Wednesday, October 2, 2019

Different nuget packages of Camlex.Client library for different Sharepoint versions

There is excited news for those Sharepoint developers which use Camlex in their work: now Camlex.Client library (Camlex version for CSOM) is available for each Sharepoint version as separate nuget package:

Sharepoint versionNuget package
2013 on-prem Camlex.Client.2013
2016 on-prem Camlex.Client.2016
2019 on-prem Camlex.Client.2019
SPO Camlex.Client.dll

Before it was only Sharepoint Online version Camlex.Client.dll (see here). May be it is more logical to call it package for SPO version Camlex.Client.Online but since this package exists quite a long time I left it to keep backward compatibility.

So now for targeting correct Sharepoint version you may just add appropriate nuget package to your project and work with it. Each package contains Camlex.Client.dll assembly which is compiled using appropriate versions of CSOM (Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll). This approach is similar to those which is used e.g. in OfficeDevPnP which uses different nuget packages for each Sharepoint version.

This feature is well wished feature and was requested many times so probably many developers will find it useful. The only reason which prevented me to do it earlier is that it will increase maintenance time and as I’m the only developer who maintains the project it is quite significant. But now time has come and now with each new release all 4 nuget packages for Camlex.Client will be updated.