Friday 22 January 2021

Fortis - Unable to find template error

I was upgrading my client's Sitecore instance lately and at some point I've spotted this issue with Fortis:

Fortis | Unable to find template for MyProject.Model.IMyTemplate

After doing some digging in the internet I couldn't find out what was causing it. I decided to compare all config files and I've spotted that my Web.config on new environment is missing these bits:

Declaration of Fortis section in  <configSections>

<configSections>
...
    <section name="fortis" type="System.Configuration.NameValueSectionHandler" />
...
</configSections>

...and the actual section my Model project assembly reference:

<fortis>
    <add key="assembly" value="MyProject.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</fortis>


With these added it all worked. I hope this will help somebody!

Monday 30 November 2020

HelixCheck - update v 1.0.1

I've just released a quick update to my GitHub Action - HelixCheck.

New release includes additional input parameter named excluded-projects which can be used to exclude projects that we don't want to be analysed. Example setup:

name: Helix Check

on:
  push:
    branches: [ develop, master ]
  pull_request:
    branches: [ develop, master ]

jobs:
  check_job:
    name: Helix check
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Helix Check
        uses: ethisysltd/helix-check@v1.0.1
        id: check
        with:
          solution-file: 'Helixbase.sln'
          project-name: 'Helixbase'
          website-folder: 'website'
          excluded-projects: 'Helixbase.Foundation.NotFollowingHelix,Helixbase.Feature.RatherNotFollowingHelix'
      
      - name: Get the check result
        run: echo "Check result - ${{ steps.check.outputs.result }}"
      
      - name: Get the output time
        run: echo "The time was - ${{ steps.check.outputs.time }}"

Value of that parameter should be a string with comma-delimited names of projects. I couldn't use YAML's multiline collections syntax here because of GitHub Actions limitations.

Ideally this parameter shouldn't be used, as Helix project setup should be clean, but I've got some requests to add this. And, as usual, in real world solutions there can be legacy projects which might be a work in progress of refactoring, so there it goes!

If used, there will be additional warning added to the output, which won't affect the result outcome but will add more visibility of the setup gotchas:

This action can be found in GitHub marketplace here: https://github.com/marketplace/actions/helix-check

Code repo is available here: https://github.com/ethisysltd/helix-check


Thursday 23 July 2020

HelixCheck - GitHub action

Recently I've prepared a GitHub action that checks solution structure to see if it is Helix compliant and follow guidelines of folders structure.

It is available on GitHub marketplace and ready to be used with Sitecore projects following Helix principles - https://github.com/marketplace/actions/helix-check.


If you're not familiar with GitHub actions you can read more about it here https://github.com/features/actions or in technical documentation - https://docs.github.com/en/actions.

General rules

Action tries to reflect Helix rules from documentation - https://helix.sitecore.net/

Projects references:
  • Feature layer projects can only reference Foundation
  • Foundation layer projects can only reference other Foundations
  • Project layer projects can reference Feature and Foundation but not other Projects
Folders structure and naming convention:
  • There are layer folders specified in the solution
    • Feature
    • Foundation
    • Project
  • Projects are placed in correct folders, for example:
    • src\Feature\ORM\website\Helixbase.Foundation.ORM.csproj - incorrect
    • src\Foundation\ORM\website\Helixbase.Foundation.ORM.csproj - correct

    Configuration

    Example workflow:

    name: Helix Check
    
    on:
      push:
        branches: [ develop, master ]
      pull_request:
        branches: [ develop, master ]
    
    jobs:
      check_job:
        name: Helix check
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout
            uses: actions/checkout@v2
    
          - name: Helix Check
            uses: ethisysltd/helix-check@v1.0
            id: check
            with:
              solution-file: 'Helixbase.sln'
              project-name: 'Helixbase'
              website-folder: 'website'
          
          - name: Get the check result
            run: echo "Check result - ${{ steps.check.outputs.result }}"
          
          - name: Get the output time
            run: echo "The time was - ${{ steps.check.outputs.time }}"

    It should be placed inside folder .github\workflows\ and named something like helix-check.yml

    Action is configured by these inputs:

    Input Description Usage
    solution-file Path to the solution that will be analyzed. Required
    project-name The name of your project. Required
    website-folder The name of the folder that always contain website project file.
    Default "website", earlier "code" was used.
    Optional

    While using the action makes sure you've checked the readme.md inside repo, as it will always be most up to date - https://github.com/ethisysltd/helix-check.

    In the action repository I've put example Helix solutions for tests - Helixbase by Neil Shack.
    If there are no issues found, simple log message is shown.

    Solution file: example-solution/valid/Helixbase.sln
    Project name: Helixbase
    Solution file exists.
    
    Solution is Helix compliant.


    I've managed to add a copy of that one and mess it up really badly so you can see result of analysis:

    Solution file: example-solution/invalid/Helixbase-Invalid.sln
    Project name: Helixbase
    Solution file exists.
    
    ##[warning]Issues with project Helixbase.Foundation.ORM
     Folder incorrect: src\Feature\ORM\code\Helixbase.Foundation.ORM.csproj
    
    ##[warning]Issues with project Helixbase.Feature.Hero
     Folder incorrect: src\Foundation\Hero\code\Helixbase.Feature.Hero.csproj
    
    ##[warning]Issues with project Helixbase.Project.Helixbase
     Incorrect references:
      - Helixbase.Project.Common
    
    ##[warning]Issues with project Helixbase.Feature.VersionTrim
     Incorrect references:
      - Helixbase.Project.Common
      - Helixbase.Feature.ShowTitles
    
    ##[warning]Issues with project Helixbase.Foundation.Core
     Incorrect references:
      - Helixbase.Feature.Redirects
      - Helixbase.Project.Common

    ##[error]Solution is not Helix compliant.

    Action is released to the Marketplace under https://github.com/marketplace/actions/helix-check. I will be adding additional checks soon, feel free to give me a shout if you find any issues or bugs.

    Cheers!

    Monday 25 November 2019

    Azure Search - Improving speed while getting facets only

    If you want to get only facets from your search query - for some purposes as preparing filters list - remember to set limit to 0.

    For example like this:

    var facetResults = searchQuery.Take(0).GetFacets();

    .Take(0) translates to $top=0 in Azure Search query. That will return something like this:

    {
        "@odata.context": "https://{YOUR-SEARCH-SERVICE}.search.windows.net/indexes('my-index-web-index-99')/$metadata#docs(*)",
        "@odata.count": 857,
        "@search.facets": {
            "contenttype_facet_1": [
                {
                    "count": 146,
                    "value": "Content Type 1"
                },
                {
                    "count": 134,
                    "value": "Content Type 2"
                },
                {
                    "count": 118,
                    "value": "Content Type 3"
                },
            ],
            "topic_facet_1": [
                {
                    "count": 176,
                    "value": "Topic 1"
                },
                {
                    "count": 70,
                    "value": "Topic 2"
                },
                {
                    "count": 62,
                    "value": "Topic 3"
                },
                {
                    "count": 52,
                    "value": "Topic 4"
                }
            ],
            "subtopic_facet_1": [
                {
                    "count": 49,
                    "value": "Subtopic 1"
                },
                {
                    "count": 32,
                    "value": "Subtopic 2"
                }
            ]
        },
        "value": []
    }
    

    So only essential statistics data without actual results

    Friday 1 November 2019

    RenderField processor for tooltip links

    A couple of days ago I've got a requirement from my client about inline tooltips functionality. Those tooltips needed to have formatted text so RTE field should be used.


    I started with creating repository folder for those tooltips




    Template for tooltip item was really simple, just one RTE field



    To have a link which will open a tooltip I had to write a pipeline processor which
    • Will read RTE field content
    • Find internal links
    • Check if they point to tooltip item
      • If yes then process link



    This pipeline processor must be run after field value is read, so after
    Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel

    Sunday 20 October 2019

    Helix Publishing Pipeline - file locks issue on deploy

    On my last project when I was implementing Helix Publishing Pipeline I found really bizarre issue. Almost every time I was deploying code by publishing it from Visual Studio, some dlls were locked by w3wp process.

    No surprise IIS uses those assemblies but I didn't have such locking problem earlier.

    I was digging for hours in the Internet and I found out that IIS uses assembly shadowing. So basically it doesn't use directly dlls from webroot bin, but from its the temp folder.

    It can be disabled by this setting

    <hostingEnvironment shadowCopyBinAssemblies="false" />

    When I set this for test, file locks were all over the place.

    Earlier I used Process Explorer and I saw that w3wp locks not only shadowed dlls but as well those from webroot bin, so something was not right there!



    More digging eventually gave me information that our issue was self-inflicted: https://stackoverflow.com/a/28019475

    In GlassMapperScCustom assemblies were loaded by invoking method
    Assembly.LoadFile(assemblyPath) 

    which loads exact assemblies and it doesn't take into account shadows.

    Instead of that we should always use

    Assembly.LoadFrom(assemblyPath) 

    which loads shadows as it should be.

    That fixed issue with file locks for good!

    Tuesday 19 February 2019

    Azure Search provider - Results ordering issue

    I was implementing Azure Search lately into my last project and I found some strange issue in the provider (we're using Sitecore 9.0.2 rev. 180604). When I wanted to order my search results using Linq like this:

    searchQuery.OrderBy(x => x.JobRole).ThenBy(x => x.LastName)

    it was translated to:

    $orderby=last_name_s,job_role_i

    So it looks like it's taking argument of ThenBy as first and OrderBy as the second. Inverting parameters:

    searchQuery.OrderBy(x => x.LastName).ThenBy(x => x.JobRole)

    gave me desired query:

    $orderby=job_role_i,last_name_s

    And search result as well were sorted like I wanted.

    Azure Search documentation states nothing unusual, but I had to confirm this:


    $orderby=[string] (optional)

    A list of comma-separated expressions to sort the results by. When calling via POST, this parameter is named orderby instead of $orderby. Each expression can be either a field name or a call to the geo.distance() function. Each expression can be followed by asc to indicate ascending, and desc to indicate descending. The default is ascending order. Ties will be broken by the match scores of documents. If no $orderby is specified, the default sort order is descending by document match score. There is a limit of 32 clauses for $orderby.
    https://docs.microsoft.com/en-us/rest/api/searchservice/search-documents#orderbystring-optional

    I have raised an issue on Sitecore Helpdesk and guys from support checked and reported the issue. It has a reference number 309333. Current resolution is to invert parameters like I did.