Sitecore Unicorn Exclude Fields


While you have a high functional developers team working on multiple Sitecore projects with same code base, it is very vital to keep the local development environment as stable and functional as possible and also keep PR short.

While achieving that stage, we came across one small issue which is intern made me to write a blog in my journal what you are reading now.

The Issue

While reviewing PRs, we observed, there is one Unicorn’s .yml file come as default to quite a few PRs. The change it has got was just few fields updated.

After quick initial investigation, found out that yml file is nothing but one of the Data Exchange Framework(DEF) batch processing item in Sitecore content tree under system node.

After bit more investigation, it turns out the sitecore’s schedule task is triggering that DEF batch process. But that raise another question, why that schduler task item is not coming as changed item list as it is also source controled using Unicorn.

The Resolution

Lets focus on the second question for now, as it has quite a quick and simple answer.

The \App_Config\Include\Unicorn\Unicorn.config has one section called <fieldFilter> which takes care of it. As few frequently value changing fields has already been excluded from being serialized (smart stuff Unicorn Developers).

That section is looking like below

<fieldFilter type="Rainbow.Filtering.ConfigurationFieldFilter, Rainbow" singleInstance="true">
					<exclude fieldID="{B1E16562-F3F9-4DDD-84CA-6E099950ECC0}" note="'Last run' field on Schedule template (used to register tasks)" />
					<exclude fieldID="{52807595-0F8F-4B20-8D2A-CB71D28C6103}" note="'__Owner' field on Standard Template" />
					<exclude fieldID="{8CDC337E-A112-42FB-BBB4-4143751E123F}" note="'__Revision' field on Standard Template" />
					<exclude fieldID="{D9CF14B1-FA16-4BA6-9288-E8A174D4D522}" note="'__Updated' field on Standard Template" />
					<exclude fieldID="{BADD9CF9-53E0-4D0C-BCC0-2D784C282F6A}" note="'__Updated by' field on Standard Template" />
					<exclude fieldID="{001DD393-96C5-490B-924A-B0F25CD9EFD8}" note="'__Lock' field on Standard Template" />
				</fieldFilter>

So now, for my initial issue to fix , I simply have to add a field I wanted to exclude form being serializedin to this fieldFilter section.

So, I created new patch configuration file (as best practice suggests) an try to patch my new exclude fields under the node <fieldFilter>. At first, I did add the config like following

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:environment="http://www.sitecore.net/xmlconfig/environment/">
	<sitecore role:require="Standalone or ContentManagement">
		<unicorn>
			<defaults>
				<!--
					The field filter can be used to ignore fields when comparing or serializing (i.e. don't write them to disk).
					Commonly, metadata fields such as Last Updated will be ignored to prevent SCM conflicts.
				-->
				<fieldFilter>
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{985BA535-0F3E-4DA8-A768-A469026DE9DB}" note="'RequestedAt' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{6A2B2CBB-4338-4814-A8A9-9FECBB90456A}" note="'LastRunFinished' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{2AA5C591-FF55-411D-96C0-978BB2C58B94}" note="'Log' field of DEF's Pipeline Batch item" />
				</fieldFilter>
			</defaults>
		</unicorn>
	</sitecore>
</configuration>

But this has weird patching when I see showconfig.appx. It actually replaces first three entries form the original xml…!!!???

I did ask God(google) and found that sitecore sometime does not patch correctly if proper attributes are not used. Someone suggest to use hint attribute to control the patching.

I did replace my patching config attribute note with the hint and eureka….!!!

This is the final configuration patch file looks like.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:environment="http://www.sitecore.net/xmlconfig/environment/">
	<sitecore role:require="Standalone or ContentManagement">
		<unicorn>
			<defaults>
				<!--
					The field filter can be used to ignore fields when comparing or serializing (i.e. don't write them to disk).
					Commonly, metadata fields such as Last Updated will be ignored to prevent SCM conflicts.
				-->
				<fieldFilter>
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{985BA535-0F3E-4DA8-A768-A469026DE9DB}" hint="'RequestedAt' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{6A2B2CBB-4338-4814-A8A9-9FECBB90456A}" hint="'LastRunFinished' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{2AA5C591-FF55-411D-96C0-978BB2C58B94}" hint="'Log' field of DEF's Pipeline Batch item" />
				</fieldFilter>
			</defaults>
		</unicorn>
	</sitecore>
</configuration>

After this, Unicorn re-serialized the DEF pipeline batch items and happy days….!!!!

Note:

There is new feature “fieldTransforms” available in Unicorn 4.1 and later version but I have not able to get that working on my project setup. But, something worth exploring for next time.

References

Sitecore SXA – Way of adding Custom Front End Assets


The Sitecore has change the website development with launch of the SXA with their first release and now they have make their vision very clear about how to quickly ship the website to market via this very powerful tool.

The Issue

While working on one of the SXA website build project, I came across one strange finding. Even if you selected Bootstrap 4 as your grid system for website. There are may out of the box bootstrap css classes are missing. This leads to some investigation ad found of the Sitecore SXA has ported just grid related styles(bootstrap-grid.css) to Sitecore SXA but not the full bootstrap main css(bootstrap.css)

Now, I have two concerns, first how can we add this the Sitecore SXA way without touching existing MVC layout or creating new layout? and Secondly, how can you only enable/import this to selective websites?

The Fix

After some googleing and reading few of Sitecore documents, found following steps will help get the answers to both above mentioned concerns.

  1. Create new base theme item of type /sitecore/templates/Foundation/Experience Accelerator/Theming/Base Theme under path /sitecore/media library/Base Themes (one can use insert options too). In my example I have given name bootstrap 411.
  2. Create a Styles folder item of type /sitecore/templates/Foundation/Experience Accelerator/Theming/Folders/Styles (one can use insert option) under the newly created base theme item above.
  3. Upload the css file to this styles folder using media upload feature. In my example I have uploaded bootstrap.css
  4. Navigate to the site specific theme item under media library. For example, /sitecore/media library/Themes/Tenant1/Website1
  5. In the Base Themes multi-select link field select the newly created base theme item in step 1 above
  6. Publish all newly created items in step 1 and 2
  7. Publish altered website specific theme item

Verification

New styles should work if the newly added stylesheet render on the page. To verify style link is render on website page or not we need to turn The Asset Optimizer off for the site (by default this is on and if it is already turned off you can skip these steps)

  1. In the Content Editor, navigate to sitecore/content/<Tenant>/<Website>/Presentation/Page Designs.
  1. In the Asset Optimization section, in the Styles Optimizing Enabled and Scripts Optimizing Enabled fields, to override styles and scripts optimization settings, select:
    • Default – to inherit global settings.
    • Yes – to always enable optimization for this site.
    • No – to always disable optimization for this site.

3. Publish the Page Design Item

4. Navigate to the web application in the browser and open the page view source and look for the newly created item path in the head section. In my example, looking for bootstrap-411(don’t mind the hyphen as it is due to link manager options settings)

<link href="/-/media/base-themes/bootstrap-411/styles/bootstrap.css" rel="stylesheet" />

Further to verify, also check other website within the same CMS and check the page source view for absence of newly added stylesheet.

In above example, we have added Style Sheet asset but this same can be done for Scripts assets as well

Happy Sitecore SXA website development…!!!

References

Sitecore Docker – Run CM sites on HTTPS


While working on the integrating Sitecore’s CM’s functionality with third party Digital Asset Management(DAM) system, I came across one interesting issue where I wanted my container applications to run on https.

The Issue

After integrating the third party DAM with Sitecore CMS, it found out that, while using local website on developer machine, the developer is not able to load the SSO login page. While loading that page below error messages logged in browser’s console.

Access to the WebCrypto API is restricted to secure origins. Compact View requires HTTPS when used outside localhost (for development).

As clearly stated I am not using localhost as host to access my cm and seems like CM needs to be securely severed over https where as we, for local development, use non secure protocol http.

The Fix

The solution is simple looking form 35,000 feet. Needs CM urls to be serving content over the secure HTTPS protocol. But when actually started digging in details, it is fun and very learning experience.

Performed following steps to achieve this on our local docker development environment.

  1. Clone or download below repository

https://github.com/michaellwest/docker-https

  1. Open the startup/createcert.ps1 for editing and change following parameter’s default value
  • $certificatepassword – from b to more secured passowrd string
  • $dnsNameList – by default the value is *.dev.local. Change this value to match your host pattern. You can specify individual host comma(,) separated.

Note

Alternatively, you can can pass those two as parameter while firing createcert.ps1 command.

3. Open docker-compose.yml file and navigate to cm service and perform following changes:

  • Add new environment parameter HOST_HEADER and set cm host value to it. If you have multiple host(this is what in my case), specify them semicolon(;) separated list. For example host1.dev.local;host2.dev.local
  • Under the volumes bind the new volume for folder startup to c:\startup path of container.
  • Under the port bind the https’s default secure port 443 with the next available container port

Note

The container host port needs to be new port which is not been use by any other services.
  • Lastly, change the entypoint to the path of startup.ps1 file under the startup folder bound under the volumes in above step for startup folder.

After all above changes to CM service of docker-compose.yml file will look something like below

services:
  ...
  cm:
    image: ${REGISTRY}sitecore-xm-cm:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    entrypoint: powershell.exe -NoLogo -NoProfile -File C:\\startup\\startup.ps1
    volumes:
      - .\src:C:\src
      - .\startup:C:\startup
    ports:
      - "44001:80"
      - "44002:443"
    networks:
      default:
        aliases:
          - cm.dev.local
          ...
    environment:
      HOST_HEADER: cm.dev.local
      ...

4. Copy folder startup and it’s content to same folder where your docker-compose.yml file is.

5. Open the powershell in elevated mode and execute following command

PS> cd <<docker-compose.yml file's folder path>>
PS> ./startup/createcert.ps1

Above powershell script will generate three files cert.cer, cert.pfx and cert.password.text under the startup folder.

This command will also generate the self-signed wildcard certificate and install to your system’s local certificate store under personal.

To verify that run mmc and open local computer certificate store.

Self signed wildcard certificate for *.dev.local

6. Now, is the time to fire up the container for sitecore. To do so run following docker compose command

PS> docker-compose up -d

After successful execution the container services will be up and one can access the host binding with https. For example https://cm.dev.local in this case.

Advance trouble shooting

  1. To check the certificate is exist after the createcert.ps1 script execution. This command can be run on both your local and against cm container as well.
PS> Get-ChildItem -Path cert:\LocalMachine\Root


PS> Get-ChildItem -Path cert:\CurrentUser\Root

  1. To verify the binding under the container’s IIS for the specified hosts use following commands
PS> Get-Website -Name 'Default Web Site'
  1. To get all the bindins and their port details for a website
PS> Get-WebBinding -Name 'Default Web Site'

References

Sitecore Powershell Reports – Export Functionality not working


The QA team, we are working with has raised a very interesting issue while testing newly created data report using Sitecore Poershell Extenstion(SPE).

The Issue

The data report was executing perfectly but while trying to export the data in any of pre-defined formats offered by SPE, it was not working.

The Sitecore Powershell is allowing export of report data in various industrial standard formats out of the box as listed below:

  • CSV
  • HTML
  • XML
  • Excel
  • JSON

These formats have option links in the ribbon above but when clicking, none of those producing any output.

¯\_(ツ)_/¯

The Investigation

First step is to try to reproduce the issue. We tried on all the available environments and it is happening on every environment except for the local environment.

I though the issue may have to do with some missing config or SPE. So, we quickly try to re-install the SPE module on CM with no over-write option for both files and content on Integration Environment. But that does not fix the issue. ☹

So, we started listing what are the major difference from modules and features point of view between local development and other environments on Azure. It turns out that all other environments have exactly the same piece of code, configurations and modules installed except for Federated Authentication using Sitecore Identity Server for CM.

The Fix

We did quick search over the internet and one of my colleague found out that there is one file which is disabled for SPE which needs to be enable if we are using sitecore 9.1 and higher(we are running 9.3) along with identity server.

The file needs to be enabled is Spe.IdentityServer.config file which is part of the SPE package.

Once package is installed, the file is located at path <<website Root>>\App_Config\Include\Spe\Spe.IdentityServer.config.disabled. The content of this disabled file is as below.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:security="http://www.sitecore.net/xmlconfig/security/">
  <sitecore role:require="Standalone or ContentManagement" security:require="Sitecore">
    <pipelines>
      <owin.cookieAuthentication.validateIdentity>
        <processor type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.ValidateSiteNeutralPaths, Sitecore.Owin.Authentication">
          <siteNeutralPaths hint="list">
            <!-- This entry corrects the infinite loop of ExecuteCommand in the SPE Console -->
            <path hint="spe">/sitecore%20modules/PowerShell</path>
          </siteNeutralPaths>
        </processor>
      </owin.cookieAuthentication.validateIdentity>
    </pipelines>
  </sitecore>
</configuration>

Tip: The best way to get these config enable in Docker container world, is to leave the above mentioned .disabled file as is. Create new configuration file with above content in Visual Studio solution deploying to z folder under app_config\include on your binding volume path which will be taken care by Sitecore config patching.

Enjoy exporting SPE reports data…!!!

References

https://github.com/SitecorePowerShell/Console/releases
https://doc.sitecorepowershell.com/troubleshooting

Sitecore Docker -Coveo Diagnosis Page Search Rest Endpoint Issue


While configuring Coveo search on my local development environment using Docker, something got my attention on Coveo’s diagnosis page(<<Sitecore CM Host>>/sitecore modules/Web/Coveo/Admin/CoveoDiagnosticPage.aspx).

This page has all the green ticks except for the one. This is Coveo Search REST Endpoint. See image below for more details.

Coveo Diagnostic Page REST API Error
Coveo Diagnostic Page REST API Error on Docker

As usually, I copied the API end point URL and hit in the Browser and it serve the request with no error. It is HTTP-200 response with valid JSON result.

The error in the log file also not giving any lead either.

Coveo.SearchProvider.Applications.BaseVerifier.VerifyComponent(:0) ERROR StateVerifier has encountered an error while verifying the component "Coveo Search REST Endpoint".<br>Exception: Coveo.SearchProvider.Applications.StateVerifierException<br>Message: Failed to obtain resource located at 'http://sicore930.dev.local/coveo/rest/'. See inner exception for details.<br>Source: Coveo.SearchProvider.Applications<br>at Coveo.SearchProvider.Applications.CommonStateVerifier.TryPingRestEndpoint(String p_Endpoint)<br>at Coveo.SearchProvider.Applications.CommonStateVerifier.<>c__DisplayClass11_0.b__0()<br>at Coveo.SearchProvider.Applications.BaseVerifier.VerifyComponent(Func`1 p_VerifyMethod, String p_ComponentName)

I opened docker powershell command for the cm container and tried to request the host from within container.

PS> Docker container ls

Grab the name or container id

PS> Docker exec -it <<container name/id>> powershell

This will open a powershell window connected to the container specified.

PS> Invoke-RestMethod -Uri "http://sitecore930.dev.local/coveo/rest" | ConvertTo-Json

It has given me following error

Now things are little clear to me. The Coveo diagnosis page is using current host to make REST API request from IIS server running on the container. The container does not have host file entry to reseolve the host url.

So now, I started searching how to make entry in container’s host file??? I was sure, I am not the first person who wanted this kind of stuff.

Following command has does the trick. but for that we need to first fire up the command prompt of the cm container.



PS> Docker exec -it <<container name/id>> powershell

Once the CM’s command prompt is ready execute below command to add the host file entry.



C:> echo 127.0.0.1 sitecore930.dev.local >> "C:\Windows\System32\drivers\etc\hosts"

After executing above command on Container’s command prompt, now my Coveo Diagnosis page is Happy…!!!

Please do let me know, is there any better solution you guys have in place for this issue.

Till that time happy Coveo searching…!!!

Additional powershell command to check the content of the file:



PS> Get-Content -Path <<fully qualified file path>>

Sitecore Docker – SQL Databse connection issue


Psssss… This is more as a note to myself..!!!

While setting my local environment for development on Sitecore 9.3 using docker, I came across below issue.

Docker - The network path was not found
Docker SQL Connection Issue
[Win32Exception (0x80004005): The network path was not found]

[SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)]
   System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection) +1341
   System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) +159
   System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) +382
   System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) +307
   System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry) +198
   System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) +422
   System.Data.SqlClient.SqlConnection.Open() +199
   Sitecore.Data.DataProviders.Sql.DataProviderCommand..ctor(IDbCommand command, DataProviderTransaction transaction, Boolean openConnection) +113
   Sitecore.Data.DataProviders.Sql.<>c__DisplayClass26_0.<CreateCommand>b__0() +48
   Sitecore.Data.DataProviders.NullRetryer.Execute(Func`1 action, Action recover) +293
   Sitecore.Data.DataProviders.Sql.<>c__DisplayClass29_0.<CreateReader>b__0() +30
   Sitecore.Data.DataProviders.NullRetryer.Execute(Func`1 action, Action recover) +293
   Sitecore.Data.DataProviders.Sql.SqlDataApi.CreateReader(String sql, Object[] parameters) +281
   Sitecore.Data.DataProviders.Sql.SqlDataProvider.GetContentLanguages() +169
   Sitecore.Data.DataProviders.Sql.SqlDataProvider.LoadLanguages() +133
   Sitecore.Data.DataProviders.Sql.SqlDataProvider.GetLanguages() +49
   Sitecore.Data.SqlServer.SqlServerDataProvider.ExecutePreLoadItemDefinitionSql(String sql, Object[] parameters, SafeDictionary`2 prefetchData) +52
   Sitecore.Data.DataProviders.Retryer.ExecuteNoResult(Action action, Action recover) +539
   Sitecore.Data.SqlServer.SqlServerDataProvider.LoadInitialItemDefinitions(String condition, Object[] parameters, SafeDictionary`2 prefetchData) +237
   Sitecore.Data.DataProviders.Sql.SqlDataProvider.EnsureInitialPrefetch() +333
   Sitecore.Data.DataProviders.Sql.SqlDataProvider.GetPrefetchData(ID itemId) +62
   Unicorn.Data.DataProvider.UnicornSqlServerDataProvider.GetItemDefinition(ID itemId, CallContext context) +242
   Sitecore.Data.DataProviders.DataProvider.GetItemDefinition(ID itemID, CallContext context, DataProviderCollection providers) +156
   Sitecore.Data.DataSource.GetItemInformation(ID itemID) +88
   Sitecore.Data.DataSource.GetItemData(ID itemID, Language language, Version version) +32
   Sitecore.Data.Engines.TemplateEngine.GetdefaultSectionOrder() +118
   Sitecore.Data.Engines.TemplateEngine.InternalGetTemplates() +486
   Sitecore.Data.Engines.TemplateEngine.GetTemplate(ID templateId) +184
   Sitecore.XA.Foundation.SitecoreExtensions.Extensions.DatabaseExtensions.GetContentItemsOfTemplate(Database database, ID templateId) +126
   Sitecore.XA.Foundation.Multisite.SiteResolvers.EnvironmentSitesResolver.ResolveAllSites(Database database) +63
   Sitecore.XA.Foundation.Multisite.Providers.SxaSiteProvider.GetSiteList() +162
   Sitecore.XA.Foundation.Multisite.Providers.SxaSiteProvider.InitializeSites() +105
   Sitecore.XA.Foundation.Multisite.Providers.SxaSiteProvider.GetSites() +18
   System.Linq.<SelectManyIterator>d__17`2.MoveNext() +265
   Sitecore.Sites.SiteCollection.AddRange(IEnumerable`1 sites) +221
   Sitecore.Sites.SitecoreSiteProvider.GetSites() +258
   Sitecore.Sites.DefaultSiteContextFactory.GetSites() +253
   Sitecore.XA.Foundation.Multisite.SiteInfoResolver.get_Sites() +60
   Sitecore.XA.Foundation.Multisite.Pipelines.Initialize.InitSiteManager.Process(PipelineArgs args) +85
   (Object , Object ) +9
   Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args) +490
   Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists) +236
   Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain) +22
   Sitecore.Nexus.Web.HttpModule.Application_Start() +220
   Sitecore.Nexus.Web.HttpModule.Init(HttpApplication app) +1165
   System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +584
   System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +168
   System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +277
   System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +369

[HttpException (0x80004005): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +532
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +111
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +724

The error speaks itself, that the CM and/or CD was not able to connect to underlying SQL server. SO, I immediately opens the SSMS and try to connect to my SQL server running as container on my local and I am successfully able to connect both using IP address as well as using alias(in my case it’s sql).

So what’s the issue??? When I am able to connect to SQL server running in container using outside of the Docker created network than why my CM and/or CD instance is not able to connect to it within the same network???

I check inward and outward binding ports setting in docker-compose.yml file for SQL service. Double check connection strings for server name, user name and password and that all looks correct.

Thanks to one of my colleague, who points out my docker-compose file was missing hostname for SQL server service.

I have added them to my docker-compose.yml for SQL, SOLR and XCONNECT and happy days.

The sample docker-compose.yml is as below.

version: '2.4'

networks:
  dev.local:

services:

  sql:
    hostname: sql
    image: ${REGISTRY}sitecore-xp-sxa-coveo-def-sqldev:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    networks:
      dev.local:   
    volumes:
      - .\data\sql:C:\Data
    mem_limit: 2GB
   
    ports:
      - "44010:1433"
    environment:
      SA_PASSWORD: ${SQL_SA_PASSWORD}
      ACCEPT_EULA: "Y"

  solr:
    hostname: solr
    image: ${REGISTRY}sitecore-xp-sxa-solr:${SITECORE_VERSION}-nanoserver-${NANOSERVER_VERSION}
    networks:
      dev.local:
    volumes:
      - .\data\solr:C:\Data
    mem_limit: 1GB
    networks:
      dev.local:
    ports:
      - "44011:8983"

  xconnect:
    hostname: xconnect
    image: ${REGISTRY}sitecore-xp-xconnect:${SITECORE_VERSION}-windowsservercore-${WINDOWSSERVERCORE_VERSION}
    volumes:
      - .\data\xconnect\logs:C:\inetpub\wwwroot\App_Data\logs
      - .\data\xconnect-appdata\models:C:\inetpub\wwwroot\App_Data\Models
    networks:
      dev.local:
    ports:
        - "44012:80"
    mem_limit: 1GB
    environment:
      SITECORE_LICENSE: ${SITECORE_LICENSE}
      SITECORE_SITECORE:XCONNECT:COLLECTIONSEARCH:SERVICES:SOLR.SOLRREADERSETTINGS:OPTIONS:REQUIREHTTPS: 'false'
      SITECORE_SITECORE:XCONNECT:SEARCHINDEXER:SERVICES:SOLR.SOLRWRITERSETTINGS:OPTIONS:REQUIREHTTPS: 'false'
      SITECORE_CONNECTIONSTRINGS_MESSAGING: Data Source=sql;Database=Sitecore.Messaging;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_PROCESSING.ENGINE.STORAGE: Data Source=sql;Database=Sitecore.ProcessingEngineStorage;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_REPORTING: Data Source=sql;Database=Sitecore.Reporting;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_XDB.MARKETINGAUTOMATION: Data Source=sql;Database=Sitecore.MarketingAutomation;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_XDB.PROCESSING.POOLS: Data Source=sql;Database=Sitecore.Processing.Pools;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_XDB.REFERENCEDATA: Data Source=sql;Database=Sitecore.ReferenceData;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_COLLECTION: Data Source=sql;Database=Sitecore.Xdb.Collection.ShardMapManager;User ID=sa;Password=${SQL_SA_PASSWORD}
      SITECORE_CONNECTIONSTRINGS_SOLRCORE: http://solr:8983/solr/sitecore_xdb
    depends_on:
      - sql
      - solr

DEF – Pipeline batch ribbon button issue


This is going to be a short blog for fixing issue I came across while working on custom pipeline creation and execution for Sitecore’s Data Exchange Framework(DEF or DxF).

The issue

While the Pipeline Batch item is selected, buttons on DATA EXCHANGE toolbar at top does not behave how they should.

Immediately after selecting pipeline item, I noticed all buttons in ribbon is visible and clickable. Secondly, clicking on Run Pipeline Batch Button does not works. I was neither starting execution of pipeline nor displaying any visible error messages. See below image for more details:

The fix

I started investigation and collecting events what could have done the damage. Found that before last deployment it was behaving the way it should be. Huuummm… that’s good hint, isn’t it? The last release just deployed files to CMS server. This is soothing to my ears as investment scope is drastically reduced to files. The content automatically gone out of equation.

To fix this, I tried install DEF SDK package first with just deploying file artifacts and skipping any content installation.

Unfortunately, that does not work ….!!! 😦

Next best bet is obvious and try to re-install the DEF framework package with deploying files only.

And that does the trick ….!!!! (Dance)

Update:

The file \App_Config\Sitecore\DataExchange\Sitecore.DataExchange.Local.config was missing. Placing this file from Package has actually fixed the issue.

Happy Data Sync and import using Sitecore Data Exchange Framework. 🙂

Sitecore Publishing Service – Part 3 – Advance Configurations


So far in Part – 1 and Part – 2 of this series, the Sitecore Publishing Service up & running in Azure PaaS and the Sitecore Publishing module is installed & configured.

This last part will trying to address few additional scenarios with publishing service. Scenarios like, the Sitecore databases are hosted in Azure SQL and Sitecore implementation have multiple publishing targets.

Sitecore database in Azure(Azure SQL)

If publishing service hosted on Azure web app and the databases are also in Azure SQL Database, there are few additional configurations needed for the service to work seamlessly with bigger publishing payload.

Follow below steps to configure publishing service for Azure Environment

  • Navigate to \configurations\system.webServer\aspNetCore node in wwwRoot\web.config file of publishing service in app service.
  • replace the arguments attribute with the following
arguments=" --environment azure"
  • Save the web.config
  • Stop and start app service

By default Sitecore publishing service is running under the “production” environment and that patches the configurations for production. After above change, service will start with Azure environment and it will patch azure environment specific configurations.

  • Navigate to wwwroot/config/azure
  • rename file sc.publishing.sqlazure.connections.xml.example to sc.publishing.sqlazure.connections.xml. Remove .example extension and make sure it has .xml extension.

New publishing target…!!!???

If other than default Internet publishing target is being used in CMS, there are few additional configurations needs to be made. So lets have a look at those.

I am assuming the additional publishing target also linked to additional database other than default web database. If so, the new connection string also needs to be added to publishing service.

New connection string

In this scenario, will take example of new web database in Azure SQL US region and need to add new target to publish content to web database to this US region.

  • Add new connection string to Publishing service. lets name it web_us
Sitecore.Framework.Publishing.Host configuration setconnectionstring web_us "<US web database connection string>"

/config/sitecore/publishing/sc.publishing.xml

Open above file and follow below steps:

  • navigate to Settings\Sitecore\Publishing\Services\DefaultConnectionFactory\Options\Connections
  • Search for the child node Internet, duplicate the whole node along with children. For example, name it InternetUS
  • Within that InternetUS node navigate to child node ConnectionString and change the value of the node to following to match the name of the connection sting in steps above.
${Sitecore:Publishing:ConnectionStrings:web_us}
  • Navigate to Settings\Sitecore\Publishing\Services\StoreFactory\Options\Stores\Targets
  • Search for the child node Internet, duplicate the whole node along with children. For example, name it InternetUS
  • Change the value of the ConnectionName to InternetUs. This must match the name of the name of the new node name under Settings\Sitecore\Publishing\Services\DefaultConnectionFactory\Options\Connections. Created in one of the step above.
  • Set the id of new Publishing Target item in Sitecore CMS. For example,
<Id>46FDC9AF-3F00-4D55-BDB8-86ED13F82E00</Id>
  • Set the value of child node ScDatabase to newly added databsae name. In our example it would be web_us.
  • Save the file

wwwroot/config/azure/sc.publishing.sqlazure.connections.xml

Note

This step is optional if the service is not using databases on Azure SQL.
  • Navigate to Settings\Sitecore\Publishing\Services\DefaultConnectionFactory\options\Connections\
  • Search for Internet node in child nodes and duplicate that node with name InternetUS along with child nodes
  • Save File

Bonus

Log level changing for debugging

Nothing can beat detailed level logging while debugging application/service. Default publishing service have two filters one sitecore and anther is default.

For sitecore filter the default log level is set to Information and default log level is set to Warning. See below xml for the same.

<Filters>
    <Sitecore>Information</Sitecore>
    <Default>Warning</Default>
</Filters>

One can select log filter level to one of the following:

  • Trace : The most detailed log messages, may contain sensitive application data. These messages are disabled by default and should never be enabled in a production environment.
  • Debug : Logs that are used for interactive investigation during development should use the Debug level. These logs should primarily contain information useful for debugging and have no long-term value.
  • Information : Track the general flow of the application using logs at the Information level. These logs should have value in the long term.
  • Warning : Warnings should highlight an abnormal or unexpected event in the application flow. This event does not cause the application execution to stop, but can signify sub-optimal performance or a potential problem for the future.
  • Error : An error should be logged when the current flow of execution is stopped due to a failure. These should indicate a failure in the current activity, not an application-wide failure. These will mainly be unhandled exceptions and recoverable failures.
  • Critical : A critical log should describe an unrecoverable application or system crash, or a catastrophic failure that requires immediate attention.

To overwrite these default log level filters, use wwwroot/config/sitecore/sc.logging.xml file.

Note

The Development environment mode sets the Sitecore log level filter to Debug. So the service can be run under Development Environment for more detailed logging.

After all these configuration changes restart the publishing service.

Have a happy performing Sitecore publishing…!!!!

Sitecore Publishing Service – Part 1 – Install and Configure Service in Azure PaaS


While working on finding solution for slow publishing issue of more than 10,000 items in Azure PaaS, I came across this very powerful add-on Sitecore Publishing Services.

Believe it or not but once it is installed, configured and up, it reduced the publishing time drastically. In our case, publishing of those 10,000 items were taking around 1 hour 30 mins(hhhuuuffff…), merely took 12 mins to publish.(Super duper awesome, isn’t it…??? This makes everyone’s life easy)

Thus, I decided to write blog on whole solution. Blog will become very lengthy if I put everything in one. Thus, splitting it in three parts.

Part 1 will cover installation and basic configuration of publishing service. Part 2 will cover installation of publishing module in CMS. The third part will cover advance configuration of publishing service.

So, lets get started…

Download

You can download both Sitecore publishing service and publishing module from Sitecore’s development site here. It is the designed and developed by Sitecore itself.

Note:

Just check the version compatibility with Sitecore version where you wanted to implement this publishing service/module. see image below for more details. (As I have downloaded first the latest and greatest version 4 at the time I am writing this blog for Sitecore 9.0.1 and later figure out it is not compatible.)

Install publishing service on Azure PaaS

With my current client all their Sitecore implementation is in Azure PaaS. It absolutely makes sense to have this Sitecore Publishing service also setting in Azure PaaS. So, follow below steps to get the publishing services up as app service.

  • Download the service application as zip file from above link. Select the one which is matching your host architecture type either 32 bit or 64 bit.
  • Open Kudu – Advance tool for the web app where you want to host publishing service
  • in Kudu editor open command console by navigate to Debug Console menu option and select CMD
  • navigate to site root folder using following command
cd site\wwwroot
  • Drag and drop service zip file to folder view area above console. This will upload the service package to Azure web app.
  • Once upload completed, run following command on console below the folder view
unzip -o *.zip

Assumption

The site’s wwwroot folder has only one zip file which is recently uploaded publishing service zip file.
  • Once unzipping of application completed, execute following commands in CMD. This will set connection stings of core, master and web database in publishing service. Going forward, these connection strings will be used for all publishing jobs.
Sitecore.Framework.Publishing.Host configuration setconnectionstring core "<core database connection string>"
Sitecore.Framework.Publishing.Host configuration setconnectionstring master "<master database connection string>"
Sitecore.Framework.Publishing.Host configuration setconnectionstring web "<web database connection string>"
  • Once connection strings are configured for these databases the next step is to upgrade the database schema to required one for Sitecore publishing service
Sitecore.Framework.Publishing.Host schema upgrade --force

After executing above command the console displays the result of the command. The below screenshot have result with already updates schema for all the databases as I have previously upgraded the schema.

Once above commands are successfully executed, now it is the time to check the status of the publishing service web application.

In the browser open below URL

http://<<azure app service name>>.azurewebsites.net/api/publishing/maintenance/status

Above web api will return following JSON result if all the configurations are correctly set.

{
    "status": 0
}

This are basic steps to deploy Sitecore Publishing services up and running in azure PaaS. In the Part – 2, will cover installation of Sitecore Publishing Module in Sitecore CM/CA with configuration.

Content sync with RAZL script


Hi Sitecore Enthusiastic,

Recently come across very great strategy to sync content between two instances of Sitecore using a very powerful tool called Razl form Hedgehog.

Please read more about Razl here.

I have used this tool before mainly to compare the content between two different databases. For example production CM and Pre-production CM. Today, I came across very new and great features with latest version of Razl offering call tasks and executing task using Razl scripts.

It is offering content sync tasks to be exported in a file(or call script) as xml format and later one can use that to sync data in different environment using Razal script.

For more information about Razl task, read official document here.

The great part of this task is you can cherry pick what you want to sync out of the whole Sitecore content tree. You can go deep up to the field level with your sync task.

once you have a list of tasks ready, you simple can export that as script and execute it with command or create scheduler task to run that script using command and it will do the sync between source and target connections.

Razl.exe /script:Migrate.xml
Razl.exe /script:"c:\Site Migration\Razl.xml"

Even if you want to go one level further you can automate this sync task post publishing(perhaps not ideal, if frequent publishing is happening) or you can hook it post deploy task in you CD script(if your build contains TDS/unicorn content items).

You must be wondering this is great tool and great way to sync, but what if I am trying to sync big chunk of content items!!!???.
You can use another great feature of Razl called Lightening Mode(obviously you can configure this in you script as well). This mode really boost the performance of sync script if your CoplyAll task is configured to do bulk copying of items.

As far as logging concern, Razl Script mode will output actions as they happen to the command prompt, this output can be written to a text file if required using following command sample.

Razl.exe /script:"c:\Site Migration\Razl.xml" >> c:\logs\RazlScriptLogs.txt

Tip: Single arrow > will create the file if missing and if exist, overwrite the content of file.
Double  arrow >> will create the file if missing and if exist, it will append to the file.

If a log folder has been already configured in the Razl GUI than Script mode will also write to the log file under configured log folder.

Thanks for reading.

Happy Content Sync…!!!

Reference
Script – https://hedgehogdevelopment.github.io/razl/script.html
Connections – https://hedgehogdevelopment.github.io/razl/connections.html
Lightning mode – https://hedgehogdevelopment.github.io/razl/comparing.html#lightning-mode