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;

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


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.

Friday, September 20, 2019

Fix The EntityContainer name must be unique EF error in Sharepoint

If you use Entity Framework in Sharepoint (I described one useful technique which simplifies usage of EF in Sharepoint in this article: Build connection string for Entity Framework programmatically via code or use Entity Framework in Sharepoint Timer jobs) you may face with the following error:

The EntityContainer name must be unique. An EntityContainer with the name '…' is already defined

Although in your project (class library which you install to GAC for using it in Sharepoint) there is single entity container with specified name.

The problem is that entity container name appears to be unique within project boundaries. I.e. if you have another project which is compiled and installed to the GAC and loaded to the same app domain and which uses the same metadata for Entity Framework data model like:


and then install another assembly to the GAC with the same EF data model metadata – you will get the above error when second project will be loaded to Sharepoint site’s app domain. This is not that obvious that you have to use unique name for EF entity containers across all assemblies used in Sharepoint. Solution for this problem is to rename EF data model in second project so it will have unique name:


After that your code will start working in Shrepoint.

Thursday, September 12, 2019

Use Office 365 connected groups in Yammer

Yammer platform allows you to integrate your Yammer groups to Office 365. Technically it means that each time when new Yammer group will be created it will be also created in Azure AD of the tenant of this Yammer network. More information about Yammer and O365 groups can be found in this article: Yammer and Office 365 Groups. This article also contains information how to enable Office 365 connected groups in Yammer and which conditions should be met before you will be able to enable it:

  • You must enforce Office 365 identity for Yammer users. When you first enforce Office 365 identity there is a seven-day trial period, after which the Status of your Office 365 Identity Enforcement changes to Committed.
  • Your Yammer network must be in a 1:1 network configuration. This means you have one Yammer network that is associated with one Office 365 tenant.

Note that currently it is possible to enforce Office 365 identity for Yammer users without 7 days trial i.e. right away.

In order to enable Office 365 connected groups in Yammer it you need to login to your Yammer network with administrator account and go to Network settings (gear icon in top left) > Network Admin > Security setting. On this page at first we need to enforce Office 365 identity for Yammer users:

Once it’s status will be changed to Committed after some time “Office 365 Connected Yammer Groups” setting will be changed to Enabled:

Documentation above says that it takes up to 24h to change status to Enabled. But in my case it was changed quite fast: almost immediately after enforcing of Office 365 identity for Yammer users.

Let’s see what happens when “Office 365 Connected Yammer Groups” setting is disabled for your Yammer network. When you create new Yammer group:

this group won’t be found in Azure AD of the Yammer network’s tenant:

After Office 365 Connected Yammer Groups have been enabled Yammer groups will appear in Yammer:

So you will be able to use all advantages of O365 connected groups. Note that for those Yammer groups which already exist when O365 connected groups had been enabled also appropriate O365 groups will be created after some time. Documentation says that it may take up to 1 week:

After about 1 week, existing eligible groups will be converted to Office 365 groups.

but for me it also happened quite fast within 1 hour or so.