How to use Remote Event Receivers with .NET Core (or .NET 5) and PnP.Framework

In June 2020, a .NET Standard version of SharePoint CSOM was released. It means that now we can build projects for SharePoint, that target multiple platforms. At the beginning of 2021, a .NET Standard version of PnP-Sites-Core was also released (with a brand new name PnP.Framework and an updated codebase). However, there are some limitations in the .NET Standard version of SharePoint CSOM. Especially the lack of Remote Event Receivers (RER). The whole namespace was dropped. In some cases, you cannot replace RER with Webhooks without loss of functionality. Sometimes you just need RER or you're upgrading your code and cannot migrate RERs to webhook, since that's expensive. 

So, let's bring support of Remote Event Receivers back to .NET Core \ .NET 5+.

The source code sample for this blog post is available at GitHub here (the master branch contains code for .NET Core, if you're looking .NET 5 sample, use net5 branch). More...

Simplify secret keys management for M365 applications with Azure Key Vault and Azure Managed Identity

Azure Key Vault simplifies a lot of things when it comes to secrets, passwords, certificate management. There are a lot of different ways of using it for different apps or services. In this post I'm going to cover below scenario: 

  • we have a service, running in the background, which connects to SharePoint API and performs some operations. As a good example, it might be a SharePoint PnP provisioning process running as a daemon through azure functions or azure web job
  • the provisioning process uses Application permissions to access SharePoint API, thus uses certificate-based authentication through Azure AD auth
  • all authentication secrets (certificate in our case) are stored in Azure Key Vault 
  • we do not store any secrets anywhere except Azure Key Vault (not locally in code and not in the azure function or job configuration)
  • we use a brand new PnP Framework!

Interesting? Then please read further below. More...

SharePoint Column Formatting tips: How to hide checked out documents

I had a need to hide all documents, which were checked out by users. With help of Column Formatting. When you check out documents, SharePoint sets a special field called CheckoutUser to be equal to a person, who checked out the document. The idea is to check if this field is null and hide a row in a view. 

However, the idea didn't work for some reason. The problem is, that CheckoutUser is a people field. In other words, it's a "complex" field and contains additional properties, like the user's email, id, etc. 

The trick was to use the email property of that field, to check if it's empty or not. In short:

"display": "=if([$CheckoutUser.email] != '', 'block', 'none')"  

Having below full formatting JSON:

spoiler (click to show)
{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/view-formatting.schema.json",
  "debugMode": true,
  "hideSelection": true,
  "hideColumnHeader": true,
  "rowFormatter": {
    "elmType": "div",
    "attributes": {
      "class": "ms-borderColor-neutralLight"
    },
    "style": {
      "box-sizing": "border-box",
      "display": "=if([$CheckoutUser.email] == '', 'block', 'none')",
      "width": "100%",
      "border-width": "1px",
      "border-style": "solid",
      "padding": "0 0 0 20px",
      "margin-bottom": "10px",
      "align-items": "stretch"
    },
    "children": [
      {
        "elmType": "div",
        "style": {
          "flex": "1 0 300px",
          "display": "flex",
          "flex-wrap": "wrap"
        },
        "children": [
          {
            "elmType": "div",
            "style": {
              "flex": "1 0 300px",
              "box-sizing": "border-box",
              "padding": "10px"
            },
            "children": [
              {
                "elmType": "button",
                "attributes": {
                  "class": "ms-fontSize-xl"
                },
                "style": {
                  "line-height": "1.5em",
                  "margin-bottom": "1em",
                  "border": "0",
                  "padding": "0px",
                  "color": "#0077ff",
                  "background-color": "transparent",
                  "cursor": "pointer"
                },
                "txtContent": "[$FileLeafRef]",
                "customRowAction": {
                  "action": "defaultClick"
                }
              },
              {
                "elmType": "div",
                "attributes": {
                  "class": "ms-fontSize-s"
                },
                "style": {
                  "line-height": "1.5em",
                  "margin-bottom": "8px"
                },
                "txtContent": "='Modified by ' + [$Editor.title] + ', ' + toLocaleString([$Modified])"
              }
            ]
          },
          {
            "elmType": "div",
            "style": {
              "flex": "0 0 170px",
              "display": "flex",
              "flex-direction": "column"
            },
            "children": [
              {
                "elmType": "button",
                "customRowAction": {
                  "action": "editProps"
                },
                "txtContent": "Edit Properties",
                "attributes": {
                  "class": "sp-row-button ms-bgColor-neutralLighter ms-fontWeight-semibold"
                },
                "style": {
                  "width": "145px",
                  "height": "32px",
                  "margin": "20px 0 10px 0"
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

When applied, one checked out document was hidden:

Hope this little trick will help you build a little bit better column/view formatting experience. 

Title image credits - Solution Vectors by Vecteezy

SharePoint development state in 2020: story based on sharepoint.stackexchange analysis with Power BI

The year 2020 is over and once again it's time to perform regular analysis of data at sharepoint.stackexchange. This is the fourth edition of such an analysis. 

Tools used to collect and analyze data: 

  • Power BI with Power BI Desktop - super cool tools for data analysis. If you don't have experience with Power BI, it's worth trying to see what is possible. When I first tried it a few years ago I was sooo impressed with power yet simplicity in performing data analysis and building visualizations. It works very well for both simple and advanced scenarios. I believe that everybody will find these tools useful for any kind of data analysis. 
  • DaxStudio - an extremely useful tool to test your DAX queries. 
  • Power BI Community - Power BI has a very strong community. I found a lot of answers at their forum, I even asked some questions and community helped with valid answers. That's not a "tool" but worth mentioning. I am grateful for all the answers.
  • Stack Exchange API

The source code used to gather initial data is available at GitHub. More...

SharePoint Framework fast serve now supports library components

A few months ago I created a tool, which speeds up a regular "gulp serve" process. In a nutshell, it uses a separate webpack based build. Please read this post to learn more. Since the initial release, I've fixed a few good things and added new features. The most awaited is library components support. Read further to find out how to use spfx-fast-serve with library components. 

You can manage library components in two different ways: with a special multi-package manager (Lerna.js) or without. Lerna is not the only multi-package manager, there is also Rush.js, however I know Lerna, I wrote a blog post on how to use Lerna with library components before, Lerna is simple and has least issues when working with SharePoint Framework. More...

SharePoint Framework, webpack 4 and tree shaking

In August 2019 SharePoint Framework 1.9.x was released. Among different changes also support for Webpack 4 was introduced. What does it mean for us? It means slightly improved build speed, support for a wide range of plugins and better tree-shaking. 

What is webpack tree-shaking exactly? In simple words, webpack is smart enough to automatically remove "dead modules" (in other words unused code/modules) from your resulting bundle. It reduces the size of the resulting bundle, thus improves load performance. More...

Styling SharePoint Framework components using CSS in JS approach

Intro

A very common way of styling your SharePoint Framework React components is through the css (to be precise sass, which eventually compiles to css). Actually, SharePoint Framework goes one step further and suggests something called css-modules. As you know, for a default web part we have a file called <Component Name>.module.scss. We write styles in that file and SharePoint Framework build pipeline generates corresponding TypeScript interface for us to use inside React component as 

className={styles.myButton}

SharePoint Framework ensures that a class name will be unique, that way we isolate our styles from the "outside world" and have them scoped to this specific component:

However, it's not the only way of styling your components using isolated scopes. Nowadays the approach when you write your css styles in code (in .js or .ts files and not in .css or .scss) becomes more and more popular and has a number of benefits: More...

SPFx overclockers or how to significantly speed up the "gulp serve" command

A few months ago I wrote an article about SharePoint Framework build performance - SPFx overclockers or how to significantly improve your SharePoint Framework build performance. I've tried to reduce the amount of time the "gulp serve" command uses to re-build your code and to finally refresh a browser. I used different optimization technics for that purpose. The idea was to tweak the default SPFx build pipeline. However, those post only partially solves the problem. 

In this post, I will solve the problem from another way around (spoiler: I managed to make "serve" 10-15 times faster). 

The idea

How SharePoint Framework's "gulp serve" works? It gets your sources and outputs javascript bundles. But "gulp serve" becomes slow when your solution grows. How to fix that issue? Well, since it's slow, then don't use it! 

So this is the idea - don't use "gulp serve", use completely custom webpack based build to transform your sources into exactly the same javascript bundles which are produced by "gulp serve". 

What is the input for "gulp serve"? - TypeScript sources, styles. What is the output? - Javascript files. Can we get sources and produce exactly the same javascript? -Yes.

How it works

Some nerdy content goes below. If you don't want to read about internal implementation, go directly to "How can I use it?"

To make it work, we need custom webpack config and webpack dev server to serve webpack output. More...

SharePoint Framework and React hooks. Should I care?

SharePoint Framework 1.9 introduced support for React 16.8+. While only a minor part of the version was changed (16.7 -> 16.8), it means a lot. It means that you can use the full power of React hooks. But should you? Obviously, the answer is yes, because React hooks introduce a lot of useful features, including:

  • reuse stateful logic across your many React components, which isn't possible with class-based components
  • get rid of high-order components, you can move some logic out of your React components into custom hooks. All that makes your code cleaner
  • all your React components now are in the same style (you don't mix class-based components with functional). Instead, you use only functional components, because they support state (with help of hook of course)

There are even more reasons going to hooks, instead of class-based components. Check out official documentation from React:

Should I use Hooks, classes, or a mix of both?

....we’d encourage you to start trying Hooks in new components you write. ....In the longer term, we expect Hooks to be the primary way people write React components.

Hooks are available starting from February 2019. A lot of libraries adopted their code to hooks. You are on the safe side if you're planning to use hooks in your code today. More...