• ADNUG Survey 2022 Results

    We recently ran a survey of the Adelaide .NET User Group membership, and had 23 responses. While that’s not a huge number compared to the 1538 people who have currently registered in our Meetup group, it’s in the ballpark of how many people we’d get attending an actual meetup event. So in that respect it’s useful.

    The 10 questions ranged over what time(s) are most convenient for people to meet, what topics are of interest, to what kind of food would they prefer.

    Style of meetup

    • 9 people voted for hybrid
    • 7 people voted for in-person
    • 6 people voted for virtual

    Requested topics

    • Accessibility
    • Amazon
    • Azure
    • Basic good practices or framework design
    • Blazor
    • Cloud
    • Code Builders
    • Coding best practices
    • C# new features
    • Development patterns
    • DevOps
    • Dependency Injection
    • Event driven design
    • MAUI
    • Microservices
    • Mobile app dev
    • New technologies
    • People’s experience and insight using technology
    • Real world experiences & “war stories”
    • Secure coding
    • Serverless
    • Software Architecture
    • Testing
    • Unity
    • Visual Studio tooling
    • Visual Studio updates
    • Web API
    • Web development
    • Why .NET6

    Participation

    Appreciate the networking time afterwards Hybrid/virtual - useful especially for those who don’t work in the city

    Start times

    • In-person - 12 like 5.30pm, 5 preferred 6pm
    • Virtual (evening) - 9 like 5.30pm, 6 for 6pm
    • Virtual (daytime) - 10 for 12 noon, 9 for 12.30pm

    Most people seem to like the 5.30pm start. I did wonder if more would like a later start for a virtual event (which is why I split the questions).

    For daytime events (these are often when we get a US speaker presenting remotely), then it’s almost evenly split between 12 noon and 12.30 (possibly an indication of when folks stop for lunch!)

    Catering

    • 15 like pizza, 5 like subway

    Pizza is definitely a favourite, but sounds like we should mix it up with the occasional subway.

    Other comments

    A bunch of nice compliments. That was much appreciated!

    Now what

    My general sense is people are happy with what we’ve been doing. As we look to return to in-person events then there’s definitely interest in still being able to attend those virtually (eg. hybrid).

    I’m always looking for presenters. If you see a topic above that you know something about, or that you’d like to learn more about by putting a talk together, I’D LOVE TO HEAR FROM YOU!!

  • Fixing my blog (part 6) - Accessibility scanning

    Now we’ve got broken links sorted, we’re in a better state to start accessibility testing using the Accessibility Insights Action. This is available as both a GitHub Action and an Azure DevOps extension. I’ll be using the GitHub Action version.

    
    name: Accessibility
    
    on:
      workflow_dispatch:
        
    jobs:
      build:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/[email protected]
    
          - uses: ./.github/actions/jekyll-build-pages
            with:
              verbose: false
    
          - run: |
              sudo find -type f ! -regex ".*\.\(html\|svg\|gif\|css\|jpg\|png\)" -delete
            name: Remove non-HTML
            
            # https://github.com/microsoft/accessibility-insights-action
          - name: Scan for accessibility issues
            uses: microsoft/[email protected]
            with:
                repo-token: ${{ secrets.GITHUB_TOKEN }}
                site-dir: ${{ github.workspace }}/_site
                scan-timeout: 6000000
                #max-urls: 1500
                localhost-port: 12345
                scan-url-relative-path: /
    
          - name: Upload report artifact
            uses: actions/[email protected]
            with:
                name: accessibility-reports
                path: ${{ github.workspace }}/_accessibility-reports/index.html
    
    

    The action can either scan a local directory or a URL. In my case, I want it to scan all the files that make up my blog. My blog content is written in Markdown (.md) files and uses the Jekyll engine to render those pages into .html. It’s the latter that should be scanned for accessibility compliance.

    To generate the .html files, I make use of the Jekyll-Build-Pages action. This will generate a bunch of files under the _site directory.

    My initial testing with the scanning tool revealed it was triggering on some pages I was including but had no control over (eg. Google Ads and the Disqus comments). I wanted to exclude those from the scanning, and one way to do that is to make the content conditional. eg.

    
    {%- if jekyll.environment == "production" -%}
    <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-999999999" crossorigin="anonymous"></script>
    {%- endif -%}
    
    

    To exclude this block, I then needed to ensure that jekyll.environment was not set to production. I achieved this by using a local copy of the action in which I set the value of the JEKYLL_ENV environment variable to development. To facilitate that I need to make a few other changes which you can see on this branch.

    To help focus the scanning just on the files I care about, I added an extra step to the workflow to remove any files that weren’t one of .html, .svg, .gif, .jpg or .png.

    Depending on how many files you have in your website, scanning can take quite.

    It’s probably a good idea to not set max-urls the first time. This uses the default of 100, which will be enough to give you an idea of the kinds of problems you need to fix.

    The reason for starting small is if you have a template or CSS that are used across every page, then every page will trigger errors, and your scan will take ages to finish and contains heaps of the same error(s).

    Once you’ve resolved those common errors, then you can ramp up your max-urls to cover all the pages on your site (if it didn’t already).

    Running the workflow above also produces an ‘Accessibility Checks’ report. You can use this to get a quick overview of the results. To drill in to the details, you should download the build artifact view the index.html file in your browser.

    Accessibility report screenshot

    Fixing the errors

    The scan flagged 5 rule violations. Expanding each rule lists the URLs that exhibited the problem, plus a suggestion on how to resolve the issue. Sometime there are multiple suggestions.

    color-contrast: Ensure the contrast between foreground and background colors meet WCAG 2 AA contrast ration thresholds

    Example

    <a href="/tag/Family.html">Family</a>
    

    Fix the following:

    • Element has insufficient color contrast of 4.14 (foreground color: #2a7ae2, background color: #fdfdfd, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1Element has insufficient color contrast of 4.14 (foreground color: #2a7ae2, background color: #fdfdfd, font size: 12.0pt (16px), font weight: normal). Expected contrast ratio of 4.5:1

      • Use foreground color: #2773d6 and the original background color: #fdfdfd to meet a contrast ratio of 4.58:1.
    • Element has insufficient color contrast of 3.77 (foreground color: #828282, background color: #fdfdfd, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1Element has insufficient color contrast of 3.77 (foreground color: #828282, background color: #fdfdfd, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1

      • Use foreground color: #747474 and the original background color: #fdfdfd to meet a contrast ratio of 4.59:1.

    These were common across all pages, so fixing these early is a quick win. I searched for the hex color (usually it was defined in one of the .scss files that generate the CSS) and replaced it with the suggested colour

    Fix the following:

    • Element is in tab order and does not have accessible text

    Fix ONE of the following:

    • Element does not have text that is visible to screen readers
    • aria-label attribute does not exist or is empty
    • aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
    • Element has no title attribute

    image-alt: Ensures <img> elements have alternate text or a role of none or presentation

    Fix ONE of the following:

    • Element does not have an alt attribute
    • aria-label attribute does not exist or is empty
    • aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
    • Element has no title attribute
    • Element’s default semantics were not overridden with role=”none” or role=”presentation”

    html-has-lang: Ensure every HTML document has a lang attribute

    Fix the following:

    • The <html> element does not have a lang attribute

    This was a false positive as for some reason it was being flagged on images.

    frame-title: Ensures <iframe> and <frame> elements have an accessible name

    Fix ONE of the following:

    • Element has no title attribute
    • aria-label attribute does not exist or is empty
    • aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty
    • Element’s default semantics were not overridden with role=”none” or role=”presentation”

    This was being flagged by some older YouTube embedded player HTML.

    I’ve raise a bug to report the problem with links to images being flagged. It feels to me like the scanner is trying to scan image URLs (which it shouldn’t). Whether that’s a bug in the action, or in how I’m using it, I hope to find out soon.

  • Fixing my blog (part 5) - Putting it all together with a PR

    In part 4 of this series of posts we used the Replace multiple strings in files GitHub Action to update files with the replacement values. The files are modified on disk, but what to do with the changes? I could just automatically commit the changes back to version control, but I prefer to take a more cautious approach and give myself a chance to review the changes to confirm if they look reasonable. Creating a pull request is a great way of doing that.

    A an action I’ve used successfully before to do this is Peter Evans’ Create Pull Request GitHub Action. Using it is very easy:

    
    - name: Create Pull Request
      uses: peter-evans/[email protected]
      with:
        token: ${{ secrets.PAT_REPO_FULL }}
    
    

    I pass in a personal access token so that any workflows that should be run on creation of a pull request will be executed.

    And with that, I have a full workflow for checking for broken links and repairing them. The only thing to watch out for is that issue I mentioned previously with the invalid JSON produced by the Lychee action. As a temporary measure, I inlined that action in my repo and applied a local code fix. Hopefully once the Lychee action itself is updated then I can go back to using their implementation.

    
    name: Links
    
    on:
      workflow_dispatch:
        
    jobs:
      linkChecker:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/[email protected]
          - name: Link Checker
            id: lychee
            uses: ./.github/actions/lychee-action #lycheeverse/[email protected]
            env:
              GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
            with:
              args: '--verbose ./_posts/**/*.md --exclude-mail --scheme http https'
              format: json
              output: ./lychee/links.json
              fail: false
    
          - uses: actions/[email protected]
            with:
              path: ./lychee/links.json
    
          - name: Wayback Machine Query
            uses: flcdrg/[email protected]
            id: wayback
            with:
              source-path: ./lychee/links.json
              timestamp-regex: '_posts\/(\d+)\/(?<year>\d+)-(?<month>\d+)-(?<day>\d+)-'
    
          - uses: actions/[email protected]
            with:
              path: ./wayback/replacements.json
              
          - name: Replacements
            uses: flcdrg/[email protected]
            with:
              find: ${{ steps.wayback.outputs.replacements }}
              prefix: '(^|\\s+|\\()'
              suffix: '($|\\s+|\\))'
              
          - name: Create Pull Request
            # if: ${{ github.ref == 'refs/heads/main' }}
            uses: peter-evans/[email protected]
            with:
              token: ${{ secrets.PAT_REPO_FULL }}
    
    

    Now that we’ve addressed the broken links, we’re in a better state to revisit the Accessibility Insights Action that started this whole adventure!