<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Darren S</title><link href="http://world.optimizely.com" /><updated>2019-09-16T04:11:05.0000000Z</updated><id>https://world.optimizely.com/blogs/darren-s/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Episerver Developer Meetup Melbourne October 10th 2019</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/9/episerver-developer-meetup-melbourne-october-10th-2019/" /><id>&lt;p&gt;&lt;span class=&quot;ember-view&quot;&gt;&lt;span&gt;Announcing I&#39;ll be presenting at an Episerver Developer Meetup again... but this time in my home town of Melbourne!!! &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luminary.com/&quot;&gt;&lt;span&gt;&lt;strong&gt;Luminary&lt;/strong&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class=&quot;ember-view&quot;&gt;&lt;span&gt; will be hosting &lt;strong&gt;Melbourne&#39;s first Episerver&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;ember-view&quot;&gt;&lt;span&gt;&lt;strong&gt;&amp;nbsp;Developer Meetup&lt;/strong&gt; from &lt;strong&gt;6pm on Thursday 10th October 2019.&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;ember-view&quot;&gt;Speakers will include;&lt;span&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marcus Babajews&lt;/strong&gt;&lt;span class=&quot;ember-view&quot;&gt;&lt;span&gt; (Episerver APAC)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Damien Dias&lt;/strong&gt;&lt;span class=&quot;ember-view&quot;&gt;&lt;span&gt; (Episerver APAC)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/ACoAAAozRPUBV1ZjecHx1NKMdvH6TgtI4ysXLXI/&quot;&gt;&lt;strong&gt;Darren Stahlhut&lt;/strong&gt;&lt;/a&gt;&lt;span class=&quot;ember-view&quot;&gt; (Luminary)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/ACoAAAoZ9tsBUb73SXoIajK7EsHPxROgzPJQjxE/&quot;&gt;&lt;strong&gt;Matthew Boniface&lt;/strong&gt;&lt;/a&gt;&lt;span class=&quot;ember-view&quot;&gt; (Empired)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;As Melbourne&#39;s first Episerver Developer Meetup, we will be discussing a wide range of topics and current trends in Episerver, as well as an open Q&amp;amp;A session.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The overall goal of this meetup is to kick start the local Episerver Development Community in Melbourne and have some fun.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://www.meetup.com/Episerver-Melbourne/events/263574319/&quot;&gt;https://www.meetup.com/Episerver-Melbourne/events/263574319/&lt;/a&gt;&lt;/p&gt;</id><updated>2019-09-16T04:11:05.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Code - Blazor + Episerver blog series</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/7/code---blazor--episerver-blog-series/" /><id>&lt;p&gt;In my last blog, I announced the start of a blog series on Episerver Blazor as a follow up to a presentation I did at the Episerver Sydney Meetup&amp;nbsp;&lt;a href=&quot;/link/651b9e1ea4f04d93bf27e8d985373068.aspx&quot;&gt;https://world.episerver.com/blogs/darren-s/dates/2019/7/blazor--episerver-blog-series/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today, I&#39;m happy to continue the series with a massive code drop&amp;nbsp;&#127881;&lt;/p&gt;
&lt;p&gt;Here is the Github repo&amp;nbsp;&#128071;&lt;br /&gt;&lt;a href=&quot;https://github.com/DarrenStahlhut/Episerver.Blazor&quot;&gt;https://github.com/DarrenStahlhut/Episerver.Blazor&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;This is a work in progress, I&#39;d love your contributions so please feel free to fork the repo and submit a PR.&lt;/p&gt;
&lt;p&gt;The next blog posts in this series will cover the following topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Getting started with Episerver Blazor, a step-by-step installation guide (for anyone that needs it).&lt;/li&gt;
&lt;li&gt;Concepts of Blazor, understanding the fundamental questions of why and how to use Blazor.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Getting Episerver Content and Routing running in Blazor.Serverside&lt;/li&gt;
&lt;li&gt;How to call Javascript Library&#39;s from C# using Blazor Javascript Interop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please post any comments or issues here or github.&lt;/p&gt;
&lt;p&gt;Have an awesome weekend!&lt;/p&gt;</id><updated>2019-07-27T02:29:09.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introduction - Blazor + Episerver blog series</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/7/blazor--episerver-blog-series/" /><id>&lt;p&gt;&lt;span&gt;Following my presentation and demo of&amp;nbsp;&lt;strong&gt;Blazor + Episerver Content Delivery API&lt;/strong&gt;&amp;nbsp;in Sydney at the &lt;strong&gt;Episerver Developer Meetup - July 2019.&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;span&gt;I&#39;ve decided to start a series of blog posts to share the content with the global community.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;For those that attended the Sydney meetup, thank you, I had a great time building the proof of concept and I&#39;m keen to expand on it over the coming weeks.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here is the Blazor slide deck from the meetup:&amp;nbsp;&lt;a href=&quot;http://bit.ly/2LmbP3N&quot;&gt;http://bit.ly/2LmbP3N&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;This first post in the series is mostly just to announce the series, share the slide deck, and get some general interest going.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;In the next post, I&#39;ll share some code (via github) including&amp;nbsp;&lt;strong&gt;Client-side&lt;/strong&gt; and &lt;strong&gt;Server-side&lt;/strong&gt; &lt;strong&gt;Blazor&lt;/strong&gt; running against &lt;strong&gt;Episerver Content Delivery API&lt;br /&gt;&lt;br /&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span&gt;I&#39;m particularly interested in expanding the solution to add&amp;nbsp;&lt;strong&gt;Episerver Routing &lt;/strong&gt;(to the&amp;nbsp;Server-side app) and demonstrate how&amp;nbsp;&lt;strong&gt;Javascript interop&amp;nbsp;&lt;/strong&gt;works, to keep the front-end JS developers happy &#128513;.&lt;br /&gt;&lt;br /&gt;Anyone eager to get a headstart can have a look at these references (included in the slide deck);&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blazor Official Site: &lt;a href=&quot;https://dotnet.microsoft.com/apps/aspnet/web-apps/client&quot;&gt;https://dotnet.microsoft.com/apps/aspnet/web-apps/client&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Blazor Official Documentation:&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.0&quot;&gt;https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.0&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Blazor Video Steven Sanderson: &lt;a href=&quot;https://www.youtube.com/watch?v=0RfUPr0KrSM&quot;&gt;https://www.youtube.com/watch?v=0RfUPr0KrSM&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Blazor Official Blog announcing release:&amp;nbsp;&lt;a href=&quot;https://devblogs.microsoft.com/aspnet/blazor-now-in-official-preview/&quot;&gt;https://devblogs.microsoft.com/aspnet/blazor-now-in-official-preview/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Episerver Content Delivery API Developer Guide:&amp;nbsp;&lt;a href=&quot;/link/6ffa5cb8173a414eac25740deeafdbc8.aspx&quot;&gt;https://world.episerver.com/documentation/developer-guides/content-delivery-api/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Episerver Content Delivery API Reference:&amp;nbsp;&lt;a href=&quot;https://sdk.episerver.com/ContentDeliveryAPI/2.x/Index.html&quot;&gt;https://sdk.episerver.com/ContentDeliveryAPI/2.x/Index.html&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;text-decoration:&amp;#32;underline;&quot;&gt;&lt;strong&gt;Blog Series Updates:&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;strong&gt;2019-07-27&amp;nbsp;&lt;/strong&gt;- Code available on GitHub - &lt;a href=&quot;/link/29d25b6084304edba82322737a60c175.aspx&quot;&gt;https://world.episerver.com/blogs/darren-s/dates/2019/7/code---blazor--episerver-blog-series/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</id><updated>2019-07-13T03:46:41.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Episerver Developer Meetup Sydney July 10th 2019</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/6/episerver-sydney-meetup-july-10th-2019/" /><id>&lt;p&gt;I&#39;m excited to announce I&#39;ll be speaking at the Episerver Developer Meetup in Sydney on Wednesday, July 10th 2019.&lt;br /&gt;&lt;br /&gt;I&#39;m going to be talking about;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blazor -&amp;nbsp;&lt;a href=&quot;https://dotnet.microsoft.com/apps/aspnet/web-apps/client&quot;&gt;https://dotnet.microsoft.com/apps/aspnet/web-apps/client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Azure Cognitive Services / Computer Vision Add-On -&amp;nbsp;&lt;a href=&quot;/link/ab0542984e38487db0206e24c6f83099.aspx&quot;&gt;https://world.episerver.com/blogs/darren-s/dates/2019/3/using-ai-to-analyze-images-and-generate-metadata/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Damian Dias&lt;/strong&gt; will talk about Commerce and CMS Certifications best practices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nicola Ayan&lt;/strong&gt; will talk about Episerver Find and share lessons learned from recent projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marcus Babajews&lt;/strong&gt; will give a short update on Episerver Campaign.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.eventbrite.com/e/episerver-developer-meetup-sydney-tickets-62842623980&quot;&gt;https://www.eventbrite.com/e/episerver-developer-meetup-sydney-tickets-62842623980&lt;/a&gt;&lt;/p&gt;</id><updated>2019-06-26T04:09:17.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>GitFlow is a natural fit for Episerver DXC</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/3/gitflow-is-a-great-fit-for-episerver-dxc/" /><id>&lt;p&gt;In this blog, I&#39;ll explain a little about GitFlow and why it aligns so well with Episerver DXC development.&lt;/p&gt;
&lt;h2&gt;What is GitFlow?&lt;/h2&gt;
&lt;p&gt;If you&#39;re not familiar with GitFlow, it&#39;s just another branching and merging strategy. It was made popular&amp;nbsp;by&amp;nbsp;&lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;Vincent Driessen at nvie&lt;/a&gt;&amp;nbsp;and has since been widely adopted by the development community.&lt;/p&gt;
&lt;p&gt;It&#39;s also built into the most popular Git Clients including &lt;a href=&quot;https://www.sourcetreeapp.com/&quot;&gt;SourceTree&lt;/a&gt; and &lt;a href=&quot;https://support.gitkraken.com/git-workflows-and-extensions/git-flow/&quot;&gt;GitKraken&lt;/a&gt;&amp;nbsp;and is available via commands in Git console.&lt;/p&gt;
&lt;p&gt;What I like most about GitFlow, is not the merging strategy itself, but&amp;nbsp;its things that having a standard strategy offers;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can more easily collaborate with&amp;nbsp;external developers and Agencies. We can simply by say &quot;we use GitFlow&quot; and they&#39;ll know what we&amp;nbsp;mean.&lt;/li&gt;
&lt;li&gt;Onboarding Developers is faster, there are a lot of good learning resources around.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GitFlow merging strategy (in a nutshell)&lt;/h2&gt;
&lt;p&gt;There are two main branches in GitFlow;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;master&lt;/strong&gt;&amp;nbsp;-&amp;nbsp;the code you have or are going to release.&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;develop&lt;/strong&gt; branch - the&lt;span&gt;&amp;nbsp;latest development, changes for the next release.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides the main branches, we also have;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feature branches&lt;/strong&gt; - this is where you actually do your development and commits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;release branches&lt;/strong&gt; - a branch to get&amp;nbsp;code ready to release to master.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hotfixes&lt;/strong&gt;&amp;nbsp;- for emergency fixes for master branch to be immediately released.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://nvie.com/img/git-model@2x.png&quot; width=&quot;600&quot; alt=&quot;GitFlow&amp;#32;merging&amp;#32;diagram&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Why does this work well with Episerver DXC?&lt;/h2&gt;
&lt;p&gt;Because of &lt;strong&gt;Episerver DXC&lt;/strong&gt;&#39;s&amp;nbsp;linear deployment path, code must be deployed from &lt;strong&gt;Integration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Preproduction&lt;/strong&gt; &amp;gt; &lt;strong&gt;Production.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This means we can think of our&amp;nbsp;&lt;strong&gt;Master&lt;/strong&gt; branch as the code ready to be deployed to &lt;strong&gt;Integration.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Deployments above &lt;strong&gt;Integration&lt;/strong&gt;&amp;nbsp;are managed via the &lt;strong&gt;Paas Portal&lt;/strong&gt; or via &lt;strong&gt;Episerver Support.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you also want to have an internal CI/CR (build and release) environment for internal QA, you can run it off the &lt;strong&gt;Develop&lt;/strong&gt; branch&lt;/p&gt;
&lt;p&gt;This all means we can use the standard implementation of &lt;strong&gt;GitFlow&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Wrapping it up&lt;/h2&gt;
&lt;p&gt;I&#39;m not saying GitFlow is perfect, but it is a decent merging strategy. It can become complicated when you aren&#39;t certain about the order that Features will be released and I have some very large scale projects that GitFlow struggles to handle so we have a customized strategy.&lt;/p&gt;
&lt;p&gt;But generally speaking, for Episerver DXC projects where the deployment chain is linear, I&#39;ve found it&#39;s a great fit.&lt;/p&gt;
&lt;p&gt;This might change in the future if we are allowed to use our own DevOps tools to deploy directly to Preproduction (or even Production) which is something I&#39;ve heard is on the technical roadmap.&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;GitFlow&amp;nbsp;by&amp;nbsp;Vincent Driessen&lt;br /&gt;&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;https://nvie.com/posts/a-successful-git-branching-model/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GitFlow Atlassian&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow&quot;&gt;https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</id><updated>2019-04-01T01:01:50.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Using AI to analyze Images in Episerver</title><link href="https://world.optimizely.com/blogs/darren-s/dates/2019/3/using-ai-to-analyze-images-and-generate-metadata/" /><id>&lt;p&gt;Inspired by Artificial Intelligence? Me too!&lt;/p&gt;
&lt;p&gt;In this blog, I&#39;ll show you how to configure &lt;strong&gt;Azure Cognitive Services&lt;/strong&gt;, add the &lt;strong&gt;Computer Vision C# SDK&lt;/strong&gt; to Episerver, and work with &lt;strong&gt;Azure Computer Vision&#39;s APIs&lt;/strong&gt; to analyze Images.&lt;/p&gt;
&lt;h2&gt;What can we do with AI in the CMS&lt;/h2&gt;
&lt;p&gt;After reading the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home&quot;&gt;official documentation&lt;/a&gt; &lt;span&gt;I had several cool ideas&lt;/span&gt;;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By using the &lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-describing-images&quot;&gt;Describing images&lt;/a&gt; feature we can generate a human-readable description of the image (eg alt text) to improve Accessibility and SEO.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;We could detect and prevent inappropriate content by using the&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-detecting-adult-content&quot;&gt;Adult and Racy images&lt;/a&gt;&amp;nbsp;feature. Imagine validating User Generated Content, or auditing an entire Media Library with a scheduled task.&lt;/li&gt;
&lt;li&gt;In line with the inappropriate visual content, we can use the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-recognizing-text&quot;&gt;Recognize Text&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;feature to read embedded text,&amp;nbsp;then validate it against a list of banned words.&lt;/li&gt;
&lt;li&gt;We could automatically set the focal point and crop images by using the&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-generating-thumbnails&quot;&gt;Thumbnails and Area of Interest&lt;/a&gt; feature. I think this one is really cool. You&#39;ve likely seen tools that allow CMS Editors to select a focal point for an image, we can now use AI to set it.&lt;/li&gt;
&lt;li&gt;We can use the&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-detecting-color-schemes&quot;&gt;Color schemes&lt;/a&gt; feature to allow us to automatically select a theme to complement the Image&#39;s&amp;nbsp;colors (eg a light or dark theme of a hero Banner).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the remainder of this blog, I will demonstrate the first idea, generating descriptive text for an image.&lt;/p&gt;
&lt;h2&gt;Configuring Azure Cognitive Services Computer Vision&lt;/h2&gt;
&lt;p&gt;You will need an Azure account to perform this step.&lt;/p&gt;
&lt;p&gt;In your Azure Portal, click &lt;strong&gt;Create a resource&lt;/strong&gt; &amp;gt; &lt;strong&gt;AI + Machine Learning&lt;/strong&gt; &amp;gt; &lt;strong&gt;Computer Vision&lt;/strong&gt; (or search for Computer Vision).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/9bf6d2f0536641d3b2d6ba8c14245204.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then complete the form&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enter a &lt;strong&gt;Name&lt;/strong&gt; (eg ComputerVision)&lt;/li&gt;
&lt;li&gt;Select your &lt;strong&gt;Subscription&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Select a &lt;strong&gt;Location&amp;nbsp;&lt;/strong&gt;(remember it, you&#39;ll need it later)&lt;/li&gt;
&lt;li&gt;Select a &lt;strong&gt;Pricing Tier&lt;/strong&gt; (the F0 free tier is fine)&lt;/li&gt;
&lt;li&gt;Select or Create a &lt;strong&gt;Resource Group&lt;/strong&gt; (eg Episerver)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finally, after Azure has provisioned the service, you&#39;ll need to copy &lt;strong&gt;Key 1&lt;/strong&gt; (actually either key will work) to use in your code (yes I have reset my keys, sorry!).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/c6f38e41b7594e81b5d067fd1f5faf5b.aspx&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;A quick test using Postman&lt;/h3&gt;
&lt;p&gt;At this point the AI Service is running in Azure, it&#39;s a good time to quickly confirm things are working. Using &lt;a href=&quot;https://www.getpostman.com/&quot;&gt;Postman&lt;/a&gt;&amp;nbsp;I made a &lt;a href=&quot;https://australiaeast.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa/console&quot;&gt;POST using the API&lt;/a&gt;. This is the &lt;a href=&quot;https://i.imgur.com/tluKsu0.jpg&quot;&gt;Image URL&lt;/a&gt;&amp;nbsp;I sent to the service, and this the JSON result.&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;{
  &quot;categories&quot;: [
    {
      &quot;name&quot;: &quot;outdoor_oceanbeach&quot;,
      &quot;score&quot;: 0.99609375,
      &quot;detail&quot;: {
        &quot;landmarks&quot;: []
      }
    }
  ],
  &quot;adult&quot;: {
    &quot;isAdultContent&quot;: false,
    &quot;isRacyContent&quot;: false,
    &quot;adultScore&quot;: 0.011389658786356449,
    &quot;racyScore&quot;: 0.030652720481157303
  },
  &quot;color&quot;: {
    &quot;dominantColorForeground&quot;: &quot;White&quot;,
    &quot;dominantColorBackground&quot;: &quot;Blue&quot;,
    &quot;dominantColors&quot;: [
      &quot;Blue&quot;,
      &quot;White&quot;
    ],
    &quot;accentColor&quot;: &quot;0750C4&quot;,
    &quot;isBwImg&quot;: false,
    &quot;isBWImg&quot;: false
  },
  &quot;imageType&quot;: {
    &quot;clipArtType&quot;: 0,
    &quot;lineDrawingType&quot;: 0
  },
  &quot;tags&quot;: [
    {
      &quot;name&quot;: &quot;water&quot;,
      &quot;confidence&quot;: 0.9997772574424744
    },
    {
      &quot;name&quot;: &quot;outdoor&quot;,
      &quot;confidence&quot;: 0.9996986389160156
    },
    {
      &quot;name&quot;: &quot;sky&quot;,
      &quot;confidence&quot;: 0.9993903636932373
    },
    {
      &quot;name&quot;: &quot;beach&quot;,
      &quot;confidence&quot;: 0.9672492146492004
    },
    {
      &quot;name&quot;: &quot;shore&quot;,
      &quot;confidence&quot;: 0.963735044002533
    },
    {
      &quot;name&quot;: &quot;ocean&quot;,
      &quot;confidence&quot;: 0.9035242199897766
    },
    {
      &quot;name&quot;: &quot;nature&quot;,
      &quot;confidence&quot;: 0.896171510219574
    },
    {
      &quot;name&quot;: &quot;wave&quot;,
      &quot;confidence&quot;: 0.4871264696121216
    },
    {
      &quot;name&quot;: &quot;sandy&quot;,
      &quot;confidence&quot;: 0.14046534895896912
    },
    {
      &quot;name&quot;: &quot;voyage&quot;,
      &quot;confidence&quot;: 0.055084559276120444
    },
    {
      &quot;name&quot;: &quot;landscape&quot;,
      &quot;confidence&quot;: 0.02963506257691794
    },
    {
      &quot;name&quot;: &quot;sand&quot;,
      &quot;confidence&quot;: 0.02806604807717514
    }
  ],
  &quot;description&quot;: {
    &quot;tags&quot;: [
      &quot;water&quot;,
      &quot;outdoor&quot;,
      &quot;beach&quot;,
      &quot;ocean&quot;,
      &quot;nature&quot;,
      &quot;man&quot;,
      &quot;wave&quot;,
      &quot;board&quot;,
      &quot;shore&quot;,
      &quot;surfing&quot;,
      &quot;sand&quot;,
      &quot;body&quot;,
      &quot;standing&quot;,
      &quot;umbrella&quot;,
      &quot;sandy&quot;,
      &quot;walking&quot;,
      &quot;riding&quot;,
      &quot;snow&quot;,
      &quot;white&quot;,
      &quot;blue&quot;
    ],
    &quot;captions&quot;: [
      {
        &quot;text&quot;: &quot;a sandy beach next to the ocean&quot;,
        &quot;confidence&quot;: 0.9815995674986626
      }
    ]
  },
  &quot;requestId&quot;: &quot;26b96fb1-8b67-4bd6-b6ac-4e9621769a12&quot;,
  &quot;metadata&quot;: {
    &quot;width&quot;: 1200,
    &quot;height&quot;: 800,
    &quot;format&quot;: &quot;Jpeg&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to move from a raw web request and a JSON result to the C# SDK.&lt;/p&gt;
&lt;h2&gt;Adding Azure Computer Vision C# SDK to Episerver&lt;/h2&gt;
&lt;p&gt;This step is easy, it&#39;s just adding a&amp;nbsp;Nuget Package to your Episerver CMS Project.&lt;/p&gt;
&lt;p&gt;Search for &lt;strong&gt;Azure Cognitive&lt;/strong&gt; &amp;gt; select &lt;strong&gt;Microsoft.Azure.CognitiveServices.Vision.ComputerVision&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/d3f3f9762c3f4f4cba0e3330c1919039.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After the install, Build your solution to make sure everything is ok, then move on.&lt;/p&gt;
&lt;h2&gt;Working with the Computer Vision APIs&lt;/h2&gt;
&lt;p&gt;My example will use the &lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-describing-images&quot;&gt;Describing Images&lt;/a&gt; feature of the API.&amp;nbsp;I will register an &lt;strong&gt;OnSavingContent&lt;/strong&gt;&amp;nbsp;event, pass the image stream to the API, and save the data returned from the Computer Vision API into read-only properties for later use.&lt;/p&gt;
&lt;p&gt;Firstly, I need a new &lt;strong&gt;Class,&lt;/strong&gt;&amp;nbsp;which I called &lt;strong&gt;ImageFile,&lt;/strong&gt;&amp;nbsp;that inherits from &lt;strong&gt;ImageData&amp;nbsp;&lt;/strong&gt;to add some extra properties.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Description&lt;/strong&gt; - To be populated by a Human&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UseAiDescription&lt;/strong&gt; - An editable boolean, initially set by AI, can be later set by a Human&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AiDescription&lt;/strong&gt; - Read-only property to hold the image description text returned by the AI analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AiDescriptionConfidence&lt;/strong&gt; - Read-only property to hold the AI&#39;s confidence in its description&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using EPiServer.Framework.DataAnnotations;
using EPiServer.Web;
using System.ComponentModel.DataAnnotations;

namespace EpiserverDemo.Models.Media
{
    [ContentType(GUID = &quot;0A89E464-56D4-449F-AEA8-2BF774AB8731&quot;)]
    [MediaDescriptor(ExtensionString = &quot;jpg,jpeg,gif,bmp,png&quot;)]
    public class ImageFile : ImageData
    {
        [Display(
        Name = &quot;Description&quot;,
            Description = &quot;Manually populated Description of the Image&quot;,
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [UIHint(UIHint.Textarea)]
        public virtual string Description { get; set; }

        [Display(
        Name = &quot;Fallback to AI Description&quot;,
            Description = &quot;If true, the AI Description will be used when Description is empty&quot;,
            GroupName = SystemTabNames.Content,
            Order = 10)]
        public virtual bool UseAiDescription { get; set; }

        [Display(
            Name = &quot;AI Description&quot;,
            Description = &quot;AI generated Description of the Image&quot;,
            GroupName = SystemTabNames.Content,
            Order = 20)]
        [Editable(false)]
        [UIHint(UIHint.Textarea)]
        public virtual string AiDescription { get; set; }

        [Display(
            Name = &quot;AI Description Confidence&quot;,
            Description = &quot;AI confidence rating for the generated Description&quot;,
            GroupName = SystemTabNames.Content,
            Order = 30)]
        [Editable(false)]
        public virtual double AiDescriptionConfidence { get; set; }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I needed to register the&amp;nbsp;&lt;strong&gt;OnSavingContent&lt;/strong&gt; event.&amp;nbsp;You&#39;ll see for brevity I&#39;ve hard-coded the &lt;strong&gt;Subscription Key&lt;/strong&gt; (Key 1 copied from Azure) and the &lt;strong&gt;Computer Vision Endpoint&lt;/strong&gt; (&lt;a href=&quot;https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa&quot;&gt;you can find a list of Endpoint URLs here based on the Location you selected in Azure&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Computer Vision API&lt;/strong&gt; can accept either a &lt;strong&gt;URL&lt;/strong&gt; or &lt;strong&gt;Stream&lt;/strong&gt;. I opted for the stream so that I didn&#39;t have to persist the Image to the database to get a URL.&lt;/p&gt;
&lt;p&gt;You will also see a bit of logic to set the &lt;strong&gt;UseAiDescription &lt;/strong&gt;property&amp;nbsp;to true when &lt;strong&gt;Confidence&lt;/strong&gt; is greater than or equal to 90%. I found the AI Description was often good when Confidence was above 85%.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System.Collections.Generic;
using EpiserverDemo.Models.Media;
using EPiServer;
using EPiServer.Core;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;

namespace EpiserverDemo.Infrastructure
{
    [InitializableModule]
    [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
    public class ImageAiMetaDataInitialization : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            var eventRegistry =
            ServiceLocator.Current.GetInstance&amp;lt;IContentEvents&amp;gt;();
            eventRegistry.SavingContent += OnSavingContent;
        }

        public void Preload(string[] parameters)
        {
        }

        private void OnSavingContent(object sender, ContentEventArgs e)
        {
            if (e.Content is ImageFile)
            {
                SetAiMetaData(e.Content as ImageFile);
            }
        }

        public void Uninitialize(InitializationEngine context)
        {
            var eventRegistry = ServiceLocator.Current.GetInstance&amp;lt;IContentEvents&amp;gt;();
            eventRegistry.SavingContent -= OnSavingContent;
        }

        public static void SetAiMetaData(ImageFile imageFile)
        {
            // get a stream of the image from binary data
            var stream = imageFile.BinaryData.OpenRead();

            // subscription key to use with Azure Computer Vision (found in Azure Portal)
            var subscriptionKey = &quot;1774efe94d4e48ec96ad9d89d2ed4fc3&quot;;

            // specify the features to return, there&#39;s some cool stuff in here
            List&amp;lt;VisualFeatureTypes&amp;gt; features =
                new List&amp;lt;VisualFeatureTypes&amp;gt;()
                {
                VisualFeatureTypes.Categories, VisualFeatureTypes.Description,
                VisualFeatureTypes.Faces, VisualFeatureTypes.ImageType,
                VisualFeatureTypes.Tags, VisualFeatureTypes.Color,
                VisualFeatureTypes.Adult, VisualFeatureTypes.Objects
                };

            // make a Computer Vision client
            ComputerVisionClient computerVision = new ComputerVisionClient(
                new ApiKeyServiceClientCredentials(subscriptionKey),
                new System.Net.Http.DelegatingHandler[] { });

            // specify the Azure region endpoint (based on Computer Vision service location in Azure Portal)            
            computerVision.Endpoint = &quot;https://australiaeast.api.cognitive.microsoft.com&quot;;

            // analyse the image, return ImageAnalysis (sync for now, not await async)
            ImageAnalysis imageAnalysis = computerVision.AnalyzeImageInStreamAsync(stream, features).Result;

            // set Image AI Description
            var caption = imageAnalysis.Description.Captions[0];
            if (caption != null)
            {
                // set confidence first
                imageFile.AiDescriptionConfidence = caption.Confidence;

                // set the boolean based on Confidence. Only do this the first time AI Description populated
                if (string.IsNullOrEmpty(imageFile.AiDescription))
                {              
                    // anything less that 90% confidence is often an inaccurate description
                    imageFile.UseAiDescription = (caption.Confidence &amp;gt;= 0.90);
                }

                // set the AI Description
                imageFile.AiDescription = caption.Text;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The end result&lt;/h2&gt;
&lt;p&gt;When your code is ready, run the CMS and drag in an Image, I used this one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/05c83e4351bc4d09b3a5c9de1e123105.aspx&quot; width=&quot;400&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This will trigger the &lt;strong&gt;OnSavingContent&lt;/strong&gt; event and send your Image to the Computer Vision API for analysis, and finally populate your properties.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/e7f343dae55b45cf971ac43d2a4974f3.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s a screencast (gif) of this whole process to give you a sense of the speed of the API (it&#39;s pretty fast considering I&#39;m using the Free Pricing Tier);&lt;br /&gt;&lt;a href=&quot;https://i.imgur.com/sgBBFLg.gifv&quot;&gt;https://i.imgur.com/sgBBFLg.gifv&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Rendering the image&lt;/h2&gt;
&lt;p&gt;The last thing left to do is to render the image, the idea here is to;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the &lt;strong&gt;Description&lt;/strong&gt; property as alt text when populated (by a Human). Humans still describe Images better than Machines.&lt;br /&gt;or&lt;/li&gt;
&lt;li&gt;Use the&amp;nbsp;&lt;strong&gt;AIDescription&lt;/strong&gt; property as alt text if the&amp;nbsp;&lt;strong&gt;Description&lt;/strong&gt; property is empty and the &lt;strong&gt;UseAiDescription&lt;/strong&gt;&amp;nbsp;is true.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I won&#39;t add the View&amp;nbsp;for this because it&#39;s pretty straight forward (and this blog is long enough) but let me know if you need it.&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;/globalassets/beach.jpg&quot; alt=&quot;a sandy beach next to the ocean&quot; &amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wrapping it up&lt;/h2&gt;
&lt;p&gt;I hope I have inspired you to consider how can AI can be used to improve your CMS Editors experience and the quality of content.&lt;/p&gt;
&lt;p&gt;I&#39;m pretty impressed with the AI generated Description when its Confidence rating is high. But after using the APIs, I can admit that&amp;nbsp;&lt;strong&gt;Humans&lt;/strong&gt; are still far better at describing Images than &lt;strong&gt;Machines.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That said I do see a lot of potential, not just to assist the CMS Editor when they upload individual images, but especially by processing large amounts of images with a Scheduled Job.&lt;/p&gt;
&lt;h2&gt;Official Documentation References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Azure Cognitive Services Computer Vision&lt;br /&gt;&lt;a href=&quot;http://%20%20https//docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home&quot;&gt;https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Computer Vision API&lt;br /&gt;&lt;a href=&quot;http://%20https//westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa&quot;&gt;https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Computer Vision C# SDK&lt;br /&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts-sdk/csharp-analyze-sdk&quot;&gt;https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts-sdk/csharp-analyze-sdk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</id><updated>2019-03-26T01:45:46.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Episerver Personalization with persistent anonymous profiles</title><link href="https://www.luminary.com/blog/episerver-personalization-with-persistent-anonymous-profiles" /><id>Episerver Personalization is a powerful feature to ensure your website displays relevant content to your visitors. At Luminary we needed a way to persist an anonymous visitor&#39;s personalisation profile across sessions without using Episerver Insight or custom cookies. Here&#39;s how we did it...</id><updated>2018-10-12T02:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Generating image metadata and SVG thumbnails with Episerver DXC Azure Blob storage</title><link href="https://www.luminary.com/blog/image-metadata-svg-thumbnails-episerver-dxc" /><id>Episerver has an ImageData base class that natively supports images. But we needed to extend it to provide metadata fields and display SVG thumbnails. Here&#39;s how we did it...</id><updated>2018-07-30T02:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>