Friday, October 13, 2017

Using Flow to promote better document sharing and collaboration in your organization

During lunch today I mentioned a customer sending me a document attachment in an e-mail, instead of what clearly should have been a sharing link to the file.

Outlook has excellent capabilities for sending sharing links instead of attachments, and especially internally in organization this should be the preferred approach to avoid e-mail bloat and multiple versions of the truth. Forcing people to change is not easy, but the conversation let to the following Flow urging your colleagues to do the right thing :)

image

Tuesday, October 10, 2017

Deploy a SharePoint Framework application customizer tenant wide

Creating application customizers which are available to all site collections is a very useful feature. Especially when it comes to site provisioning solutions. In my current project I’m creating a top banner which shows if the Office 365 Group is allowed to have external members, or if the team site can be shared with external users. This extension is installed on all new sites during creation.

Want to know more about a custom self-service solution for Office 365 Groups? Join me at ESPC November 16th 2017 where this post will be part of the solution demoed.

image

Wednesday, October 4, 2017

Adding images to SharePoint from a URL - mini life hack

Often you find yourself adding an image to SharePoint which you find on the internet. The upload dialog in SharePoint does not offer to link to a URL outside the domain you are on, so the workaround is to save the image locally, then upload.

At least if you are using Windows there is a quicker approach which usually works, and it also works in most other applications which allow you to upload a file.

Monday, October 2, 2017

Blocking vs. non-blocking Flows

Microsoft Flow has many triggers and one of the most useful ones is the HTTP request trigger, where an external party can call a specified endpoint with a message which will trigger the workflow. Basically this feature has two modes, one where the workflow executes logic and returns the outcome and the other where it does not need to return the outcome.

If you have an application which is translating text and you want the text back to the application you can create a Flow similar to the one below. A request which takes a string as input, the text is then translated to Norwegian, and returned at the end.

image

When running a REST query against the Flow URL using for example PowerShell we get the expected result back.

> $json = '{"thetext":"This is a test"}'
> Invoke-RestMethod -Method Post -Uri $uri -Body $json -ContentType "application/json"
dette er en test

This above operation is a blocking one. If you however want the translated text to be sent out as an e-mail, you remove the Response action and add an e-mail action.

image

When you now call the Flow URL you will immediately get a 200 success back, while the workflow executes the steps you have added. A non-blocking workflow.

Summary

If you want to use Microsoft Flow as an API in your application with input and output you can include both a Request and Response step. The calling application will then wait until a response is returned (or it times out). If you however want to use Microsoft Flow to execute an fire and forget action, omit the Response step, and the workflow will start executing while your calling application immediately can continue, regardless of what happens in the workflow.

Friday, September 22, 2017

Resolving assemblies when using PnP Core and ADAL / Graph

This is a super technical post and it goes like this:

image

If you use NuGet and reference PnP as well as ADAL and Graph clients as I have above, and you write code to apply a pnp template you might run into DLL hell and get the following exception:

"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."

The reason is that PnP take a dependency on both of these libraries, but on older versions. Deep in the code PnP uses reflection to find all serializer types, and it will throw up an assembly loader exception due to you having newer versions of these DLL’s in your project.

You can either align your dependency with what PnP uses, or you add an assembly redirect from the older to newer versions. Below is code which will dynamically resolve to the newest version for these issues.

Note: This assumes your version is newer than whatever PnP takes a dependency on

Add the code in a static constructor, or somewhere else which ensures it runs once for your application.

public static void RedirectAssembly()
{
    var list = AppDomain.CurrentDomain.GetAssemblies().OrderByDescending(a => a.FullName).Select(a => a.FullName).ToList();
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        var requestedAssembly = new AssemblyName(args.Name);
        foreach (string asmName in list)
        {
            if (asmName.StartsWith(requestedAssembly.Name + ","))
            {
                return Assembly.Load(asmName);
            }
        }
        return null;
    };
}

Funny part is that it now works fine for me without this code – but, just in case :)

Tuesday, September 19, 2017

Introducing a generic (mostly) all purpose extensibility schema for the Microsoft Graph

If you’ve followed my blog lately you know I’m experimenting with using Graph Extensions from the Microsoft Graph to persist metadata for resources in the graph, more specifically I’m storing metadata about different types of Office 365 Groups.

image

I decided to go with schema extensions over open extensions as this allows me to query and filter on my schema properties, instead of just reading and writing the properties. If you plan on only reading and writing data, I recommend using open extensions – why? Read on!

Wednesday, September 13, 2017

SharePoint Framework helper class for calling the Microsoft Graph

I’m creating a couple of web parts using SharePoint Framework in my current project so I figured I’d share a small helper class I created for performing GET requests against the Microsoft Graph. The code is written in TypeScript and handles single item results as well as paging on array results.

MSGraph.ts

import { GraphHttpClient, GraphHttpClientResponse } from '@microsoft/sp-http';

export class MSGraph {
    public static async Get(graphClient: GraphHttpClient, url: string) {
        let values: any[] = [];
        while (true) {
            let response: GraphHttpClientResponse = await graphClient.get(url, GraphHttpClient.configurations.v1);
            // Check that the request was successful
            if (response.ok) {
                let result = await response.json();
                let nextLink = result["@odata.nextLink"];
                // Check if result is single entity or an array of results
                if (result.value && result.value.length > 0) {
                    values.push.apply(values, result.value);
                }
                result.value = values;
                if (nextLink) {
                    url = result["@odata.nextLink"].replace("https://graph.microsoft.com/", "");
                } else {
                    return result;
                }
            }
            else {
                // Reject with the error message
                throw new Error(response.statusText);
            }
        }
    }
}

You can use the code as follows where I have extended the properties to include the web part context object in order to pass in graphHttpClient object.

import { MSGraph } from './MSGraph';

...

try {
  let groups = await MSGraph.Get(this.props.context.graphHttpClient, "v1.0/groups?$top=5");
} catch (error) {
  console.error(error);
}

Monday, September 11, 2017

An approach to working with Schema Extensions in the Microsoft Graph

I wrote a post last week about my issues with custom metadata and the Microsoft Graph. The week ended leaving me on the fence on which way to go. However, a couple of days off has sorted my brain a little bit, and I’ve had dialogs with the Graph team on these three Stack Overflow questions:

I think I’ve finally landed on using Schema Extensions and the approach below seems like something I can work with.

Friday, September 8, 2017

Making ESPC as easy as 1.2.3 – get 10% discount on checkout

Europe’s Largest SharePoint, Office 365 & Azure Conference is approaching fast. I’ll be presenting How to Take Control of Your Office 365 Groups – Using Technology to Solve Business Processes, a developer centric session on how you can control Groups creation and configuration using PowerApps, Flow, Azure Functions and PnP.

Here’s a few handy tips on how to make the most of your time at the conference.

Find out who’s going

Check out Twitter #ESPC17 to find out who’s going or visit the ESPC17 delegates page. If you would like to be added to this page, email your image and details to sarah@sharepointeurope.com There’s no better time to network with your peers, connect with new prospects, or touch base with customers than ESPC17. Don’t bank on running into them at the conference, reach out to them before and arrange a meeting.

Plan Ahead

Take a look at the conference schedule and decide the sessions and tutorials you would like to attend. Take note of their time so you can plan your meetings accordingly. If you are travelling with co-workers, split up and attend different sessions. You can swap notes after, allowing your company to get the most out of the conference.

Learn

Before the session, think of some questions you would like the answers to. Don’t be afraid to ask them during the Q&A, or alternatively go up and have a chat with the speaker afterwards. It is also important to take notes. A good practice is to write down the 3 most important takeaways from each session.

Socialize

With 2,000 people from the SharePoint, Office 365 & Azure community estimated to attend ESPC17, it is worth going to the after parties (The Black & White Party at the Guinness Storehouse on Wednesday 15th) and the many other great side-line and networking sessions, you never know who you’ll meet. Swap ideas, get advice and make those all-important contacts. Don’t be afraid to go up to a speaker or blogger and introduce yourself – they expect this at a conference.

Share what you learn

To capture maximum value for you and your company, schedule time to share what you’ve learned and even better, to go ahead and implement, as soon as you get back to the office. Organise an informal meeting with your colleagues and managers and share important takeaways from the conference.

image

Still haven’t made up your mind? Then visit 10 reasons to attend ESPC17 to see why you should be there. Then book your ticket today. Use coupon code ESPC17Speak on checkout to avail of a further 10% discount.

Thursday, September 7, 2017

Which schema to use in the Microsoft Graph for custom metadata: Schema Extensions or Open Extensions? Or maybe neither? I need help!

[Read my follow-up post at: http://www.techmikael.com/2017/09/an-approach-to-working-with-schema.html]

I’m trying to build out a solution for custom metadata for Office 365 Groups and it’s not that easy to do the right thing. My scenario is some worker process setting data, so I’m running in an app only context, not user delegated.

SNAGHTMLb983c97
If you don’t know what I’m talking about, Schema Extensions and Open Extensions are ways to store additional metadata to objects in the Microsoft Graph. Objects can for example be a user account, an e-mail message in Exchange or an Office 365 Group object. You persist the metadata with the object, not in some outside store.

Using Open Extensions is by far the easiest, as you can define your extension and the key/value pairs of data arbitrary, using the permissions of the object you are extending. The caveat however is that you cannot filter on these metadata. Say you added metadata to e-mail messages saying it’s customer related. Using Open Extension you cannot query to retrieve only those messages tagged. For me, not being able to filter is a blocker.

This is where Schema Extensions come in. Schema Extensions are typed schemas and you can indeed filter on them. But here are the issues I have experienced so far – I might be wrong about some of these, and base them off my testing. There is a whole lot more information about schema extensions on the old Azure AD Graph docs – which may or may not have solutions to my issues.
  • Schema Extensions cannot be created using app only permissions, so you cannot really automate it, and you might need a separate ADAL app to create it from the one you use for other automation.
  • A schema can not be used before it transitions from InDevelopment to Available.
  • You cannot delete a schema which has transitioned into being Available.
  • You cannot delete properties, only add new ones once a schema is made Available.
  • You cannot add a schema which is InDevelopment to for example an Office 365 Group object, making development harder.
  • Unless you have a verified domain of com, edu, net, org, you will end up with a random prefix for your schema extension. Which means you cannot easily filter to find the schema you created, but need to loop over all to find the one ending in your name. Unless you choose to record the name, but that won’t work for a generic solution across tenants.
In order to get the most flexible solution you might want to put metadata you need to filter on in a schema extension, and all others as open extension data. But this increases complexity as data are stored in two ways. Not the most ideal way to go, but a possibility.

Summary

While storing metadata in the Microsoft Graph seems like a good idea, as it reduces the number of moving parts, it might not be the best solution for every scenario. The ALM scenario for me right now is a bit in the wind, and perhaps storing the data outside the Microsoft Graph is a better and more flexible approach – even though I have to add more moving parts to the solution.

What’s your take?