Friday, 12 May 2017

Getting the current context (SPHttpClient, PageContext) in a SharePoint Framework Service

I have briefly written about building SPFx services (using ServiceScopes) in my previous post, SharePoint Framework: Org Chart web part using Office UI Fabric, React and OData batching

In this post, lets have a more in-depth look at how to actually get the current SharePoint context in your service, without passing it in explicitly.

All the code used in this post is available on GitHub: https://github.com/vman/SPFx-Service-Context-Demo


Building an SPFx service using ServiceScopes:


Suppose you want to create a service which you want to call from multiple SPFx webparts. The idea is that the code of your service should load on the page only once even if multiple web parts using the same service are added to the page. There is already some great information out there on building such kind of service in SPFx so I won't repeat it here. Have a look:

Share data through a SharePoint Framework service

Building shared code in SharePoint Framework - revisited

I myself have been working on building an SPFx service as an npm package and then using it in a webpart:
https://github.com/vman/SPFx-Service

But before you go ahead and start using ServiceScopes to build your SPFx service, have a read through this Tech Note from the SPFx team:
https://github.com/SharePoint/sp-dev-docs/wiki/Tech-Note:-ServiceScope-API

To summarise, it is recommended to consider other alternatives first before using ServiceScopes. Other alternatives include explicitly passing in dependencies like SPHttpClient in the constructor of your service, or if your service has multiple dependencies, then build a class which has all the dependencies as properties and then pass an object of the class to your service's constructor.

While these recommendations would work in some scenarios, they might not be viable in all conditions. If you are building your service as an npm package, passing in the current context every time you want to use the service might be very burdensome. Ideally, your service should be able to determine all the information about the current context on its own. So lets have a look in this post on how do to that.

Quick note before moving ahead: Building library packages in SPFx is currently not available but it is on the roadmap. It would be nice to see the "build a library" option in the SPFx Yeoman generator. The UserVoice link for this request is here: https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform/suggestions/19224202-add-support-for-library-packages-in-the-sharepoint

In this post, to keep things simple, I am going to build my service in the same package as my SPFx webpart. The idea is to demonstrate the concept of using ServiceScopes to get the current context. It would work exactly the same if the service was part of a different SPFx package. If you want to have a look at how this works, have a look at my github repo here: https://github.com/vman/SPFx-Service


Getting the current context in an SPFx service:


Now that you have decided to build an SPFx service using ServiceScopes, lets have a look at how to get the current context in your service without passing it in explicitly.

First, you need to build a service which accepts a ServiceScope object in the constructor. This is the only dependency your service will need. Also, you will not need to explicitly pass in this dependency. SharePoint Framework will handle this for you.

Here is my code for the service:

Now lets have a look at what is going on in the code:

First, we are importing the SPHttpClient class from the @microsoft/sp-http package and the PageContext class from the @microsoft/sp-page-context package.

These classes expose their own ServiceKeys, so in the constructor of our service, we are using those keys to grab an instance of these classes. These instances of classes will already be initialised thanks to the ServiceScope.whenFinished and ServiceScope.consume methods. We can then use the instances in the methods of our class.

Using the current web url to initialise PnP-JS-Core :


Just as an example, you could use the initialised PageContext object to get the current web url and pass it to the PnP JS library. This can be useful if you want to get lists in the current web:



Consuming the service:


Now you have built your service, it is time to consume it from your SPFx web part. It is very straightforward, you just have to instantiate an object of your class using the ServiceScope.consume method and your are good to go. I am using async/await just to keep things simple, but using Promise.then will also work here:


Have a look at the complete code in this post here: https://github.com/vman/SPFx-Service-Context-Demo

Thanks for reading! Hope you have found this post helpful.

Friday, 28 April 2017

Error handling in SPFx when using TypeScript Async/Await

This is a quick follow up post to my previous post Using TypeScript async/await to simplify your SharePoint Framework code.

Since publishing my previous post, some folks have asked how would the error handling work when using async/await in SharePoint Framework. So decided to make this short how-to post.

At first glance, it is really straightforward, you essentially have to wrap your code in a try..catch block and the typescript compiler does the rest.

But there is something interesting here. Under the hood, SharePoint Framework uses the fetch API to make http requests. MDN has some great info on the fetch API if you haven't seen it already: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

What would be surprising for some (including me) is that the fetch API rejects the promise only when network errors occur. A "404 Not found" is considered as valid response and the Promise is resolved.

E.g. If you make a get request to a SharePoint list which does not exist, the fetch API (and the SharePoint Framework) will actually resolve your Promise.

A fetch() promise will reject with a TypeError when a network error is encountered, although this usually means permission issues or similar — a 404 does not constitute a network error, for example. An accurate check for a successful fetch() would include checking that the promise resolved, then checking that the Response.ok property has a value of true.

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful

There has also been some discusson on this on the SharePoint Framewok GitHub repo:
https://github.com/SharePoint/sp-dev-docs/issues/184

This is why, in addition to a try..catch block, you have to also check the Response.ok property of the returned Response. Here is the basic code you need to handle errors when using async/await:


What you can also do is, since the fetch API returns promises, you can use chaining to detect if the Response.ok property is false. Have a look at this post: Handling Failed HTTP Responses With fetch()

Update 6th May 2017: Here is a slightly more complex example where I have built a service with a custom get method which also handles errors for you:

And here is how to consume the service from your SPFx webpart:

Here is the GitHub repository for the service if you are interested:
https://github.com/vman/SPFx-Fetcher


Hope you find this useful!

Tuesday, 25 April 2017

Using TypeScript async/await to simplify your SPFx code

I recently learned about the Async/Await functionality in TypeScript and I was really surprised how easily you can simplify your code with it. Using Async/Await, you can get rid of spaghetti code as well as long chains of Promises and callbacks in your asynchronous functions.

The Async/Await functionality has been around since TypeScript 1.7 but back then it was only available for the ES6/ES2016 runtime. Since TypeScript 2.1, async/await works for ES5 and ES3 runtimes as well, which is very good news. I am kicking myself that I did not start using it sooner.

As with anything new I learn, I have tried to apply it to SharePoint as well to see how I can improve my development experience. Turns out using async/await can really make your SharePoint Framework code simpler and more readable. Lets have a look at some examples and compare between using Promises and Async/Await in your code.

Also, an important thing to note is that although I am making comparisons between using Promises and using async/await, ultimately the aync/await code is downleveled to using Promises by the typescript compiler. If the runtime does not have a native Promise object, we should make sure we have the right polyfills available.

The comparison here is more around code readability and conciseness.

All the code I am using is running inside a SharePoint Framework webpart. So, when you see the 'this' keyword in the code, it refers to my SPFx webpart which inherits from the BaseClientSideWebPart class. Since I am calling the code from inside my webpart, I have access to 'this'.

Here is my import statements for the code:


Simple example using Promises and 'then' callbacks:



Same code using async/await:



Here is a slightly more complex example with code which accepts an array of SharePoint login names and uses the batching framework to get the user profile properties of each user in the array.

You will need the IPerson interface for this:


Complex example using Promises and 'then' callbacks:



Same code using async/await:



As you can see, there is significantly less callbacks when using async/await and the code is also a lot more readable.

Hope you found this post useful. Thanks for reading!


Friday, 21 April 2017

Create/Update SharePoint list items with REST without the '__metadata' property

When updating list items in SharePoint with the REST API, we need to know the ListItemEntityTypeFullName of the list item we are planning to update. There are some good examples on MSDN regarding this https://msdn.microsoft.com/en-us/library/office/dn292552.aspx

The ListItemEntityTypeFullName property (SP.Data.ProjectPolicyItemListItem in the previous example) is especially important if you want to create and update list items. This value must be passed as the type property in the metadata that you pass in the body of the HTTP request whenever you create and update list items.

For example, when you want to update list items in a list called "MyCustomList" you need to know the ListItemEntityTypeFullName of the list items before hand. In this case, it will be SP.Data.MyCustomListListItem. Most examples around the internet do this by querying the list first and then getting the ListItemEntityTypeFullName property from it and using that in the call to update the list items.

If you do not specify the ListItemEntityTypeFullName, you get this error
An entry without a type name was found, but no expected type was specified. To allow entries without type information, the expected type must also be specified when the model is specified

The good news is that you only need to use the entity type full name when you are using "application/json;odata=verbose" as your Accept and Content-Type headers.

If you are using "application/json;odata=nometadata" in your Accept and Content-Type headers, then you do not need the ListItemEntityTypeFullName as well.

Here is are a couple of quick gists I have put together to show how we can create and update list items without specifying the ListItemEntityTypeFullName. I should mention I have tested these only in SharePoint Online at the time of this writing:

1) Create list item without specifying ListItemEntityTypeFullName



2) Update list item without specifying ListItemEntityTypeFullName


Wednesday, 12 April 2017

Send emails to authenticated external users using CSOM

Here is some quick code I put together to send emails in SharePoint Online to external users who have accepted sharing invitations and signed in as authenticated users.

Before having look at the code, I should mention my site collection has external sharing turned on and the "Allow external users who accept sharing invitations and sign in as authenticated users" option selected.


And here is the code:


Thanks for reading!

Monday, 23 January 2017

Working with the REST API in SharePoint Framework (SPFx)

The SharePoint Framework reached GA recently. You can see the release notes here: https://github.com/SharePoint/sp-dev-docs/wiki/Release-Notes-GA

One of these changes from the preview versions was how REST requests are handled when talking to SharePoint. Lets have a look at what changed and also see some code samples I created when tinkering around with the latest changes.

Before that, you should know that I have also updated my previous SPFx REST API related posts for the SPFx GA version. If you are interested, you can have a look here:

Batch REST requests in SharePoint Framework (SPFx) using SPHttpClientBatch

Making a POST request to SharePoint from an SPFx webpart

1) SPHttpClient, SPHttpClientConfiguration and the '@microsoft/sp-http' package


The HttpContext and all REST API related operations are part of the @microsoft/sp-http package.

The class SPHttpClient has inbuilt get and post methods which make it really easy to query SharePoint. The methods automatically add headers such as ODataVersion and Request Digest which are needed when making a REST call to SharePoint.

The SPHttpClientConfiguration class can be used to either let default headers be set on the REST request or it also allows you to override certain headers if needed. Lets have a look at this:

2) GET requests


Making GET requests to SharePoint is really easy when you specify the SPHttpClientConfiguration as SPHttpClientConfigurations.v1. It sets the following headers to your REST request. You don't have to set any headers manually.

consoleLogging = true;
jsonRequest = true;
jsonResponse = true;
defaultSameOriginCredentials = true;
defaultODataVersion = ODataVersion.v4;
requestDigest = true

First, you will need to import the required modules from the @microsoft/sp-http package as mentioned earlier:

Then use this code to make a GET request to SharePoint. The following code makes 3 different requests to SharePoint. The first one gets the current web, the second one gets the current user from the User Information List and the third one gets the current user properties from the User Profile Service:



3) POST requests


For making a POST request, you have to use the SPHttpClient.post method. I have a separate post around this. Check it out here: http://www.vrdmn.com/2016/08/making-post-request-to-sharepoint-from.html


4) Calling SharePoint Search REST API with OData Version 3


With the preview SPFx versions, the default OData Version attached with each SPFx REST request was 4. This caused the calls to the SharePoint Search REST Api to fail and return a "500 Internal Server Error" as the search API would only work with Odata Version 3.0.

The issue is discussed on GitHub SPFx repo here: https://github.com/SharePoint/sp-dev-docs/issues/44

As a result of that, SPFx now provides you a way to override the default headers sent with the REST request:

Thanks for reading! All the code for this, as always, is on GitHub: https://github.com/vman/SPFx-REST-Operations

Monday, 7 November 2016

Introducing: SharePoint Online Public CDN Manager

Update 24th March 2017: This post was updated since the general availability of the Office 365 Public CDN. The SPO CDN Manager now supports the GA version of the Office 365 Public CDN.

The Office 365 Public CDN recently reached General availability. It allows static assets like images, JavaScript, CSS etc. to be hosted in a globally available CDN. Find out more about it here.

With the general availability, the Office 365 PowerShell and SharePoint Online CSOM were also updated with APIs which could be used to manage the Public CDN.

Although the APIs are handy, what was missing was a nice and simple GUI to manage the CDN settings. So I set out to create an app which would give a nice overview of all the CDN settings including folders in the tenant which have been configured as Origins, file types which have been set to be pushed to the CDN and finally a way to enable/disable the CDN.

Introducing the SharePoint Online Public CDN Manager:


Check it out now: https://spocdnmanager.azurewebsites.net/




Checkout the code on GitHub: https://github.com/vman/SPO-CDN-Manager


As you can tell, the SharePoint Online Public CDN Manager can be used to:

1) Add/Remove CDN Origins i.e. SPO Libraries which will be used to store static assets.

2) Add/Remove File types. Which files will be pushed to the CDN.

3) Enable/Disable the CDN on a tenant.

4) Create the default CDN origins specified by the Office 365 Public CDN

The Implementation:


1) It is an MVC app which is Multi Tenant and hosted on the Azure App Service. It uses the March 2017 Release of SharePoint Online CSOM to talk to SharePoint.
https://dev.office.com/blogs/new-sharepoint-csom-version-released-for-Office-365-march-2017

2) For the UI, the Office UI Fabric core styles are used together with the Office UI Fabric JS Components



3) The app requires "Office 365 SharePoint Online" Full Control permissions on all site collections. This is because the CDN is a tenant wide setting and can be modified only by Tenant Administrators or SharePoint Administrators.



The app uses Delegated (User) authentication for every call to SharePoint so that only Tenant/SharePoint Administrators can access the CDN Properties:
So even if a user who is not an Admin lands on the page, they are not able to fiddle with the CDN settings.

Tenant vs Office365Tenant


Something interesting I came across while working on this. There are 2 classes available in CSOM now to manipulate tenant settings:

Microsoft.Online.SharePoint.TenantManagement.Office365Tenant

Microsoft.Online.SharePoint.TenantAdministration.Tenant

Both these classes have the Public CDN properties which can be used to manage the CDN. But the interesting this is that the Tenant class requires the Tenant Administration Url (https://yourtenant-admin.sharepoint.com) to instantiate but the Office365Tenant class can be instantiated by a regular site url in SharePoint Online. (https://yourtenant.sharepoint.com/sites/publishing)

If a regular SharePoint site url is used to instantiate the Tenant class, you get an exception saying:

Current site is not a tenant administration site.

This is why I have used the Office365Tenant class. Checkout the code on GitHub for more details.

Workaround for Internet Explorer "Quirks":


The SPO CDN Manager has been tested on latest version of Chrome, Edge and IE. It works without any issues on Chrome and Edge.

But, to get it working on IE, you will have to add the remote site https://spocdnmanager.azurewebsites.net to IE's trusted sites.

Thanks for reading! Hope you find the SPO CDN Manager useful.