<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sitecore &#8211; blog.boro2g .co.uk</title>
	<atom:link href="https://blog.boro2g.co.uk/category/sitecore/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.boro2g.co.uk</link>
	<description>Some ideas about coding, dev and all things online.</description>
	<lastBuildDate>Tue, 30 Mar 2021 14:29:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.8</generator>
	<item>
		<title>Why is choosing a CMS so damn hard?</title>
		<link>https://blog.boro2g.co.uk/why-is-choosing-a-cms-so-damn-hard/</link>
					<comments>https://blog.boro2g.co.uk/why-is-choosing-a-cms-so-damn-hard/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Tue, 30 Mar 2021 13:36:58 +0000</pubDate>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[Contentful]]></category>
		<category><![CDATA[Mach]]></category>
		<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1163</guid>

					<description><![CDATA[<p>Imagine the scenario &#8211; you start on a new feature or project and there is a need for dynamic content. Sounds simple right? Just pick a CMS platform, setup an account, update a bit of content, publish and you are done. Well, if only it was that simple! * *Note &#8211; this post assumes that [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/why-is-choosing-a-cms-so-damn-hard/">Why is choosing a CMS so damn hard?</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Imagine the scenario &#8211; you start on a new feature or project and there is a need for dynamic content. Sounds simple right? Just pick a CMS platform, setup an account, update a bit of content, publish and you are done. Well, if only it was that simple! *</p>



<p><em>*Note &#8211; this post assumes that a platform like WordPress isn&#8217;t sufficient for your requirements</em> </p>



<p><strong>Where to start?</strong></p>



<p>If you look at <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/List_of_content_management_systems" target="_blank">https://en.wikipedia.org/wiki/List_of_content_management_systems</a>, it certainly won&#8217;t clear things up. There are a LOT of options! So, what sort of information should you use to feed into your decision process?</p>



<p><strong>A few core CMS concepts</strong></p>



<p>Before we go further, let&#8217;s define a few key concepts:</p>



<ul><li>Headless Content Management System (CMS) &#8211; &#8220;A headless CMS is a content management system that provides a way to author content, but instead of having your content coupled to a particular output (like web page rendering), it provides your content as data over an API.&#8221; <a rel="noreferrer noopener" href="https://www.sanity.io/blog/headless-cms-explained" target="_blank">https://www.sanity.io/blog/headless-cms-explained</a></li><li>Digital Experience Platform (DXP) &#8211; &#8220;Gartner defines a digital experience platform (DXP) as an integrated set of technologies, based on a common platform, that provides a broad range of audiences with consistent, secure and personalized access to information and applications across many digital touchpoints.&#8221; <a rel="noreferrer noopener" href="https://www.gartner.com/reviews/market/digital-experience-platforms" target="_blank">https://www.gartner.com/reviews/market/digital-experience-platforms</a></li></ul>



<p>It&#8217;s worth noting that certain vendors aim to fulfil both entries above, whereas others operate purely as headless, cloud native SAAS providers.</p>



<p><strong>How to help you make a decision?</strong></p>



<p><em>Ah, but what if the decision has already been made</em>? </p>



<p>Within your team(s) or business(es), do you have an existing CMS? If so, can it be scaled or modified to serve your new needs. It&#8217;s worth considering that &#8216;scaled&#8217; here covers many things &#8211; licensing, usability, modifiability, supportability, physical capacity and a raft more. This discussion often leads to some interesting outcomes and can easily expose issues, or the opposite, a positive view of existing tooling.</p>



<p><em>Ok, so we already successfully use CMS X</em></p>



<p>We&#8217;re getting warmer, but I&#8217;d suggest you still need to answer a few more questions:</p>



<ul><li>Is it fit for purpose?</li><li>Do it&#8217;s content delivery approaches fit the needs of your new requirements?</li><li>Will the team that use the system be the same as the existing editors?</li></ul>



<p><strong>How to select a <em>new </em>CMS?</strong></p>



<p>I&#8217;d recommend you build up your own criteria for assessing different tools, here are a few thought starters:</p>



<ul><li>Cost<ul><li>What are the license fees, and how do they scale?<ul><li>Is it a consistent cost year by year?</li><li>What if you need more editors?</li><li>What if you need more content items, or media items?</li><li>What if you need to serve more traffic?</li><li>How much would a new environment cost?</li></ul></li><li>How much does it cost to run and maintain the system?<ul><li>What hosting costs will you incur?</li><li>How much does a release cost?</li><li>What cost lies with your different DR options?</li><li>How will the infra receive security patches and software upgrades?</li><li>What does an upgrade of the tool look like? Is it handled for you, or do you need to own an upgrade?<ul><li>Note. This has stung us hard in the past with certain vendors!</li></ul></li></ul></li></ul><ul><li>How much effort/cost is required to set it up before you can focus on delivery of features to the customer?</li></ul></li><li>Features<ul><li>Does the tool support the features you require?</li><li>Or, does the tool come with features you don&#8217;t require?<ul><li>This is an interesting point &#8211; are you buying a Ferrari when all you need is a Ford?</li></ul></li><li>Are your competitors using the same tool?<ul><li>Does it suit your business model?</li></ul></li><li>What multi-lingual requirements do you have?<ul><li>And how does that map to content and presentation?</li></ul></li></ul></li><li>Technology constraints<ul><li>Are there any technology restrictions imposed by the tools<ul><li>E.g. hosting options, language choices, CI/CD patterns, tooling constraints</li><li>Who owns the hosted platform, and how do backups work?</li><li>Does the location of data matter for your business?</li></ul></li></ul></li><li>Platform vs a tool<ul><li>This ties into the concepts above, do you want a DXP or a headless CMS</li><li>Is a <a rel="noreferrer noopener" href="https://www.avenga.com/magazine/composable-architecture" target="_blank">composable architecture</a> desirable for your team(s)?</li></ul></li><li>Out the box vs bespoke<ul><li>What comes &#8216;for free&#8217;? And, do you even want the &#8216;free&#8217; features?<ul><li>If we think of enterprise platforms such as Sitecore, you get a lot OTB for free. E.g. the concept of sites, pipelines, commands and many more. </li><li>If you go down the headless route this lies in your dev teams hands.</li></ul></li></ul></li><li>Building a team<ul><li>Can you even build a team around tool X?</li><li>Do you have in-house experience in the tool or associated tools?</li></ul></li><li>Support<ul><li>What if something goes wrong, what support can you get?<ul><li>Note, I&#8217;d see support running from before you sign the contracts all the way through to post live ongoing support</li></ul></li></ul></li><li>Scalability, performance and common NFR&#8217;s<ul><li>Will the tool scale and perform to your requirements?</li></ul></li></ul>



<p>It&#8217;s worth noting, this is not meant to be an exhaustive list &#8211; every project will have different requirements and metrics that get prioritized. The goal is to provide some thought starters in areas we&#8217;ve found useful in the past.</p>



<p><strong>Finally, the fun part &#8211; rolling it out</strong></p>



<figure class="wp-block-image size-large"><a href="https://blog.boro2g.co.uk/wp-content/uploads/2021/03/a8d4e44df35f2f5f42ebe27a2bd272d674253259f5d7862ab6624effbd3d484b1.jpg"><img fetchpriority="high" decoding="async" width="400" height="400" src="https://blog.boro2g.co.uk/wp-content/uploads/2021/03/a8d4e44df35f2f5f42ebe27a2bd272d674253259f5d7862ab6624effbd3d484b1.jpg" alt="" class="wp-image-1170" srcset="https://blog.boro2g.co.uk/wp-content/uploads/2021/03/a8d4e44df35f2f5f42ebe27a2bd272d674253259f5d7862ab6624effbd3d484b1.jpg 400w, https://blog.boro2g.co.uk/wp-content/uploads/2021/03/a8d4e44df35f2f5f42ebe27a2bd272d674253259f5d7862ab6624effbd3d484b1-300x300.jpg 300w, https://blog.boro2g.co.uk/wp-content/uploads/2021/03/a8d4e44df35f2f5f42ebe27a2bd272d674253259f5d7862ab6624effbd3d484b1-150x150.jpg 150w" sizes="(max-width: 400px) 100vw, 400px" /></a></figure>



<p>Well, almost. Now the <s>fun</s> / <s>hard</s> part (omit for your preference :)). </p>



<p>You have your new tool, but how does it map to the business? How will the editors get on with it? What does multi-lingual design look like? What technology do you use to build the front ends? Where to start? What is the meaning of life?</p>



<p>Maybe that&#8217;s content for another blog post&#8230;</p>



<p><em>Happy editing!</em></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/why-is-choosing-a-cms-so-damn-hard/">Why is choosing a CMS so damn hard?</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/why-is-choosing-a-cms-so-damn-hard/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sitecore forms &#8211; custom form element save issue</title>
		<link>https://blog.boro2g.co.uk/sitecore-forms-custom-form-element-save-issue/</link>
					<comments>https://blog.boro2g.co.uk/sitecore-forms-custom-form-element-save-issue/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Tue, 04 Aug 2020 09:17:00 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1126</guid>

					<description><![CDATA[<p>In a recent project we needed to add some richer functionality to a form, so decided to wrap it up in a custom Vue.js component which we could then integrate into Sitecore forms. Sounds simple right? Building the component Sitecore provides some good documentation on how to build different flavours of form rows &#8211; have [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/sitecore-forms-custom-form-element-save-issue/">Sitecore forms &#8211; custom form element save issue</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In a recent project we needed to add some richer functionality to a form, so decided to wrap it up in a custom Vue.js component which we could then integrate into Sitecore forms. Sounds simple right?</p>



<p><strong>Building the component</strong></p>



<p>Sitecore provides some good documentation on how to build different flavours of form rows &#8211; have a look at the walkthrough&#8217;s in <a rel="noreferrer noopener" href="https://doc.sitecore.com/developers/93/sitecore-experience-manager/en/sitecore-forms.html" target="_blank">https://doc.sitecore.com/developers/93/sitecore-experience-manager/en/sitecore-forms.html</a> if you are interested.</p>



<p><strong>Saving your data</strong></p>



<p>Assuming you want to build something a bit richer than the demo video component, chances are you want to actually store data that a user provides. In our use case, we used Vue.js to update a hidden input &#8211; under the hood we then save that data into the DB and also ping off to other save actions. </p>



<p>Simples? Well, not quite &#8211; unless you know where to set things up.</p>



<p><strong>Configuring the form row</strong></p>



<p>In Sitecore forms, a custom form row needs a few things. A template in <strong>master </strong>to represent the configuration of the form row, and a set of items in <strong>core </strong>to represent the UI for configuring the form row.</p>



<p><a rel="noreferrer noopener" href="https://doc.sitecore.com/developers/93/sitecore-experience-manager/en/walkthrough--creating-a-custom-form-element.html" target="_blank">https://doc.sitecore.com/developers/93/sitecore-experience-manager/en/walkthrough&#8211;creating-a-custom-form-element.html</a></p>



<p><strong>The importance of AllowSave</strong></p>



<p>This is the key bit, and took a fair amount of digging to find. I could see my custom data was being posted back to Sitecore, with the right data. But, it was never getting saved in the database <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>To fix I needed to make sure that both the configuration in core and my custom template had <strong>AllowSave</strong> available.</p>



<ul><li>In core, under &#8216;/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings&#8217; you create your custom configuration including sub-items based off the template &#8216;FormSection&#8217; (see &#8216;/sitecore/client/Applications/FormsBuilder/Components/Layouts/PropertyGridForm/PageSettings/Settings/SingleLineText/Advanced&#8217; for reference&#8217;<ul><li>Here is where you need to ensure you include &#8216;<strong>AllowSave</strong>&#8216; in the &#8216;<strong>ControlDefinitions</strong>&#8216; field for your custom item</li><li>This is enough to get the checkbox showing in the form builder ui, but not enough to get everything working</li></ul></li><li>In master, under &#8216;/sitecore/templates/System/Forms/Fields&#8217; you create the template to represent the configuration data being saved for your form element<ul><li>Here is where you need to make sure the base templates contains &#8216;<strong>Save Settings</strong>&#8216;</li></ul></li></ul>



<p><strong>Summary</strong></p>



<p>Setting up a custom form row / element is generally pretty simple. However, the documentation doesn&#8217;t cover quite a key step &#8211; saving the data. It doesn&#8217;t take much additional configuration as long as you know the right place to make changes!</p>



<p>Happy saving.</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/sitecore-forms-custom-form-element-save-issue/">Sitecore forms &#8211; custom form element save issue</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/sitecore-forms-custom-form-element-save-issue/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>JSS &#8211; Your data, your way. Sugcon talk</title>
		<link>https://blog.boro2g.co.uk/jss-your-data-your-way-sugcon-talk/</link>
					<comments>https://blog.boro2g.co.uk/jss-your-data-your-way-sugcon-talk/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Fri, 01 May 2020 08:23:29 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1109</guid>

					<description><![CDATA[<p>Thanks to anyone that managed to tune into the Sugcon Virtual event yesterday. As promised, a copy of the slides can be found at https://blog.boro2g.co.uk/wp-content/uploads/2020/05/JSS_Your_Data_Your_Way-Virtual.pdf And the repo of content https://github.com/boro2g/JssYourDataYourWay Stay safe everyone!</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/jss-your-data-your-way-sugcon-talk/">JSS &#8211; Your data, your way. Sugcon talk</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Thanks to anyone that managed to tune into the Sugcon Virtual event yesterday. </p>



<p>As promised, a copy of the slides can be found at <a href="https://blog.boro2g.co.uk/wp-content/uploads/2020/05/JSS_Your_Data_Your_Way-Virtual.pdf" target="_blank" rel="noreferrer noopener">https://blog.boro2g.co.uk/wp-content/uploads/2020/05/JSS_Your_Data_Your_Way-Virtual.pdf</a></p>



<p>And the repo of content <a href="https://github.com/boro2g/JssYourDataYourWay" target="_blank" rel="noreferrer noopener">https://github.com/boro2g/JssYourDataYourWay</a></p>



<p>Stay safe everyone!</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/jss-your-data-your-way-sugcon-talk/">JSS &#8211; Your data, your way. Sugcon talk</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/jss-your-data-your-way-sugcon-talk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automating a multi region deployment with Azure Devops</title>
		<link>https://blog.boro2g.co.uk/automating-a-multi-region-deployment-with-azure-devops/</link>
					<comments>https://blog.boro2g.co.uk/automating-a-multi-region-deployment-with-azure-devops/#comments</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Fri, 18 Oct 2019 11:12:24 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1085</guid>

					<description><![CDATA[<p>For a recent project we&#8217;ve invested a lot of time into Azure Devops, and in the most part found it a very useful toolset for deploying our code to both Azure and AWS. When we started on this process, YAML pipelines weren&#8217;t available for our source code provider &#8211; this meant everything had to be [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/automating-a-multi-region-deployment-with-azure-devops/">Automating a multi region deployment with Azure Devops</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>For a recent project we&#8217;ve invested a lot of time into Azure Devops, and in the most part found it a very useful toolset for deploying our code to both Azure and AWS.</p>



<p>When we started on this process, YAML pipelines weren&#8217;t available for our source code provider &#8211; this meant everything had to be setup manually <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>However, recently this has changed <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> This post will run through a few ways you can optimize your release process and automate the whole thing. </p>



<p>First a bit of background and then some actual code examples.</p>



<p><strong>Why YAML</strong>?</p>



<p>Setting up your pipelines via the UI is a really good way to quickly prototype things, however what if you need to change these pipelines to mimic deployment features alongside code features. Yaml allows you to keep the pipeline definition in the same codebase as the actual features. You deploy branch XXX and that can be configured differently to branch YYY.</p>



<p>Another benefit, the changes are then visible in your pull requests so validating changes is a lot easier.</p>



<p><strong>Async Jobs</strong></p>



<p>A big optimization we gained was to release to different regions in parallel. Yaml makes this very easy by using Jobs &#8211; each job can run on an agent and hence push to multiple regions in parallel.</p>



<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&amp;tabs=yaml">https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&amp;tabs=yaml</a></p>



<p><strong>Yaml file templates</strong></p>



<p>If you have common functionality you want to duplicate, e.g. &#8216;Deploy to Eu-West-1&#8217;, templates are a good way to split your functionality. They allow you to group logical functionality you want to run multiple times.</p>



<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops">https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops</a></p>



<p><strong>Azure Devops rest API</strong></p>



<p>All of your build/releases can be triggered via the UI portal, however if you want to automate that process I&#8217;d suggest looking into the rest API. Via this you can trigger, monitor and administer builds, releases and a whole load more. </p>



<p>We use powershell to orchestrate the process.</p>



<p><a href="https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/queue?view=azure-devops-rest-5.1">https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/queue?view=azure-devops-rest-5.1</a></p>



<p><strong>Variables, and variable groups</strong></p>



<p>I have to confess, this syntax feels slightly cumbersome, but it&#8217;s very possible to reference variables passed into a specific pipeline along with global variables from groups you setup in the <strong>Library </strong>section of the portal.</p>



<p><strong>Now, some examples</strong></p>



<p>The root YAML file:</p>



<pre class="crayon-plain-tag">pr: none
trigger: none

variables:
- group: 'DataDog' # reference Variable groups if needed
- name : 'system.debug'
  value: true
- name : 'DynamicParameter' # these can be calculated off other variable values
  value: &quot;name-$(EnvironmentName)-$(ColourName)&quot;
- name: 'WebsiteFolder'
  value: 'Website/FolderName'

#- name: &quot;EnvironmentName&quot; # see the rest api example below for how to pass in variables
#  value: &quot;Set externally&quot;
#- name: &quot;ColourName&quot;
#  value: &quot;Set externally&quot;
#- name: &quot;AwsCredentials&quot;
#  value: &quot;Set externally&quot;

jobs:
- job: Build
  pool:
    vmImage: 'windows-2019' # vmImages: https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops#use-a-microsoft-hosted-agent
  steps:  
 
  - task: NuGetToolInstaller@0
    displayName: 'Use NuGet 4.4.1'
    inputs:
      versionSpec: 4.4.1    

  - task: NuGetCommand@2 # if using secure artifacts, you can download them into a dotnetcore project this way
    displayName: 'NuGet restore'
    inputs:
      restoreSolution: 'Website/###.sln'
      feedsToUse: config
      nugetConfigPath: Website/nuget.config

  - task: Npm@1
    displayName: 'NPM install'
    inputs:
      workingDir: '$(WebsiteFolder)'     
      verbose: false

  - task: Npm@1
    displayName: 'NPM build scss'
    inputs:
      workingDir: '$(WebsiteFolder)'     
      command: custom
      verbose: false
      customCommand: 'run scss-build'

  - task: DotNetCoreCLI@2
    displayName: 'dotnet publish'
    inputs:
      command: publish
      publishWebProjects: false
      projects: '$(WebsiteFolder)/Website.csproj'
      arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)\Website'
      zipAfterPublish: false  

  - task: PublishPipelineArtifact@0 # in order to share the common build with multiple releases you need to publish the artifact
    inputs:
      artifactName: &quot;Website&quot;
      targetPath: '$(Build.ArtifactStagingDirectory)'

- job: ReleaseEU
  pool:
    vmImage: 'windows-2019'
  dependsOn: Build # these will only start when the 'Build' task above starts
  steps:
  - template: TaskGroups/DeployToRegion.yaml # this
    parameters:
      AwsCredentials: '$(AwsCredentials)'
      RegionName: 'eu-west-1'      
      EnvironmentName: '$(EnvironmentName)'
      ColourName: '$(ColourName)'
      DatadogApiKey: '$(DatadogApiKey)' # referenced from a variable group      

- job: ReleaseRegionN # Will run in parallel with ReleaseEU if you have enough build agents
  pool:
    vmImage: 'windows-2019'
  dependsOn: Build
  steps:
  - template: TaskGroups/DeployToRegion.yaml # this template file is shown below
    parameters:
      AwsCredentials: '$(AwsCredentials)'
      RegionName: 'ANother region'      
      EnvironmentName: '$(EnvironmentName)'
      ColourName: '$(ColourName)'
      DatadogApiKey: '$(DatadogApiKey)' # referenced from a variable group</pre>



<p>The &#8216;DeployToRegion&#8217; template:</p>



<pre class="crayon-plain-tag">parameters:
  AwsCredentials: ''
  RegionName: ''  
  EnvironmentName: ''
  ColourName: ''
  DatadogApiKey: ''  

steps:
- task: DownloadPipelineArtifact@1 # you can download artifacts from other builds if needed
  inputs:
      buildType: 'specific'
      project: 'Project Name'
      pipeline: '##'
      buildVersionToDownload: 'latest'
      artifactName: 'Devops'
      targetPath: '$(System.ArtifactsDirectory)/Devops'

- task: DownloadPipelineArtifact@1 # or download from the current one
  inputs:
      buildType: 'current'
      artifactName: 'Website'
      targetPath: '$(System.ArtifactsDirectory)'

- template: DeployToElasticBeanstalk.yaml # and can chain templates if needed
  parameters:
      AwsCredentials: '${{ parameters.AwsCredentials }}'
      RegionName: '${{ parameters.RegionName }}'      
      EnvironmentName: '${{ parameters.EnvironmentName }}'
      ColourName: '${{ parameters.ColourName }}'
      DatadogApiKey: '${{ parameters.DatadogApiKey }}'</pre>



<p>And finally some powershell to fire it all off:</p>



<pre class="crayon-plain-tag">### Example usage: .\TriggerBuild.ps1 -branch &quot;release/release-006&quot; -isReleaseCandidate $false -additionalReleaseParameters @{ &quot;EnvironmentName&quot; = &quot;qa&quot;; &quot;ColourName&quot; = &quot;blue&quot;; }

param (
    [Parameter(Mandatory = $true)][string]$branch,   
    [boolean]$isReleaseCandidate = $false,
    [HashTable]$additionalReleaseParameters = @{ }
)

$ErrorActionPreference = &quot;Stop&quot;

$authToken = Get-DevOpsAuthToken # see https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops for how to get a token
$accountName = &quot;AzureDevopsAccountName&quot; 
$projectName = &quot;AzureDevopsProjectName&quot;

$buildDefinitionIds = @(27) # the build pipeline id

Write-Host &quot;Building with settings:&quot;
Write-Host &quot;Branch: '$branch'&quot;
Write-Host &quot;Tag as 'release-candidate' and retain build: $isReleaseCandidate&quot;
Write-Host &quot;Build definition IDs: $buildDefinitionIds&quot;
Write-Host &quot;Additional parameters: $($additionalReleaseParameters | ConvertTo-Json) &quot;
Write-Host &quot;&quot;

$releaseIds = @()

$result = @{
    Success = $false;    
}

foreach ($definitionId in $buildDefinitionIds)
{
    $deploymentParams = @{
        &quot;definition&quot; = @{
            &quot;id&quot; = $definitionId;
        }
        &quot;sourceBranch&quot; = $branch;
    }

    if ($additionalReleaseParameters.GetEnumerator().length -gt 0)
    {
        $deploymentParams.parameters = $additionalReleaseParameters | ConvertTo-Json
    }

    $content = (Invoke-WebRequest -uri &quot;https://dev.azure.com/$accountName/$projectName/_apis/build/builds?api-version=4.1&quot; `
        -ContentType &quot;application/json&quot; -Headers (Get-DevOpsHeaders -AuthToken $authToken) -Method POST -Body ($deploymentParams | ConvertTo-Json)).Content | ConvertFrom-Json

    $releaseIds += $content.id  

    Write-Host &quot;Build $($content.id) queued: https://dev.azure.com/$accountName/$projectName/_build/results?buildId=$($content.id)&quot; -ForegroundColor Yellow
}

$aBuildFailed = $false

foreach ($releaseId in $releaseIds)
{
    $status = &quot;&quot;

    while ($status -ne &quot;completed&quot;)
    {
        try
        {
            $content = (Invoke-WebRequest -uri &quot;https://dev.azure.com/$accountName/$projectName/_apis/build/builds/$releaseId&quot; -Headers (Get-DevOpsHeaders -AuthToken $authToken)).Content | ConvertFrom-Json
        }
        catch
        {
            Write-Host &quot;  Error calling DevopsAPI. If this happens several times check the url: https://dev.azure.com/$accountName/$projectName/_apis/build/builds/$releaseId&quot; -ForegroundColor red
        }

        $status = $content.status

        Write-Host &quot; Build id $releaseId has status: $status&quot;

        if ($content.result -eq &quot;failed&quot; -or $content.result -eq &quot;canceled&quot;)
        {
            $aBuildFailed = $true

            Write-Host &quot;Build $releaseId failed - check https://dev.azure.com/$accountName/$projectName/_build/results?buildId=$releaseId for details&quot; -ForegroundColor Red
        }
        elseif ($content.result -eq &quot;completed&quot;)
        {
            Write-Host &quot;Build $releaseId completed successfully&quot; -ForegroundColor Green
        }

        Start-Sleep -s 5
    }

    if ($isReleaseCandidate -eq $true)
    {
        Write-Host &quot; Adding RC tags: release-candidate&quot;
        $tags = (Invoke-WebRequest -uri &quot;https://dev.azure.com/$accountName/$projectName/_apis/build/builds/$releaseId/tags/release-candidate?api-version=4.1&quot; -Headers (Get-DevOpsHeaders -AuthToken $authToken) -Method PUT).Content | ConvertFrom-Json

        Write-Host &quot; Adding retain build to $releaseId&quot;
        $updates = (Invoke-WebRequest -uri &quot;https://dev.azure.com/$accountName/$projectName/_apis/build/builds/$($releaseId)?api-version=4.1&quot; -ContentType &quot;application/json&quot; -Headers (Get-DevOpsHeaders -AuthToken $authToken) -Method PATCH -Body (@{&quot;retainedByRelease&quot; = $true } | ConvertTo-Json)).Content | ConvertFrom-Json
    }
}

$result.Success = !$aBuildFailed

return $result</pre>



<p>Happy deploying <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/automating-a-multi-region-deployment-with-azure-devops/">Automating a multi region deployment with Azure Devops</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/automating-a-multi-region-deployment-with-azure-devops/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>JSS Blog post series</title>
		<link>https://blog.boro2g.co.uk/jss-blog-post-series/</link>
					<comments>https://blog.boro2g.co.uk/jss-blog-post-series/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Mon, 24 Jun 2019 09:34:25 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<category><![CDATA[sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1081</guid>

					<description><![CDATA[<p>I&#8217;ve recently been working with the Marketing team within Valtech to get a series of JSS Blog posts published onto the Valtech site. If anyone is interested you can access them via https://www.valtech.com/en-gb/insights/going-live-with-jss/ The topics cover things like what it’s like to move from being a traditional Sitecore dev to a JSS dev, how to [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/jss-blog-post-series/">JSS Blog post series</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve recently been working with the Marketing team within Valtech to get a series of JSS Blog posts published onto the Valtech site.</p>



<p>If anyone is interested you can access them via  <a href="https://www.valtech.com/en-gb/insights/going-live-with-jss/">https://www.valtech.com/en-gb/insights/going-live-with-jss/</a> </p>



<p><em>The topics cover things like what it’s like to move from being a traditional Sitecore dev to a JSS dev, how to get everything deployed, any gotchas we didn&#8217;t estimate for when we started and some key design decisions we made along the way. </em></p>



<p>I hope you find them useful <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/jss-blog-post-series/">JSS Blog post series</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/jss-blog-post-series/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setting a row colour in powershell &#124; Format-Table</title>
		<link>https://blog.boro2g.co.uk/setting-a-row-colour-in-powershell-format-table/</link>
					<comments>https://blog.boro2g.co.uk/setting-a-row-colour-in-powershell-format-table/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Wed, 17 Apr 2019 15:33:30 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1021</guid>

					<description><![CDATA[<p>This is quite a quick post, but a useful tip. If you are setting up some data in powershell which you then fire at the console via &#124; Format-Table it can be useful to highlight specific rows. Imagine you have a hashtable with the key as a string, and the value as a number. When [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/setting-a-row-colour-in-powershell-format-table/">Setting a row colour in powershell | Format-Table</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This is quite a quick post, but a useful tip. If you are setting up some data in powershell which you then fire at the console via <strong>| Format-Table</strong> it can be useful to highlight specific rows.</p>



<p>Imagine you have a hashtable with the key as a string, and the value as a number. When you send to the console you will see the names and values set in a table. </p>



<pre class="crayon-plain-tag">@{&quot;Bob&quot;=1;&quot;John&quot;=3;} | Format-Table</pre>



<p>Now if you want to set <strong>John</strong> to be a certain colour then you can use the code below.  <br><em>Note for static values this doesn&#8217;t add much value, we use it for a table that is getting printed dynamically e.g. based on a timer tick and dynamic version of the Name </em></p>



<pre class="crayon-plain-tag">@{&quot;Bob&quot;=1;&quot;John&quot;=3;} | Format-Table @{
            Label = &quot;Name&quot;
            Expression =
            {
                if (&quot;John&quot; -eq $_.Name)
                {
                    $color = &quot;32&quot; #green
                }
                else
                {
                    $color = &quot;0&quot; #white
                }
                $e = [char]27
                &quot;$e[${color}m$($_.Name)${e}[0m&quot;
            }
        }, Value</pre>



<p>This requires PowerShell 5.1 or later (check with <code>$PSVersionTable.PSVersion</code>)  and doesn&#8217;t seem to play fair with the PowerShell ISE, however from a normal PowerShell window or VSCode it works a charm.</p>



<p>Happy colouring <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/setting-a-row-colour-in-powershell-format-table/">Setting a row colour in powershell | Format-Table</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/setting-a-row-colour-in-powershell-format-table/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Build yourself a JMeter load testing server</title>
		<link>https://blog.boro2g.co.uk/build-yourself-a-jmeter-load-testing-server/</link>
					<comments>https://blog.boro2g.co.uk/build-yourself-a-jmeter-load-testing-server/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Wed, 13 Mar 2019 14:21:36 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<category><![CDATA[load testing]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=1015</guid>

					<description><![CDATA[<p>As you come close to launching your new web application, whether it be Sitecore, Node or plain ol&#8217; HTML, it&#8217;s always good to validate how well it performs. The cloud opens up lots of possibilities for how to approach this &#8211; including lots of online LTAAS (er, is load test as a service even a [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/build-yourself-a-jmeter-load-testing-server/">Build yourself a JMeter load testing server</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As you come close to launching your new web application, whether it be Sitecore, Node or plain ol&#8217; HTML, it&#8217;s always good to validate how well it performs.</p>



<p>The cloud opens up lots of possibilities for how to approach this &#8211; including lots of online LTAAS (er, is load test as a service even a thing!?!? :))</p>



<p><strong>Iteration 1 &#8211; LTAAS with Azure Devops</strong></p>



<p>We are using Azure Devops within our current project, so thought it be good to give their load testing features a blast. This came with mixed success, and a mixed $$$ cost.</p>



<p><em>Pro&#8217;s</em></p>



<ul><li>You don&#8217;t need to manage any of the kit</li><li>The sky&#8217;s the limit with the amount of concurrent machines to run (&lt; 25)</li><li>It supports various methods for building a script</li></ul>



<p><em>Con&#8217;s</em></p>



<ul><li>The feedback loop can feel slow</li><li>You get limited support for JMeter scripts, and limited graph&#8217;s of your results. <em>Note, this could be due to inexperience with the tool</em></li><li>It costs per minute of load test you run. We managed to un-wittingly rack up quite a substantial bill with a misconfigured script.</li></ul>



<p><strong>Iteration 2 &#8211; DIY</strong></p>



<p>Another approach is that you actually setup the infrastructure yourself. For our capacity and requirements this ended up being a much more favourable option &#8211; once we&#8217;d managed to get the most out of our kit.</p>



<p><em>Pro&#8217;s</em></p>



<ul><li>Assuming you use JMeter, you can quickly iterate through tests and get a wide spread of results as you go</li><li>If you need more grunt, you can always increase the box spec&#8217;s</li></ul>



<p><em>Con&#8217;s</em></p>



<ul><li>You need to tune the box to get the most out of it</li><li>Large boxes in e.g. AWS cost $$$</li></ul>



<p><strong>Configuring things yourself</strong></p>



<p>Here are a few steps to follow if you really want to max out your load test box, as well as you web infrastructure:</p>



<ul><li>Pick a box with plenty of RAM &#8211; we opted for and AWS  <br>r5.2xlarge  &#8211;  8 core and 64GB RAM</li><li>Ensure JMeter can use all the RAM it can. Within JMeter.bat you can set the heap size available to the program &#8211; by default this is 512mb. If you add <code>set HEAP=-Xms256m -Xmx60g</code> then JMeter will sap up all 60GB of RAM it can</li><li>Ensure Windows can use as many TCPIP connections as possible. Again, by default this is quite low. You need to set 2 registry keys &#8211; see <a rel="noreferrer noopener" aria-label="http://docs.testplant.com/epp/9.0.0/ePP/advovercoming_tcpip_connection_li.htm (opens in a new tab)" href="http://docs.testplant.com/epp/9.0.0/ePP/advovercoming_tcpip_connection_li.htm" target="_blank">http://docs.testplant.com/epp/9.0.0/ePP/advovercoming_tcpip_connection_li.htm</a> for more details. <ul><li>Until we&#8217;d set these values, our tests would bomb out after a couple minutes as the box simply couldn&#8217;t connect to our website any more.</li></ul></li></ul>



<p><strong>Other tips</strong></p>



<p>JMeter has some really good plugins for modelling load, in particular around step&#8217;d load and realtime visualization of results. </p>



<p>I&#8217;d recommend checking out:</p>



<ul><li><a rel="noreferrer noopener" aria-label="https://jmeter-plugins.org/wiki/ConcurrencyThreadGroup/ (opens in a new tab)" href="https://jmeter-plugins.org/wiki/ConcurrencyThreadGroup/" target="_blank">https://jmeter-plugins.org/wiki/ConcurrencyThreadGroup/</a></li><li><a href="https://jmeter-plugins.org/wiki/TransactionsPerSecond/" target="_blank" rel="noreferrer noopener" aria-label="https://jmeter-plugins.org/wiki/TransactionsPerSecond/ (opens in a new tab)">https://jmeter-plugins.org/wiki/TransactionsPerSecond/</a></li></ul>



<p><strong>Some good additional reading</strong></p>



<p><a href="https://www.blazemeter.com/blog/9-easy-solutions-jmeter-load-test-%E2%80%9Cout-memory%E2%80%9D-failure">https://www.blazemeter.com/blog/9-easy-solutions-jmeter-load-test-%E2%80%9Cout-memory%E2%80%9D-failure</a></p>



<p>Happy testing! <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/build-yourself-a-jmeter-load-testing-server/">Build yourself a JMeter load testing server</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/build-yourself-a-jmeter-load-testing-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Setting up JSS with Vue, Typescript and dependency injection</title>
		<link>https://blog.boro2g.co.uk/setting-up-jss-with-vue-typescript-and-dependency-injection/</link>
					<comments>https://blog.boro2g.co.uk/setting-up-jss-with-vue-typescript-and-dependency-injection/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Mon, 04 Feb 2019 11:23:03 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<category><![CDATA[jss]]></category>
		<category><![CDATA[sitecore]]></category>
		<category><![CDATA[typescript]]></category>
		<category><![CDATA[vue]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=991</guid>

					<description><![CDATA[<p>If JSS is a new term for you, I&#8217;d seriously recommend checking our the documentation that Sitecore have provided: https://jss.sitecore.com/ . By the end of this post we&#8217;ll have run through how you can get JSS up and running locally, with dependencies all wired together using a DI container and any functional aspects written in [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/setting-up-jss-with-vue-typescript-and-dependency-injection/">Setting up JSS with Vue, Typescript and dependency injection</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If JSS is a new term for you, I&#8217;d seriously recommend checking our the documentation that Sitecore have provided: <a rel="noreferrer noopener" aria-label="https://jss.sitecore.com/ (opens in a new tab)" href="https://jss.sitecore.com/" target="_blank">https://jss.sitecore.com/</a> . </p>



<p>By the end of this post we&#8217;ll have run through how you can get JSS up and running locally, with dependencies all wired together using a DI container and any functional aspects written in TypeScript. For us this is a key set of requirements &#8211; we&#8217;ve worked with many projects that have grown over several years. By putting in some key rules and requirements up front should mean with good discipline that the codebase can scale over time.</p>



<p><strong>Why&nbsp;JSS?</strong></p>



<p>Imagine a standard Sitecore development team, typically based around C# developers and some front end devs. In the default approach to building a site you&#8217;d need everyone to contribute Razor files with the markup and associated styling and functionality. This is the approach you would probably have seen for several years until more recently with the demand for richer front end technologies. Think Vue, Angular, React and so on. </p>



<p>This is what JSS facilitates.</p>



<p><strong>Is this right for everyone?</strong></p>



<p>Just because technologies exist, it doesn&#8217;t always make them the right platform to jump on. E.g. if you have a very established Sitecore development team that doesn&#8217;t have the appetite for these front end technologies, then JSS might not be the thing for you.</p>



<p><strong>Getting started</strong></p>



<p>The quick start from the docs site provides 4 tasks to get you started:</p>



<pre class="crayon-plain-tag">npm install -g @sitecore-jss/sitecore-jss-cli
jss create my-first-jss-app vue
cd my-first-jss-app
jss start</pre>



<p>Provided you have node installed, once you run ^ you should then see <a href="http://localhost:3000" target="_blank" rel="noreferrer noopener" aria-label="http://localhost:3000 (opens in a new tab)">http://localhost:3000</a> fire up.</p>



<p><strong>Why TypeScript?</strong></p>



<p>I wouldn&#8217;t consider starting a new web project now without TypeScript as it provides so many useful features for a codebase. Refactoring is just like if you were using C#, variables have types, classes can implement other abstract classes or interfaces. If you&#8217;ve not used it before, I&#8217;d highly recommend it.</p>



<p>In terms of designing your application, another key factor to consider is the coupling between the different layers. Core functionality being one layer, your UI framework being another. If you structure things so that e.g. you can peel out Vue without too much trouble, moving up through different technologies or versions will be a breeze.</p>



<p><strong>Changes to the default app</strong></p>



<p>Here we&#8217;ll add things like some demo services, some DI registrations and a few other bits we&#8217;ll need.</p>



<p>1.First up lets include some extra dependencies:</p>



<pre class="crayon-plain-tag">npm install -d inversify-inject-decorators, vue-class-component, inversify, vue-property-decorator, reflect-metadata, ts-loader, typescript</pre>



<p>2. In src/AppRoot.vue, before the <code>export default</code> line add <code>import "reflect-metadata"</code><br></p>



<p>3. Add a tsconfig.json file to the root folder (a level above src):</p>



<pre class="crayon-plain-tag">{
    &quot;compilerOptions&quot;: {
        &quot;outDir&quot;: &quot;./built/&quot;,
        &quot;sourceMap&quot;: true,
        &quot;strict&quot;: true,
        &quot;module&quot;: &quot;es2015&quot;,
        &quot;moduleResolution&quot;: &quot;node&quot;,
        &quot;target&quot;: &quot;es5&quot;,       
        &quot;lib&quot;: [
            &quot;es6&quot;,
            &quot;dom&quot;
        ],
        &quot;types&quot;: [
            &quot;reflect-metadata&quot;
        ],
        &quot;experimentalDecorators&quot;: true,
        &quot;emitDecoratorMetadata&quot;: true,
        &quot;baseUrl&quot;: &quot;./src&quot;,
        &quot;paths&quot;: {            
            &quot;@di_ids&quot;: [&quot;DependencyInjection/Identifiers&quot;]
        }
    },
    &quot;include&quot;: [
        &quot;./src/**/*&quot;
    ]
}</pre>



<p>4. Update the webpack config, in the Vue world this is done in <code>vue.config.js</code></p>



<pre class="crayon-plain-tag">//at the top of the file:
let path= require('path');

//alongside the graphql includes:
config.module.rules.push({
    test: /\.tsx?$/,
    loader: 'ts-loader',
    exclude: /node_modules/,
    options: {
      appendTsSuffixTo: [/\.vue$/],
    }
  });

config.resolve.extensions.push('.ts');

//note, this is required for alias'ing to work for your references - a nice way to avoid crazy import statements. Same change exists in tsconfig

config.resolve.alias[&quot;@di_ids&quot;] = path.resolve(__dirname, 'src/DependencyInjection/Identifiers')</pre>



<p>5. Now add a <code>vue-shim.d.ts</code> (in the src folder)</p>



<pre class="crayon-plain-tag">declare module &quot;*.vue&quot; {
    import Vue from &quot;vue&quot;;
    export default Vue;
}</pre>



<p>6. Next, some dummy TypeScript dependencies:</p>



<pre class="crayon-plain-tag">// /src/scripts/processors/TestProcessor.ts

import { IService } from &quot;../services/TestService&quot;;
import { inject, injectable } from 'inversify';
import {SERVICE_IDENTIFIER} from &quot;@di_ids&quot;;

@injectable()
export default class TestProcessor
{    
    constructor(@inject(SERVICE_IDENTIFIER.IService) private service:IService) {        
        
    }

    public DoSomething() : string {
        return this.service.DoIt();
    }
}

// /src/scripts/services/TestServices.ts

import { injectable } from 'inversify';

@injectable()
export class ServiceA implements IService {
    DoIt(): string {
        return &quot;ServiceA&quot;;
    }

}
@injectable()
export class ServiceB implements IService {
    DoIt(): string {
        return &quot;ServiceB&quot;;
    }

}

export interface IService {
    DoIt(): string;
}</pre>



<p>7. And the DI  container and keys:</p>



<pre class="crayon-plain-tag">// /src/DependencyInjection/ContainerRoot.ts

import { Container } from &quot;inversify&quot;;
import getDecorators from 'inversify-inject-decorators';
import TestModule from './Modules/TestModule'

let container = new Container();

container.load(TestModule);

const { lazyInject } = getDecorators(container);

export { container, lazyInject }

// /src/DependencyInjection/Identifiers.ts

const SERVICE_IDENTIFIER = {
    IService: Symbol(&quot;IService&quot;),
    Container: Symbol(&quot;Container&quot;),
    TestProcessor: Symbol(&quot;TestProcessor&quot;)
};

export {SERVICE_IDENTIFIER}

// /src/DependencyInjection/Modules/TestModule.ts

import { ContainerModule, interfaces } from &quot;inversify&quot;;
import { SERVICE_IDENTIFIER } from &quot;../Identifiers&quot;;
import { IService, ServiceA, ServiceB } from &quot;../../scripts/services/TestService&quot;;
import TestProcessor from &quot;../../scripts/processors/TestProcessor&quot;;

const testServices = new ContainerModule(
    (
        bind: interfaces.Bind
    ) =&gt; {
        bind&lt;IService&gt;(SERVICE_IDENTIFIER.IService).to(ServiceA);
        bind&lt;TestProcessor&gt;(SERVICE_IDENTIFIER.TestProcessor).to(TestProcessor);
    }
);

export default testServices;</pre>



<p>8. Now a TypeScript enabled Vue component: <code>/src/components/Hello.vue</code></p>



<pre class="crayon-plain-tag">&lt;template&gt;
    &lt;div&gt;
        &lt;div class=&quot;greeting&quot;&gt;Hello {{name}}{{exclamationMarks}}&lt;/div&gt;
        &lt;button @click=&quot;decrement&quot;&gt;-&lt;/button&gt;
        &lt;button @click=&quot;increment&quot;&gt;+&lt;/button&gt;       
    &lt;/div&gt;
&lt;/template&gt;

&lt;script lang=&quot;ts&quot;&gt;
import { Vue, Component, Prop, Inject } from 'vue-property-decorator'
import { Container } from &quot;inversify&quot;;
import TestProcessor from '../scripts/processors/TestProcessor';
import { SERVICE_IDENTIFIER } from &quot;@di_ids&quot;;
import { inject, injectable } from 'inversify';
import { lazyInject } from '../DependencyInjection/ContainerRoot';


@Component({
    //components: { SubComponent }
})
export default class Hello extends Vue
{      
    @lazyInject(SERVICE_IDENTIFIER.TestProcessor)
    private _testProcessor!: TestProcessor;

// // If you want to use Vue's OTB Inject/Provide you can
    // @Inject(SERVICE_IDENTIFIER.Container)
    // private _container!: Container;

    created (): void {
        //console.log(this._container.resolve&lt;TestProcessor&gt;(TestProcessor).DoSomething());

        console.log(this._testProcessor.DoSomething());
    }

    @Prop() name!: string;
    @Prop() initialEnthusiasm!: number;    

    enthusiasm = this.initialEnthusiasm;

    increment() {
        this.enthusiasm++;
    }
    decrement() {
        if (this.enthusiasm &gt; 1) {
            this.enthusiasm--;
        }
    }

    get exclamationMarks(): string {
        return Array(this.enthusiasm + 1).join('!');
    }    
}
&lt;/script&gt;

&lt;style&gt;
.greeting {
    font-size: 20px;
}
&lt;/style&gt;</pre>



<p>9. And to finally get it showing on a page, edit layout.vue to include your component:</p>



<pre class="crayon-plain-tag">&lt;div class=&quot;container&quot;&gt;
      &lt;!-- &lt;placeholder name=&quot;jss-main&quot; :rendering=&quot;route&quot; /&gt; --&gt;
      &lt;Hello :initialEnthusiasm=&quot;5&quot; /&gt;
&lt;/div&gt;

//...
import Hello from './components/Hello'

//...
components: {
    //...,
    Hello
},</pre>



<p>After all that, you should see the homepage load up and &#8220;ServiceA&#8221; getting logged to the console. Not the most impressive output but shows the full flow of dependencies getting configured and resolved, with all the code written in TypeScript <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>If you are using SSR Renderings, you&#8217;ll also need to add <code>|ts</code> into the list of rules that get &#8216;unshift&#8217;ed in <code>/server/server.vue.config.js</code></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/setting-up-jss-with-vue-typescript-and-dependency-injection/">Setting up JSS with Vue, Typescript and dependency injection</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/setting-up-jss-with-vue-typescript-and-dependency-injection/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deploying custom code to xConnect and the Marketing Automation Engine</title>
		<link>https://blog.boro2g.co.uk/deploying-custom-code-to-xconnect-and-the-marketing-automation-engine/</link>
					<comments>https://blog.boro2g.co.uk/deploying-custom-code-to-xconnect-and-the-marketing-automation-engine/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Fri, 23 Nov 2018 16:04:39 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=980</guid>

					<description><![CDATA[<p>Over the last few years the deployment footprint of a fully functional Sitecore application has shifted hugely. It&#8217;s no longer as simple as one database server and a couple web nodes &#8211; now you need to consider all kinds of different infrastructure. What are the different parts of Sitecore 9? xConnect &#8211; a separate web [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/deploying-custom-code-to-xconnect-and-the-marketing-automation-engine/">Deploying custom code to xConnect and the Marketing Automation Engine</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Over the last few years the deployment footprint of a fully functional Sitecore application has shifted hugely. It&#8217;s no longer as simple as one database server and a couple web nodes &#8211; now you need to consider all kinds of different infrastructure.</p>



<p><strong>What are the different parts of Sitecore 9?</strong></p>



<ul><li>xConnect &#8211; a separate web application to your main site</li><li>AutomationEngine &#8211; this runs as a windows service</li><li>IndexWorker &#8211; this also runs as a windows service</li><li>Website &#8211; much like the good ol&#8217; days <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li></ul>



<p><strong>Adding your own customizations</strong></p>



<p>It&#8217;s pretty simple to <a href="https://doc.sitecore.net/developers/xp/xconnect/xconnect-model/facets/creating-facets/index.html" target="_blank" rel="noopener">setup your own custom facets</a>. However what&#8217;s slightly harder is how do you deploy these to all of the different functions above? If the dll&#8217;s and configs don&#8217;t match between e.g. the website and xConnect you will get errors in the logs &#8211; luckily these do a good job of explaining the mismatch.</p>



<p><strong>Sharing the love</strong></p>



<p>In its simplest form the process of deploying your custom facet relies on 2 things &#8211; the dll that contains the facet and a json representation of the facets. To generate the JSON try <a href="https://doc.sitecore.net/developers/xp/xconnect/xconnect-model/managing-model/deployment.html" target="_blank">this</a>.</p>



<p><strong>Automate the boring stuff</strong></p>



<p>No one likes doing the same thing again and again, especially if you consider deploying something like this to multiple servers in the cloud. </p>



<p>For a recent demo I built a process that worked both locally and remotely. This was great as the octopus deploy step only had to run one exe and the whole deployment glued together as expected.</p>



<p><strong>Just show me the codez!</strong></p>



<p>Just before we do I&#8217;ll quickly explain the steps involved:</p>



<ol><li>Build the code (no shit sherlock)</li><li>Write the json schema</li><li>Deploy the model config (see the sitecore post earlier about this format)</li><li>Deploy the dlls</li><li>Deploy the patch configs</li><li>Deploy the agent configs. Note these assume you are using Slow Cheetah to transform accordingly for each environment</li></ol>



<p>Before you run it you need to:</p>



<ol><li>Correct the references to things like xConnect etc</li><li>Correct the references to the dlls you want to include and set their names in the DeployDlls method (<strong>var dllsToCopy</strong>)</li><li>Set the <strong>deploymentFolder</strong></li></ol>



<p>All the <a href="https://github.com/boro2g/xConnectDeployer" target="_blank" rel="noopener">source code is available online here</a></p>



<p>One file of note is <strong>sc.MarketingAutomation.ActivityTypes.xml</strong> &#8211; this allows you to patch in things like custom MA Actions, setup dependency injection within the MAEngine and a whole raft more.</p>



<p><a href="https://github.com/boro2g/xConnectDeployer" target="_blank"></a></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/deploying-custom-code-to-xconnect-and-the-marketing-automation-engine/">Deploying custom code to xConnect and the Marketing Automation Engine</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/deploying-custom-code-to-xconnect-and-the-marketing-automation-engine/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Debugging Sitecore Marketing Automation UI</title>
		<link>https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation-ui/</link>
					<comments>https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation-ui/#respond</comments>
		
		<dc:creator><![CDATA[boro]]></dc:creator>
		<pubDate>Wed, 24 Oct 2018 13:13:53 +0000</pubDate>
				<category><![CDATA[Sitecore]]></category>
		<category><![CDATA[marketing automation]]></category>
		<category><![CDATA[sitecore]]></category>
		<guid isPermaLink="false">https://blog.boro2g.co.uk/?p=965</guid>

					<description><![CDATA[<p>The previous post detailed how you can debug the server side aspects of the Marketing Automation agent. If you start experimenting with richer functionality, I&#8217;m sure you&#8217;ll soon want to create your own custom activities and UI&#8217;s. Sitecore provide a good description of doing this in their documentation. Adding custom fields to the UI In [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation-ui/">Debugging Sitecore Marketing Automation UI</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>The <a href="https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation/">previous post</a> detailed how you can debug the server side aspects of the Marketing Automation agent. If you start experimenting with richer functionality, I&#8217;m sure you&#8217;ll soon want to create your own custom activities and UI&#8217;s.</p>



<p>Sitecore provide a good description of doing this in their <a href="https://doc.sitecore.net/developers/xp/marketing-automation/activities/activity-types/add-activity-type-to-ui.html" target="_blank">documentation</a>.</p>



<p><strong>Adding custom fields to the UI</strong></p>



<p>In my demo activity, I needed to include a MessageKey that would be passed through to the backend engine. Getting the field to show was relatively easy if you follow the example. I&#8217;d also recommend checking out <a href="https://github.com/avershalovich/Demo9.Features/tree/master/Demo9.Features.UI/SendPromoEmailAction-UI" target="_blank">this repo</a>.</p>



<p>The problem I hit was getting the MessageKey value to render correctly in the UI when I opened a plan for the second time &#8211; rather than seeing the Key displayed as expected, you&#8217;d see an empty block.</p>



<figure class="wp-block-image"><img decoding="async" width="93" height="264" src="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-no-data.png" alt="" class="wp-image-967"/><figcaption>Missing key value</figcaption></figure>



<figure class="wp-block-image"><img decoding="async" width="243" height="256" src="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-with-data.png" alt="" class="wp-image-968"/><figcaption>Showing the key value</figcaption></figure>



<p><strong>Why was this?</strong></p>



<p>Well, it turns out the <strong>MessageKey != messageKey</strong> . For some reason, when you write your custom typescript activity, you need to reference &#8216;this.editorParams.messageKey&#8217;, not &#8216;this.editorParams.MessageKey&#8217;. Note the capital, or lack of, <strong>M</strong>.</p>



<p><strong>Missing bits of Sitecore</strong></p>



<p>One thing the docs doesn&#8217;t mention is when you create your custom parameter within the Sitecore tree, you need to set a couple additional fields (Editor ID, Editor Parameters). Have a look at some existing ones for more details.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="770" height="289" src="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-params.png" alt="" class="wp-image-969" srcset="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-params.png 770w, https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-params-300x113.png 300w, https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-params-768x288.png 768w" sizes="(max-width: 770px) 100vw, 770px" /></figure>



<p><strong>Debugging the UI</strong></p>



<p>How did I spot the issue with the <strong>M</strong>? Once you&#8217;ve built your plugin js (npm run dev) you get a minified js file to deploy. Alongside this you will also get a sourcemap file:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="238" height="81" src="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-sourcemap.png" alt="" class="wp-image-970"/></figure>



<p>If you copy this to the same folder as your deployed plugin, you can then do some clever things in chrome:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="922" height="352" src="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-sourcemaps.png" alt="" class="wp-image-971" srcset="https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-sourcemaps.png 922w, https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-sourcemaps-300x115.png 300w, https://blog.boro2g.co.uk/wp-content/uploads/2018/10/ma-sourcemaps-768x293.png 768w" sizes="(max-width: 922px) 100vw, 922px" /></figure>



<p>In order for this to work you need to:</p>



<ul><li>Deploy the sourcemap file as per above</li><li>Add the folder where the original TS files live into chrome<ul><li>In the diagram above => Filesystem => Add folder to workspace </li></ul></li></ul>



<p>Happy debugging <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a rel="nofollow" href="https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation-ui/">Debugging Sitecore Marketing Automation UI</a> appeared first on <a rel="nofollow" href="https://blog.boro2g.co.uk">blog.boro2g .co.uk</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.boro2g.co.uk/debugging-sitecore-marketing-automation-ui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
