March 2019 - Posts

My blog site has been around for quite a long time.  It started as a conversation at a bar by Kyle Kelin, the Dot Net Mafia's original purpose was to provide a site to rank and review recruiters known for being shady and lying to both candidates and clients.  That concept never took off but we decided to use the name sometime around 2008 to provide a blogging platform for a group of us including Kevin Williams, Tony Kilhoffer, James Ashley, Kyle Kelin, and Cory Robinson.  For a time, we had a nice active blogging platform and many of us participated.  With the exception of myself though, I was really the only one that kept blogging.  If you look back at, you will see that I have content dating all the way back to December of 2004.  Before I really started blogging officially, I used to write small articles using a SharePoint 2003 announcements list for our small team of .NET developers at Dollar Thrifty Automotive Group.  We were making the transition from ASP.NET 1.1 to ASP.NET 2.0 and this is where I showed tips to my team.  It was simple but it worked.  Some of the posts are pretty cheesy and they don't really have any relevance any more but I've kept them around for nostalgia's sake.

After most of my team including myself left Dollar Thrifty Automotive Group at the end of 2005, I created my own lightweight content management system built in ASP.NET 2.0 running in the data center hosted by Isocentric Networks where I worked for a while.  Through their generosity, they came my VM running for years.  Later I migrated it to an Azure Virtual Machine.  I somehow exported my content from the SharePoint announcements list and imported it into a SQL database.  That worked well until the DotNetMafia concept came around. was based on Community Server by Telligent.   For a while it was the go-to solution for blogs in the technical community.  Honestly, I don't know how I was able to import the content into Community Server.  It's there though.  As you might remember though, they changed ownership and took the free product away and the community dropped them as fast as possible.  You don't see many sites running on it any longer.  About 6 years ago, I looked at trying to upgrade it to a newer version and it proved to be more trouble than it's worth.  

I've been trying to get off of Community Server for years.  The site isn't mobile friendly.  It's no longer supported and it's really starting to show its age.  With over 1000 posts, I have built up a lot of SEO over the years and that's hard to give up.  Ideally I wanted to bring in all of my content AND maintain the URLs.  That's just not going to happen and it doesn't need to.  The world was a lot different 10 years ago and the brand DotNetMafia needs to go.  Moving forward, I'll do all of my blogging from a WordPress site at and eventually I'll figure out how to import my content.  There are very few resources on how to make this happen.  The content is in a SQL database.  If I can extract it out and possibly get it into an OPML format, I might be able to get my content imported.  In the meantime, I'll try to cross-post where I can, but has a shelf-life like InfoPath.  We'll keep the VM hosting it around until I get tired of paying for it. doesn't have a lot of content yet, but it will.

For those that know me, you might have heard about my extensive use of Ionic Framework, a mobile app platform, to build various side projects including BrewZap and HappenZap. If you aren’t familiar with Ionic Framework, it’s a node.js based development framework for mobile apps. Ionic was originally built using AngularJS and then modern versions of Angular. With it’s recent release of 4.0.0, Ionic has made the shift to web components. This has allowed Ionic to support other frameworks such as React and Vue. I’ve been trying to get Ionic Framework to work inside SPFx on and off for about two years now. Now with SPFx 1.8 and React 16.7.0, all of the dependencies have lined up and it is in fact possible using the new Ionic React.


with no comments

If you have ever used Office Fabric with SPFx, you may have found yourselves struggling.  You quickly learned than previous version of SPFx did not work with version 6+ of Office.  Instead you had to use the LTS version of Office Fabric which varies significantly from version 6.  What make this such a pain point is that there isn't really any documentation on the Office Fabric site that tells you that.  Instead you just installed it, tried it out, and couldn't figure out why things weren't working until you did an Internet search.  In addition what made things even harder is that many of the parameter and function names have changed between version 5 and 6.  The documentation only covers what's in version 6.  Some functionality flat-out isn't there in version 5 and you had to find work-arounds.  This pain ends today with SPFx 1.8.

First, install the latest version of SharePoint Framework 1.8 by running the following:

npm install -g @microsoft/generator-sharepoint

Once it completes, start a new project or follow the instructions in the release notes on how to migrate your existing project.  Start a new branch if you are migrating an existing project.

Now install Office Fabric with the following command:

npm install office-ui-frabric-react

Now, add your favorite Office Fabric React code for buttons, pickers, command bars, etc.  Finally run gulp serve.  Unfortunately, you'll still see the errors in merge-styles that we have always gotten when trying to use v6 of Fabric React.  That's because Fabric React needs a newer version of TypeScript.  SPFx 1.8 now supports TypeScript 2.7.2 by default.  That's not good enough. Luckily, we can use other versions of TypeScript now.  I tried to use 3.3 but couldn't get it to work.  However, I could get it to work by using 3.0.  Here's how you do that.

In your package.json file, replace the @microsoft/rush-stack-compiler-2.7 dependency with 3.0 as follows:

"@microsoft/rush-stack-compiler-3.0": "0.5.9"

Now, update your tsconfig.json and change the extends line to the following:

"extends": "./node_modules/@microsoft/rush-stack-compiler-3.0/includes/tsconfig-web.json",

Now run the following command:

npm install

Your Fabric React 6 components should now be working when you run your project again.  Here's my example with a command bar and a button:

Screen Shot 2019-03-14 at 4.04.08 PM

If you want to look at my code changes, you can see them in this simple repo.

These are exciting times and this should make working with Office Fabric React much easier.

On any consumer-facing platform where users can submit content that will be seen by the public, it's a good idea to have some level of content moderation.  Manual content moderation using humans is tedious and labor-intensive.  Luckily, Azure Content Moderator, part of Azure Cognitive Services, provides us with some AI capability to potentially detect language that might be offensive.  It's actually quite easy to get started with as well.

First, you'll want to create a new Content Moderator in your Azure Portal.  The options are fairly straight forward based upon region, resource groups, and scale.  For this example, I used the F0 Plan which comes with 5000 moderation transactions a month (full pricing details).  This should be more than enough to prove out the concept.

Screen Shot 2019-03-04 at 2.35.21 PM

When your Content Moderator finishes provisioning, go to the Keys tab and make note of Key 1 and Key 2 here.  You'll use this later.  Keep these keys secure so that others don't use your API calls.

In this example, we are using Ionic Framework 4.0 which just hit general availability fairly recently.  We'll build on a simple out-of-the-box app.  Full source code is available at the link at the end of this post.  If you don't have Ionic Framework installed, you can install it from here.   To start a new project in Ionic Framework, issue the following command.

ionic start IonicAzureContentModerator

After the project has been created, you can see it in the browser by running the following command:

ionic serve

This will launch the app in a web browser with live reload.  Now let's add the components we need to test this out.  First, let's create a service to make our call to Azure.  Normally this service would call our own API or function which would proxy the call to Azure Content Moderator.  We do this so that our API key is not stored in the client application.  For simplicity though, we are going to call Azure directly because this is only an example.  To create the service issue the following command in the Ionic CLI.

ionic g service services/ContentModeratorService

This will create a stub for a service. We'll look at what goes in here shortly.  However, since we are going to be making an Http call, we need to add the angular HttpClientModule.  Open app.module.ts and add the following import:

import { HttpClientModule, HttpClient } from '@angular/common/http';

Next add HttpClientModule to the list of imports of @NgModule.

Now let's go back to our service and we'll start by adding our HttpClientModule reference.

import { HttpClient, HttpHeaders } from '@angular/common/http';

We also need to add the HttpClient to our constructor to create an instance.  Finally, we have a simple method called moderateContent which calls the Azure Endpoint for the Content Moderator.  The first step is to assemble a URL to that endpoint.  This URL varies by region so you will need to look up what the URL is based on where you deployed your Content Moderator.  The API has a few parameters including whether to scan for PII as well.  As a result, I've made that a parameter on my function.  Here is what my URL looks like for South Central US.

let apiUrl = `${PII}&classify=true`;

Next, we construct an HttpOptions object to pass the API Key.  It goes in a header by the name of Ocp-Apim-Subscription-Key.  I store the API key in the value Constants.apiKey.  Again, we wouldn't normally store our API key in a client application like this.

const httpOptions = {

headers: new HttpHeaders({

'Ocp-Apim-Subscription-Key': Constants.apiKey



Finally we make the HTTP POST while passing the content that we want to moderate in the body.

Now, we can build a simple form to collect the user's input and make the call to our service.  I add an ion-textarea to collect the user's input and add a toggle to choose whether or not to scan for PII.  Then I just make use of some ion-badge components to display the results.  Here is what our interface looks like in the browser.

Screen Shot 2019-03-04 at 3.19.50 PM

Here is the HTML code.

Screen Shot 2019-03-04 at 3.20.58 PM

Clicking the button simply executes the moderateContent method in the service we created.  Let's look at the data that comes back when we execute a call. 

Screen Shot 2019-03-04 at 3.27.12 PM

In the Content Moderator response, we receive a Classification object and in that object there are three categories returned: Category1, Category2, and Category3 along with a boolean ReviewRecommended which will return true if the text is likely an issue.  The categories are defined as follows:

  • Catagory1 - refers to potential presence of language that may be considered sexually explicit or adult in certain situations.
  • Category2 - refers to potential presence of language that may be considered sexually suggestive or mature in certain situations.
  • Category3 - refers to potential presence of language that may be considered offensive in certain situations.

Each category contains a decimal value between 0 and 1.  The higher it is, the more likely the content applies to that category.  In this case, the phrase we sent is more of a general profanity as opposed to being sexual of nature. 

In our app, we simply bind these values using the ion-note so that you can easily see how the phrase was interpreted.

Screen Shot 2019-03-04 at 3.35.05 PM

If you use the toggle for PII, you can look for things such as national id numbers, phone numbers, addresses, and IP addresses.  Here is an example of the output.  You can find more information in the docs.

Screen Shot 2019-03-04 at 3.37.20 PM

You can observe the values of potential PII using the PII object.  You'll notice in this case as well that the Classification values were significantly lower because there wasn't any offensive text in the string we sent.

Azure Content Moderator part of Cognitive Services is a great way to test content to see if it's potentially offensive.  While you will still want to incorporate a human review element into any content moderation process. This should help automate some of the process for you.  In addition, Cognitive Services has Content Moderation for images which can identify potentially suggestive images.

If you want to dive deeper, you can take a look at my code sample in GitHub.

with no comments
Filed under: , ,