<?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="https://world.optimizely.com/blogs/darren-s/" /><updated>2019-09-16T04:11:05.0000000Z</updated><id>https://world.optimizely.com/blogs/darren-s/</id><generator uri="https://world.optimizely.com/blogs/darren-s/" 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>https://world.optimizely.com/blogs/darren-s/dates/2019/9/episerver-developer-meetup-melbourne-october-10th-2019/</id><published>2019-09-16T04:11:05.0000000Z</published><updated>2019-09-16T04:11:05.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&lt;p&gt;&lt;span class="ember-view"&gt;&lt;span&gt;Announcing I'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="https://www.luminary.com/"&gt;&lt;span&gt;&lt;strong&gt;Luminary&lt;/strong&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="ember-view"&gt;&lt;span&gt; will be hosting &lt;strong&gt;Melbourne's first Episerver&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ember-view"&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="ember-view"&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="ember-view"&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="ember-view"&gt;&lt;span&gt; (Episerver APAC)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/ACoAAAozRPUBV1ZjecHx1NKMdvH6TgtI4ysXLXI/"&gt;&lt;strong&gt;Darren Stahlhut&lt;/strong&gt;&lt;/a&gt;&lt;span class="ember-view"&gt; (Luminary)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/ACoAAAoZ9tsBUb73SXoIajK7EsHPxROgzPJQjxE/"&gt;&lt;strong&gt;Matthew Boniface&lt;/strong&gt;&lt;/a&gt;&lt;span class="ember-view"&gt; (Empired)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;As Melbourne'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="https://www.meetup.com/Episerver-Melbourne/events/263574319/"&gt;https://www.meetup.com/Episerver-Melbourne/events/263574319/&lt;/a&gt;&lt;/p&gt;</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>https://world.optimizely.com/blogs/darren-s/dates/2019/7/code---blazor--episerver-blog-series/</id><published>2019-07-27T02:29:09.0000000Z</published><updated>2019-07-27T02:29:09.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&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="/link/651b9e1ea4f04d93bf27e8d985373068.aspx"&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'm happy to continue the series with a massive code drop&amp;nbsp;🎉&lt;/p&gt;
&lt;p&gt;Here is the Github repo&amp;nbsp;👇&lt;br /&gt;&lt;a href="https://github.com/DarrenStahlhut/Episerver.Blazor"&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'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'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;</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>https://world.optimizely.com/blogs/darren-s/dates/2019/7/blazor--episerver-blog-series/</id><published>2019-07-13T03:46:41.0000000Z</published><updated>2019-07-13T03:46:41.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&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'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'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="http://bit.ly/2LmbP3N"&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'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'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 😁.&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="https://dotnet.microsoft.com/apps/aspnet/web-apps/client"&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="https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.0"&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="https://www.youtube.com/watch?v=0RfUPr0KrSM"&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="https://devblogs.microsoft.com/aspnet/blazor-now-in-official-preview/"&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="/link/6ffa5cb8173a414eac25740deeafdbc8.aspx"&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="https://sdk.episerver.com/ContentDeliveryAPI/2.x/Index.html"&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="text-decoration:&amp;#32;underline;"&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="/link/29d25b6084304edba82322737a60c175.aspx"&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;</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>https://world.optimizely.com/blogs/darren-s/dates/2019/6/episerver-sydney-meetup-july-10th-2019/</id><published>2019-06-26T04:09:17.0000000Z</published><updated>2019-06-26T04:09:17.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&lt;p&gt;I'm excited to announce I'll be speaking at the Episerver Developer Meetup in Sydney on Wednesday, July 10th 2019.&lt;br /&gt;&lt;br /&gt;I'm going to be talking about;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blazor -&amp;nbsp;&lt;a href="https://dotnet.microsoft.com/apps/aspnet/web-apps/client"&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="/link/ab0542984e38487db0206e24c6f83099.aspx"&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="https://www.eventbrite.com/e/episerver-developer-meetup-sydney-tickets-62842623980"&gt;https://www.eventbrite.com/e/episerver-developer-meetup-sydney-tickets-62842623980&lt;/a&gt;&lt;/p&gt;</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>https://world.optimizely.com/blogs/darren-s/dates/2019/3/gitflow-is-a-great-fit-for-episerver-dxc/</id><published>2019-04-01T01:01:50.0000000Z</published><updated>2019-04-01T01:01:50.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&lt;p&gt;In this blog, I'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're not familiar with GitFlow, it's just another branching and merging strategy. It was made popular&amp;nbsp;by&amp;nbsp;&lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&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's also built into the most popular Git Clients including &lt;a href="https://www.sourcetreeapp.com/"&gt;SourceTree&lt;/a&gt; and &lt;a href="https://support.gitkraken.com/git-workflows-and-extensions/git-flow/"&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 "we use GitFlow" and they'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="https://nvie.com/img/git-model@2x.png" width="600" alt="GitFlow&amp;#32;merging&amp;#32;diagram" /&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;'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'm not saying GitFlow is perfect, but it is a decent merging strategy. It can become complicated when you aren'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've found it'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'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="https://nvie.com/posts/a-successful-git-branching-model/"&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="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</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>https://world.optimizely.com/blogs/darren-s/dates/2019/3/using-ai-to-analyze-images-and-generate-metadata/</id><published>2019-03-26T01:45:46.0000000Z</published><updated>2019-03-26T01:45:46.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">&lt;p&gt;Inspired by Artificial Intelligence? Me too!&lt;/p&gt;
&lt;p&gt;In this blog, I'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'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="https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home"&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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-describing-images"&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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-detecting-adult-content"&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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-recognizing-text"&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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-generating-thumbnails"&gt;Thumbnails and Area of Interest&lt;/a&gt; feature. I think this one is really cool. You'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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-detecting-color-schemes"&gt;Color schemes&lt;/a&gt; feature to allow us to automatically select a theme to complement the Image'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="/link/9bf6d2f0536641d3b2d6ba8c14245204.aspx" /&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'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'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="/link/c6f38e41b7594e81b5d067fd1f5faf5b.aspx" /&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's a good time to quickly confirm things are working. Using &lt;a href="https://www.getpostman.com/"&gt;Postman&lt;/a&gt;&amp;nbsp;I made a &lt;a href="https://australiaeast.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa/console"&gt;POST using the API&lt;/a&gt;. This is the &lt;a href="https://i.imgur.com/tluKsu0.jpg"&gt;Image URL&lt;/a&gt;&amp;nbsp;I sent to the service, and this the JSON result.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;{
  "categories": [
    {
      "name": "outdoor_oceanbeach",
      "score": 0.99609375,
      "detail": {
        "landmarks": []
      }
    }
  ],
  "adult": {
    "isAdultContent": false,
    "isRacyContent": false,
    "adultScore": 0.011389658786356449,
    "racyScore": 0.030652720481157303
  },
  "color": {
    "dominantColorForeground": "White",
    "dominantColorBackground": "Blue",
    "dominantColors": [
      "Blue",
      "White"
    ],
    "accentColor": "0750C4",
    "isBwImg": false,
    "isBWImg": false
  },
  "imageType": {
    "clipArtType": 0,
    "lineDrawingType": 0
  },
  "tags": [
    {
      "name": "water",
      "confidence": 0.9997772574424744
    },
    {
      "name": "outdoor",
      "confidence": 0.9996986389160156
    },
    {
      "name": "sky",
      "confidence": 0.9993903636932373
    },
    {
      "name": "beach",
      "confidence": 0.9672492146492004
    },
    {
      "name": "shore",
      "confidence": 0.963735044002533
    },
    {
      "name": "ocean",
      "confidence": 0.9035242199897766
    },
    {
      "name": "nature",
      "confidence": 0.896171510219574
    },
    {
      "name": "wave",
      "confidence": 0.4871264696121216
    },
    {
      "name": "sandy",
      "confidence": 0.14046534895896912
    },
    {
      "name": "voyage",
      "confidence": 0.055084559276120444
    },
    {
      "name": "landscape",
      "confidence": 0.02963506257691794
    },
    {
      "name": "sand",
      "confidence": 0.02806604807717514
    }
  ],
  "description": {
    "tags": [
      "water",
      "outdoor",
      "beach",
      "ocean",
      "nature",
      "man",
      "wave",
      "board",
      "shore",
      "surfing",
      "sand",
      "body",
      "standing",
      "umbrella",
      "sandy",
      "walking",
      "riding",
      "snow",
      "white",
      "blue"
    ],
    "captions": [
      {
        "text": "a sandy beach next to the ocean",
        "confidence": 0.9815995674986626
      }
    ]
  },
  "requestId": "26b96fb1-8b67-4bd6-b6ac-4e9621769a12",
  "metadata": {
    "width": 1200,
    "height": 800,
    "format": "Jpeg"
  }
}&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'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="/link/d3f3f9762c3f4f4cba0e3330c1919039.aspx" /&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="https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/concept-describing-images"&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's confidence in its description&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="language-csharp"&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 = "0A89E464-56D4-449F-AEA8-2BF774AB8731")]
    [MediaDescriptor(ExtensionString = "jpg,jpeg,gif,bmp,png")]
    public class ImageFile : ImageData
    {
        [Display(
        Name = "Description",
            Description = "Manually populated Description of the Image",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [UIHint(UIHint.Textarea)]
        public virtual string Description { get; set; }

        [Display(
        Name = "Fallback to AI Description",
            Description = "If true, the AI Description will be used when Description is empty",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        public virtual bool UseAiDescription { get; set; }

        [Display(
            Name = "AI Description",
            Description = "AI generated Description of the Image",
            GroupName = SystemTabNames.Content,
            Order = 20)]
        [Editable(false)]
        [UIHint(UIHint.Textarea)]
        public virtual string AiDescription { get; set; }

        [Display(
            Name = "AI Description Confidence",
            Description = "AI confidence rating for the generated Description",
            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'll see for brevity I'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="https://westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa"&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'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="language-csharp"&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 = "1774efe94d4e48ec96ad9d89d2ed4fc3";

            // specify the features to return, there'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 = "https://australiaeast.api.cognitive.microsoft.com";

            // 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="/link/05c83e4351bc4d09b3a5c9de1e123105.aspx" width="400" /&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="/link/e7f343dae55b45cf971ac43d2a4974f3.aspx" /&gt;&lt;/p&gt;
&lt;p&gt;Here's a screencast (gif) of this whole process to give you a sense of the speed of the API (it's pretty fast considering I'm using the Free Pricing Tier);&lt;br /&gt;&lt;a href="https://i.imgur.com/sgBBFLg.gifv"&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't add the View&amp;nbsp;for this because it's pretty straight forward (and this blog is long enough) but let me know if you need it.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;img src="/globalassets/beach.jpg" alt="a sandy beach next to the ocean" &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'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="http://%20%20https//docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/home"&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="http://%20https//westus.dev.cognitive.microsoft.com/docs/services/5adf991815e1060e6355ad44/operations/56f91f2e778daf14a499e1fa"&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="https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts-sdk/csharp-analyze-sdk"&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;</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>https://www.luminary.com/blog/episerver-personalization-with-persistent-anonymous-profiles</id><published>2018-10-12T02:00:00.0000000Z</published><updated>2018-10-12T08:02:36.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">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's personalisation profile across sessions without using Episerver Insight or custom cookies. Here's how we did it...</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>https://www.luminary.com/blog/image-metadata-svg-thumbnails-episerver-dxc</id><published>2018-07-30T02:00:00.0000000Z</published><updated>2018-08-09T01:02:37.0000000Z</updated><author><name>darren.stahlhut@optimizely.com</name></author><category term="Blog post" /><summary type="html">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's how we did it...</summary></entry></feed>