<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">
  <channel>
    <title>Rick Strahl's Web Log</title>
    <link>https://weblog.west-wind.com/</link>
    <description>Life, Surf, Code and everything in between</description>
    <generator>West Wind Web Log</generator>
    <language>en-us</language>
    <image>
      <url>http://www.west-wind.com/images/WebLogBannerLogo.jpg</url>
      <title>Rick Strahl's Web Log</title>
      <link>https://weblog.west-wind.com/</link>
    </image>
    <pubDate>Sat, 11 Apr 2026 00:51:54 GMT</pubDate>
    <lastBuildDate>Mon, 02 Mar 2026 20:10:23 GMT</lastBuildDate>
    <xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><item>
      <title>Azure Trusted Signing Revisited with Dotnet Sign</title>
      <link>https://weblog.west-wind.com/posts/2026/Mar/02/Azure-Trusted-Signing-Revisited-with-Dotnet-Sign</link>
      <guid isPermaLink="false">5249291_202603022010</guid>
      <pubDate>Mon, 02 Mar 2026 20:10:23 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2026/Mar/02/Azure-Trusted-Signing-Revisited-with-Dotnet-Sign#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=5249291</wfw:commentRss>
      <category>Windows</category>
      <category>Security</category>
      <category>WPF</category>
      <description>&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Azure-Trusted-Signing-Revisited-with-Dotnet-Sign/TrustedSigningBanner.jpg" alt="Trusted Signing Banner"&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href="https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing"&gt;wrote about how to get Azure Trusted Signing to work&lt;/a&gt; for my application signing tasks a while back and mentioned how frustrating that process was both on Azure as well as on the client for the actual signing process. Well, since then I'm happy to say that some additional tooling has come out from Microsoft that makes this process quite a bit easier and also the signing process considerably faster than my previous workflow.&lt;/p&gt;
&lt;p&gt;This post is specifically about &lt;strong&gt;the client side of signing&lt;/strong&gt; - the original post covers both the Azure setup for your Azure Trusted Signing account and that hasn't changed much as well as the old SignTool based workflow which was a pain in the ass. In this post I'll discuss the new-ish &lt;code&gt;dotnet sign&lt;/code&gt; tooling that now works officially with Azure Trusted Signing and is a lot simpler to set up and faster to run.&lt;/p&gt;
&lt;p&gt;The documentation for the local client signing part of this process is still nearly non-existent or, at minimum, non-discoverable, and LLMs absolutely give the wrong advice because of it. The change of terminology and command names in the tooling isn't helping either, along with the outdated documentation. Why in the heck would you name something as obscure and non-relevant as &lt;code&gt;artifact-signing&lt;/code&gt; instead of the obvious &lt;code&gt;trusted-signing&lt;/code&gt; that already existed? But I disgress &#128516;&lt;/p&gt;
&lt;p&gt;So, here's the skinny on what works with a heck of a lot less effort than what I described in the previous post.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://markdownmonster.west-wind.com?ut=weblog"  target="_blank"
     title="Markdown Monster - Easy to use, yet powerfully productive Markdown Editing for Windows"&gt;
&lt;img src="/images/sponsors/banner-example.png?v=1.2" class="da-content-image" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="setting-up-trusted-signing"&gt;Setting up Trusted Signing&lt;/h2&gt;
&lt;p&gt;You still need to set up your Azure Trusted Signing, so that part hasn't changed, although by now hopefully the process to set this up might be a little simpler than what I described in my previous post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing#setting-up-microsoft-trusted-signing"&gt;Setting up Microsoft Azure Trusted Signing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you have your Trusted Signing account set up and ready to go, what has changed for the better is the process of how you sign your binaries on the local machine. It's quite a bit easier using &lt;code&gt;dotnet sign&lt;/code&gt; as that tool combines everything you need through the single set of tools - except for the Azure CLI which is required for authentication.&lt;/p&gt;
&lt;h2 id="local-signing-enter-dotnet-sign"&gt;Local Signing: Enter dotnet sign&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dotnet sign&lt;/code&gt; is a &lt;strong&gt;dotnet tool&lt;/strong&gt; that you install via the .NET SDK. You need to have the .NET SDK installed to install dotnet sign, as well as the Azure CLI so you can authenticate your Azure account.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/en-us/download/dotnet/10.0"&gt;.NET 10 SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest&amp;amp;pivots=winget"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dotnet/sign"&gt;Dotnet Sign&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="install-net-sdk"&gt;Install .NET SDK&lt;/h3&gt;
&lt;p&gt;The .NET SDK is required in order to install the dotnet tool infrastructure required to install and run the &lt;code&gt;dotnet sign&lt;/code&gt; tool.&lt;/p&gt;
&lt;p&gt;You can install the SDK from here if you don't already have it on your dev machine&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/en-us/download/dotnet/10.0"&gt;.NET 10 SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;h4 id="--dotnet-tool-and-the-net-sdk"&gt;&lt;i class="fas fa-info-circle" style="font-size: 1.1em"&gt;&lt;/i&gt;  &lt;code&gt;dotnet tool&lt;/code&gt; and the .NET SDK&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;dotnet tool&lt;/code&gt; deployed &lt;em&gt;applications&lt;/em&gt; use the locally installed .NET SDK to take advantage of the cross platform features of .NET without having to install any additional framework dependencies or having to create separate installers for each platform. A Dotnet tool will run on any of .NET's supported platforms assuming you use cross-platform compatible features only. It does this by automatically creating a platform specific executable for the tool application that &lt;code&gt;dotnet tool install&lt;/code&gt; is run on.  For this reason it's a convenient way to deploy tools across platforms and if you're in the .NET development eco-system in any way it's likely the .NET SDK is already installed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="install-azure-cli"&gt;Install Azure CLI&lt;/h3&gt;
&lt;p&gt;The Azure CLI is required so that you can authenticate using Azure's oAuth Authentication flow.&lt;/p&gt;
&lt;p&gt;You can install the Azure CLI in a number of ways but the easiest is probably via WinGet.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?view=azure-cli-latest&amp;amp;pivots=winget"&gt;Install Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's the WinGet command:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ps"&gt;winget install --exact --id Microsoft.AzureCLI
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id="logging-into-azure-cli"&gt;Logging into Azure CLI&lt;/h4&gt;
&lt;p&gt;Once the Azure CLI is installed you can then log in and set the subscription that your Certificate runs under:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-powershell"&gt;az config set core.enable_broker_on_windows=false
az login
az account set --subscription &amp;quot;Pay-As-You-Go&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The prompt to login is interactive - follow the yellow prompts. I've had quite a few  issues with the default Windows oAuth authentication using a Web Browser, and the first configuration line:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ps"&gt;az config set core.enable_broker_on_windows=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;provides more reliable authentication directly in the CLI. You can try without it first, and if that doesn't work use that line to use the alternate sign in flow.&lt;/p&gt;
&lt;p&gt;For me this was the only way I get it to work correctly. Your mileage may vary and you may not  need it. Another thing to look out for is to make sure you choose the right subscription as subscription ids are hard to decipher in some cases if you have a few of them.&lt;/p&gt;
&lt;h3 id="install-dotnet-sign"&gt;Install Dotnet Sign&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/dotnet/sign"&gt;Dotnet Sign&lt;/a&gt; is a &lt;strong&gt;dotnet tool&lt;/strong&gt; installed executable, and in order to install it you need use the &lt;code&gt;dotnet tool&lt;/code&gt; command that's part of the .NET SDK.&lt;/p&gt;
&lt;p&gt;Make sure the .NET SDK is installed first, and then to install dotnet sign:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ps"&gt;dotnet tool install -g --prerelease sign
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tool is currently in pre-release so the &lt;code&gt;--prerelease&lt;/code&gt; switch is not optional -  otherwise the package won't be found. You can also install locally into your project by omitting the &lt;code&gt;-g&lt;/code&gt; switch which creates a fixed local copy instead of a global instance installed in the shared tools location.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3 id="using-sign-code-artifact-signing"&gt;Using Sign Code Artifact Signing&lt;/h3&gt;
&lt;p&gt;With all this in place you can now use the &lt;code&gt;Sign&lt;/code&gt; command from the command line to sign your binaries. Specifically you'll use:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ps"&gt;sign code artifact-signing --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that although there's a &lt;code&gt;trusted-signing&lt;/code&gt; option, it's now deprecated and you should use &lt;code&gt;artifact-signing&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;A full signing command for a binary file looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-powershell"&gt;sign code artifact-signing  `
   --verbosity warning `
   --timestamp-url http://timestamp.digicert.com `
   --artifact-signing-endpoint https://eus.codesigning.azure.net/ `
   --artifact-signing-account MySigningAccount `
   --artifact-signing-certificate-profile MySignongCertificateProfile `  .\Distribution\MarkdownMonster.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can specify multiple files and they will be batch sent together. Typically you'll want to run with Verbosity of warning, which doesn't show any output unless you have a problem. The default (Trace) and Information are very verbose and too much noise in any sort of build output unless you explicitly are looking for that.&lt;/p&gt;
&lt;p&gt;Here's what that looks like with Information verbosity, when you run it in the Terminal:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Azure-Trusted-Signing-Revisited-with-Dotnet-Sign/SignCodeInTheTerminal.png" alt="Sign Code In The Terminal"&gt;&lt;/p&gt;
&lt;p&gt;Signing is &lt;strong&gt;considerably faster&lt;/strong&gt; than what I saw with my old &lt;code&gt;SignTool&lt;/code&gt; based workflow, with signing times under two seconds for most files (this is one is quite large). Based on this speed, it looks like &lt;code&gt;sign&lt;/code&gt; uses locally created hashes rather than uploading the entire file to the server for processing.&lt;/p&gt;
&lt;p&gt;Unfortunately, the new workflow with Sign doesn't support a metadata file like &lt;code&gt;SignTool&lt;/code&gt; supports, so you &lt;strong&gt;have to specify all the Azure parameters explicitly&lt;/strong&gt;. I'll fix that with the Powershell script provided below to keep that useful functionality intact.&lt;/p&gt;
&lt;h3 id="putting-it-all-together-into-a-signing-script"&gt;Putting it all together into a Signing Script&lt;/h3&gt;
&lt;p&gt;The basic syntax for signing via &lt;code&gt;Sign&lt;/code&gt; is now simple enough. However, I need signing in &lt;strong&gt;a lot of different projects&lt;/strong&gt;, so I need to reuse the functionality across these various projects and provide the script as part of the &lt;strong&gt;local&lt;/strong&gt; build infrastructure.&lt;/p&gt;
&lt;p&gt;The reasons to create a script for all this are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using metadata configuration files (like SignTool used to use)&lt;/li&gt;
&lt;li&gt;Handling login optionally&lt;/li&gt;
&lt;li&gt;Handling parameter errors and signing errors&lt;/li&gt;
&lt;li&gt;Documentation for prerequisites and configuration in the script&lt;/li&gt;
&lt;li&gt;Self-contained for easy re-use - just copy two files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's the Powershell script:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-powershell"&gt;# File name: Signfile.ps1
# Prerequisites:  
# dotnet tool install -g --prerelease sign
# Azure CLI required for logging in optionally
# Support metadata: SignfileMetaData.json

param(
    [string]$file = &amp;quot;&amp;quot;,
    [string]$file1 = &amp;quot;&amp;quot;,
    [string]$file2 = &amp;quot;&amp;quot;,
    [string]$file3 = &amp;quot;&amp;quot;,
    [string]$file4 = &amp;quot;&amp;quot;,
    [string]$file5 = &amp;quot;&amp;quot;,
    [string]$file6 = &amp;quot;&amp;quot;,
    [string]$file7 = &amp;quot;&amp;quot;,
    [string]$file8 = &amp;quot;&amp;quot;,
    [boolean]$login = $false
)
if (-not $file) {
    Write-Host &amp;quot;Usage: SignFile.ps1 -file &amp;lt;path to file to sign&amp;gt;&amp;quot;
    exit 1
}

if ($login) {
    az config set core.enable_broker_on_windows=false
    az login
    az account set --subscription &amp;quot;Pay-As-You-Go&amp;quot;
}

# SignfileMetadata.json is not checked in. Format:
# {
#   &amp;quot;Endpoint&amp;quot;: &amp;quot;https://eus.codesigning.azure.net/&amp;quot;,
#   &amp;quot;CodeSigningAccountName&amp;quot;: &amp;quot;MySigningAccount&amp;quot;,
#   &amp;quot;CertificateProfileName&amp;quot;: &amp;quot;MySigningCertificateProfile&amp;quot;
# }

$metadata = Get-Content -Path &amp;quot;SignfileMetadata.json&amp;quot; -Raw | ConvertFrom-Json
$tsEndpoint = $metadata.Endpoint
$tsAccount = $metadata.CodeSigningAccountName
$tsCertProfile = $metadata.CertificateProfileName
$timeServer = &amp;quot;http://timestamp.digicert.com&amp;quot;

$signArgs = @(
    &amp;quot;--verbosity&amp;quot;, &amp;quot;warning&amp;quot;,
    &amp;quot;--timestamp-url&amp;quot;, $timeServer,
    &amp;quot;--artifact-signing-endpoint&amp;quot;, $tsEndpoint,
    &amp;quot;--artifact-signing-account&amp;quot;, $tsAccount,
    &amp;quot;--artifact-signing-certificate-profile&amp;quot;, $tsCertProfile
)

# Add file arguments at the end
foreach ($f in @($file, $file1, $file2, $file3, $file4, $file5, $file6, $file7, $file8)) {
    if (![string]::IsNullOrWhiteSpace($f)) {
        $signArgs += $f
    }
}

# Run signtool and capture the exit code
sign code artifact-signing $signArgs
$exitCode = $LASTEXITCODE

if ($exitCode -eq 0) {
    Write-Host &amp;quot;File(s) signed successfully.&amp;quot; -ForegroundColor Green
    exit 0
} else {
    Write-Host &amp;quot;Signing failed with exit code: $exitCode&amp;quot; -ForegroundColor Red
    exit $exitCode
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script uses a separate, external configuration file for the Azure values required for code signing to work. I tend to check in the signing script into Git, while the metadata is locally created and not checked in which separates the two. Alternately you can use some other approach to keep the private data out of your repo - environment variables would also do the trick, but I prefer this explicit approach because it makes it easy to copy the data and script across multiple projects while still keeping the private data out of Git.&lt;/p&gt;
&lt;p&gt;Here's what the metadata file looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;// SignfileMetadata.json
{
  &amp;quot;Endpoint&amp;quot;: &amp;quot;https://eus.codesigning.azure.net/&amp;quot;,
  &amp;quot;CodeSigningAccountName&amp;quot;: &amp;quot;MySigningAccount&amp;quot;,
  &amp;quot;CertificateProfileName&amp;quot;: &amp;quot;MyCodeSignCertificateProfile&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now I can drop &lt;code&gt;SignFile.ps&lt;/code&gt; and &lt;code&gt;SignfileMetadata.json&lt;/code&gt; file into a folder and use it for signing.&lt;/p&gt;
&lt;p&gt;In my build script I then have something like this to invoke the signing operation after my binaries have been built:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-powershell"&gt;if ($nosign -eq $false) {    
    &amp;quot;Signing binaries...&amp;quot;
    .\signfile-dotnetsign.ps1 -file &amp;quot;.\Distribution\MarkdownMonster.exe&amp;quot; `
                    -file1 &amp;quot;.\Distribution\MarkdownMonsterArm64.exe&amp;quot; `
                    -file2 &amp;quot;.\Distribution\MarkdownMonster.dll&amp;quot; `
                    -file3 &amp;quot;.\Distribution\mm.exe&amp;quot; `
                    -file4 &amp;quot;.\Distribution\mmcli.exe&amp;quot; `
                    -login $false                   

    if ($LASTEXITCODE -ne 0) {
        Write-Host &amp;quot;Signing failed, exiting build script.&amp;quot;
        exit $LASTEXITCODE
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then again at the very end to sign the final setup distributable:
l&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-powershell"&gt;.\signfile-dotnetsign.ps1 `
	-file &amp;quot;.\Builds\CurrentRelease\MarkdownMonsterSetup.exe&amp;quot; `
    -login $false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The meta data file can be created in the output folder and should not be checked into Git repo. Alternately you could also change the code to use environment variables if that suits your workflow better.&lt;/p&gt;
&lt;h2 id="dotnet-sign-is-much-better"&gt;Dotnet Sign is Much Better&lt;/h2&gt;
&lt;p&gt;I've been using this new workflow for a couple of weeks now, and it has made signing &lt;strong&gt;a lot faster&lt;/strong&gt; than &lt;code&gt;Signtool&lt;/code&gt;. It appears that binaries are locally hashed and only the hash data is sent to the server result in much faster processing times. Average processing with Signtool was around well over 5 seconds per file, it's now down under 1 second per file - a huge improvement in packaging performance.&lt;/p&gt;
&lt;p&gt;Microsoft's own documentation now also uses the Digicert timestamp server &lt;a href="https://weblog.west-wind.com/posts/2026/Feb/26/Dont-use-the-Microsoft-Timestamp-Server-for-Signing"&gt;instead of the Microsoft one that has been failing for me on a regular basis&lt;/a&gt;. Using the DigitCert timestamp server I haven't had any signing failures in the last two weeks.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;So all of this is good news, as it's taken away some of the early growing pains of using Azure Trusted Signing and makes it much more usable and predictable to run on the client without having to jump through all sorts of hoops.&lt;/p&gt;
&lt;p&gt;It still isn't as simple as it could be, especially if developers are not already using the .NET ecosystem, but if you're doing code signing for Authenticode, you're likely a Windows developer.&lt;/p&gt;
&lt;p&gt;The last hurdle that I'd like to get going now is NuGet signing. But I'll leave that for another time... Onwards.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing"&gt;Fighting through Setting up Microsoft Trusted Signing  (for steps to set up on Azure)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/trusted-signing/"&gt;Microsoft Trusted Signing Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/pricing/details/trusted-signing/"&gt;Microsoft Trusted Signing Pricing Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="margin-top: 30px;font-size: 0.8em;
            border-top: 1px solid #eee;padding-top: 8px;"&gt;
    &lt;img src="https://markdownmonster.west-wind.com/favicon.png" style="height: 20px;float: left; margin-right: 10px;"&gt;
    this post created and published with the 
    &lt;a href="https://markdownmonster.west-wind.com" target="top"&gt;Markdown Monster Editor&lt;/a&gt; 
&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style='margin: 10px 0px'&gt;&lt;small&gt;© Rick Strahl, West Wind Technologies, 2005-2026&lt;/small&gt;&lt;/div&gt;&lt;div&gt;Posted in &lt;b&gt;&lt;a href='/ShowPosts.aspx?Category=Windows'&gt;Windows&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href='/ShowPosts.aspx?Category=Security'&gt;Security&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href='/ShowPosts.aspx?Category=WPF'&gt;WPF&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/div&gt;
&lt;/small&gt;</description>
    </item>
    <item>
      <title>Don't use the Microsoft Timestamp Server for Signing</title>
      <link>https://weblog.west-wind.com/posts/2026/Feb/26/Dont-use-the-Microsoft-Timestamp-Server-for-Signing</link>
      <guid isPermaLink="false">5239628_202602262241</guid>
      <pubDate>Thu, 26 Feb 2026 22:41:03 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2026/Feb/26/Dont-use-the-Microsoft-Timestamp-Server-for-Signing#Comments</comments>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=5239628</wfw:commentRss>
      <category>Security</category>
      <category>Windows</category>
      <description>&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Dont-use-the-Microsoft-Timestamp-Server-for-Signing/SigningFailedBanner.png" alt="Signing Failed Banner"&gt;&lt;/p&gt;
&lt;p&gt;If you're using any of the Microsoft Signing technologies like Trusted Signing, one thing you might run into is frequent failures of the default, suggested timestamp server that Microsoft uses in their examples:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$timeServer = &amp;quot;http://timestamp.acs.microsoft.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For signing code with trusted signing like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ps"&gt;$timeServer = &amp;quot;http://timestamp.acs.microsoft.com&amp;quot;

$args = @(
    &amp;quot;sign&amp;quot;, &amp;quot;/v&amp;quot;, &amp;quot;/debug&amp;quot;, &amp;quot;/fd&amp;quot;, &amp;quot;SHA256&amp;quot;,
    &amp;quot;/tr&amp;quot;, &amp;quot;$timeServer&amp;quot;,
    &amp;quot;/td&amp;quot;, &amp;quot;SHA256&amp;quot;,
    &amp;quot;/dlib&amp;quot;, &amp;quot;$env:LOCALAPPDATA\Microsoft\MicrosoftTrustedSigningClientTools\Azure.CodeSigning.Dlib.dll&amp;quot;,
    &amp;quot;/dmdf&amp;quot;, &amp;quot;.\SignfileMetadata.json&amp;quot;
)
# Add non-empty file arguments
foreach ($f in @($file, $file1, $file2, $file3, $file4, $file5, $file6, $file7)) {
    if (![string]::IsNullOrWhiteSpace($f)) {
        $args += $f
    }
}

# Run signtool and capture the exit code
.\signtool.exe $args
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works about 80% of the time for me in my multiple file signing workflow - yeah that's a pretty high failure rate! I end up signing 8 files per distribution (several app binaries and the final setup Exe) and quite frequently one of those signing operations (mostly the last one of the larger set up exe) fails with:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Dont-use-the-Microsoft-Timestamp-Server-for-Signing/SigningFailedWithMicrosoftTimeService.png" alt="Signing Failed With Microsoft Time Service"&gt;&lt;br&gt;
&lt;small&gt;&lt;strong&gt;Figure 1&lt;/strong&gt; - Signing fails due to the Microsoft Timestamp Server &lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I see this happening in two separate but similar workflows both of which are signing a number of files in fairly rapid succession. I'm using &lt;code&gt;Signtool&lt;/code&gt; to batch the files to sign, but it appears Signtool behind the scenes is still sending them one at a time - and that might be where the problem is - some sort of rate limiting kicking depending on how quick these files sign.&lt;/p&gt;
&lt;p&gt;Regardless, whether it's an infra failure or a rate limiting issue, it's crazy to think that something as simple as a timestamp server could fail in a common scenario like this, but leave it to Microsoft to screw that up. &#128169;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://markdownmonster.west-wind.com?ut=weblog"  target="_blank"
     title="Markdown Monster - Easy to use, yet powerfully productive Markdown Editing for Windows"&gt;
&lt;img src="/images/sponsors/banner-example.png?v=1.2" class="da-content-image" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="use-a-different-timestamp-server"&gt;Use a different TimeStamp Server&lt;/h2&gt;
&lt;p&gt;The solution to this is simple: Don't use the Microsoft server and instead switch to a different signing compatible Timestamp Server that is actually reliable.&lt;/p&gt;
&lt;p&gt;I've been using DigiCert's server with this Url:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$timeServer = &amp;quot;http://timestamp.digicert.com&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and that has solved the problem for me at the moment. No more signing errors.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing"&gt;Fighting through Setting up Microsoft Trusted Signing&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Alternate Timestamp Servers&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DigiCert&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.digicert.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.digicert.com/ts&lt;/code&gt; (alt endpoint)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sectigo (Comodo)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.sectigo.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.comodoca.com/rfc3161&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GlobalSign&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.globalsign.com/?signature=sha2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSL.com&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://ts.ssl.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http://ts.ssl.com/rfc3161&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Entrust&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://timestamp.entrust.net/TSS/RFC3161sha2TS&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Certum (Asseco)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://time.certum.pl&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="margin-top: 30px;font-size: 0.8em;
            border-top: 1px solid #eee;padding-top: 8px;"&gt;
    &lt;img src="https://markdownmonster.west-wind.com/favicon.png" style="height: 20px;float: left; margin-right: 10px;"&gt;
    this post created and published with the 
    &lt;a href="https://markdownmonster.west-wind.com" target="top"&gt;Markdown Monster Editor&lt;/a&gt; 
&lt;/div&gt;
&lt;p style="margin-top: 1em;"&gt;

&lt;/p&gt;
&lt;div style='margin: 10px 0px'&gt;&lt;small&gt;© Rick Strahl, West Wind Technologies, 2005-2026&lt;/small&gt;&lt;/div&gt;&lt;div&gt;Posted in &lt;b&gt;&lt;a href='/ShowPosts.aspx?Category=Security'&gt;Security&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href='/ShowPosts.aspx?Category=Windows'&gt;Windows&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/div&gt;
&lt;/small&gt;</description>
    </item>
    <item>
      <title>Reliably Refreshing the WebView2 Control</title>
      <link>https://weblog.west-wind.com/posts/2026/Feb/04/Reliably-Refreshing-the-WebView2-Control</link>
      <guid isPermaLink="false">5204283_202602050753</guid>
      <pubDate>Thu, 05 Feb 2026 07:53:22 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2026/Feb/04/Reliably-Refreshing-the-WebView2-Control#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=5204283</wfw:commentRss>
      <category>WebView</category>
      <category>Windows</category>
      <category>WPF</category>
      <description>&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Reliably-Refreshing-the-WebView2-Control/WebViewRefreshBanner.jpg" alt="Web View Refresh Banner"&gt;&lt;/p&gt;
&lt;p&gt;It seems like such a simple thing: Reloading Web Browser content when a page is already active. Just reload, right! But... it's never quite so simple. There is soft reload and hard reload,  and it turns out the WebView2 control does not expose the underlying browser APIs in the same way you might be used to by your browser or DOM APIs. While there's &lt;code&gt;Reload()&lt;/code&gt; functionality, there's no direct support for a hard reload that also reloads related resources like images, overriding local and server cache settings.&lt;/p&gt;
&lt;p&gt;Specifically the WebView2 control has a &lt;code&gt;CoreWebView2.Reload()&lt;/code&gt; method, but it lacks a &lt;code&gt;noCache&lt;/code&gt; parameter to completely reload content of the page and all of its dependencies.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://markdownmonster.west-wind.com?ut=weblog"  target="_blank"
     title="Markdown Monster - Easy to use, yet powerfully productive Markdown Editing for Windows"&gt;
&lt;img src="/images/sponsors/banner-example.png?v=1.2" class="da-content-image" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="why-hard-refreshes-matter"&gt;Why Hard Refreshes matter&lt;/h2&gt;
&lt;p&gt;Refreshing content is a common thing that you do in any Web application, but in local desktop applications it's even more important, as many applications render content to local files, and then load those files into the WebView for display as previews or or other Html type views.&lt;/p&gt;
&lt;p&gt;For example in &lt;a href="https://markdownmonster.west-wind.com"&gt;Markdown Monster&lt;/a&gt; and &lt;a href="https://documentationmonster.com"&gt;Documentation Monster&lt;/a&gt; I render preview Html to file and then display the Html output in the browser.&lt;/p&gt;
&lt;p&gt;But in these specific scenarios typical 'page' updates update the in memory DOM with changes for much faster updates, rather than full reloads from disk.&lt;/p&gt;
&lt;p&gt;However, there are a few scenarios that require a full reload of the page and all of its related resources. Specifically there are several operations that drop or paste images into the document and if an image has been changed I want to see the change immediately in the preview. By default &lt;code&gt;Reload()&lt;/code&gt; will reload the page, but &lt;strong&gt;won't refresh the images&lt;/strong&gt; so while I can force the refresh of the page content, if the image is already displayed, the changed image will not show up.&lt;/p&gt;
&lt;p&gt;Hrmph! &#128544;&lt;/p&gt;
&lt;h2 id="webview2-reload"&gt;WebView2 Reload()&lt;/h2&gt;
&lt;p&gt;So the WebView has a &lt;code&gt;CoreWebView2.Reload()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-cs"&gt;var url = WebView.Source?.ToString();
WebView.CoreWebView2.Reload()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you call &lt;code&gt;Reload()&lt;/code&gt; like this you'll find that even the page content &lt;strong&gt;sometimes still doesn't refresh&lt;/strong&gt; - even if content has been changed. This can happen due to target site's cache policy or the browser cache policy with local files or if local files are not properly updating their &lt;code&gt;LastWrite&lt;/code&gt; timestamps. Mostly a reload works for content though...&lt;/p&gt;
&lt;h3 id="dependent-resource-refreshing"&gt;Dependent Resource Refreshing&lt;/h3&gt;
&lt;p&gt;But much worse is that even if the content page itself refreshes with &lt;code&gt;Reload()&lt;/code&gt;, dependent resources like images, scripts, style sheets etc. usually do not.&lt;/p&gt;
&lt;p&gt;This can be really annoying if you're using the browser as a previewer. For example, in Markdown editing you might paste an image into the editor and it displays fine. Then you make a change to the underlying image, refresh the browser and... the image does not update which is an annoying fail!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://weblog.west-wind.com/images/2026/Reliably-Refreshing-the-WebView2-Control/MarkdownMonster%20Image%20Updates.png" alt="MarkdownMonster Image Updates"&gt;&lt;br&gt;
&lt;small&gt;&lt;strong&gt;Figure 1&lt;/strong&gt; - Markdown Monster images don't update if using only &lt;code&gt;CioreWebView2.Reload()&lt;/code&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;This happens even if the content page refreshes. Incidentally the same thing happens in a desktop browser, unless you hard refresh. And even then sometimes images do not refresh. But again, &lt;code&gt;Reload()&lt;/code&gt; is not a hard refresh so by default support resources and in some cases even the main content do not refresh.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2 id="hard-refresh-in-the-webview"&gt;Hard Refresh in the WebView&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;So how do we do a real hard refresh in the WebView2 control?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let's take a look...&lt;/p&gt;
&lt;h3 id="interactive-hard-reload-with-keyboard-shortcuts"&gt;Interactive Hard Reload with Keyboard Shortcuts&lt;/h3&gt;
&lt;p&gt;T
he WebView control is essentially a full Chromium instance so it has most of Chromium's native features. This means you can press &lt;code&gt;ctrl-shift-R&lt;/code&gt; or &lt;code&gt;Ctrl-F5&lt;/code&gt; to force a hard refresh in the browser - assuming you haven't overridden the key handling in some way in your host application.&lt;/p&gt;
&lt;p&gt;It's an easy work around as long as your users are tech savy and do the key gymnastics or you've provided good documentation or visual clues to make the keyboard shortcuts accessible. But shortcuts are always difficult to bring attention to... it's just not very obvious. Obviously! &#128514;&lt;/p&gt;
&lt;h3 id="programmatic-hard-reload"&gt;Programmatic Hard Reload&lt;/h3&gt;
&lt;p&gt;Which brings us to programmatic solutions to Hard Refreshes that you can attach to commands or event handlers.  Programmatic solutions are more explicit and... more obvious.&lt;/p&gt;
&lt;h4 id="good---replace-the-url"&gt;Good - Replace the Url&lt;/h4&gt;
&lt;p&gt;For a simple way to force at least the content page to refresh reliably, you can replace the Url and force the page to reload explicitly:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public void Refresh(bool noCache)
{
   if (WebBrowser == null || string.IsNullOrEmpty(WebBrowser.Source?.ToString()))
       return;  
       
   if (!noCache)       
   {
	WebBrowser.CoreWebView2.Reload();
	return;
   }

   var orig = WebBrowser.Source;
   WebBrowser.Source = new Uri(&amp;quot;about:blank&amp;quot;);
   WebBrowser.Dispatcher.Invoke( ()=&amp;gt; WebBrowser.Source = orig);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The idea here is that you force the Url to be reset in the control. The Url has to be set to a different value first and then reset to properly log a change so it gets set to &lt;code&gt;about:blank&lt;/code&gt; then back to the original Url.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that it appears resetting the &lt;code&gt;WebBrowser.Source&lt;/code&gt; is cycle dependent which is why I use a Dispatcher in the code above. In my use of this approach I started with two one-after-the-other &lt;code&gt;WebBrowser.Source&lt;/code&gt; assignments and that worked most of the time but failed occasionally and unreliably. Using the &lt;code&gt;Dispatcher&lt;/code&gt; improved the reliability significantly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In most situations I've found that this also reloads dependent resources, but I've had reports from a number of users that on occasion they see images not refreshing. Fairly rare though so this seems to corroborate my timing suspicion of the Source assignment.&lt;/p&gt;
&lt;p&gt;There are more reliable &lt;code&gt;Reload()&lt;/code&gt; solutions, but the reason you might want to use this solution is to avoid blowing out your entire profile cache entirely on a reload as the two following approaches I show next do.&lt;/p&gt;
&lt;h4 id="better---simple-cache-revocation"&gt;Better - Simple Cache Revocation&lt;/h4&gt;
&lt;p&gt;The next approach uses the WebView's built in &lt;strong&gt;Profile Cache&lt;/strong&gt; APIs to clear the browser cache to force reloading all content. The &lt;code&gt;WebView.CoreWebView2.Profile.ClearBrowsingDataAsync()&lt;/code&gt; method can be used to clear all or select cache items from the active profile.&lt;/p&gt;
&lt;p&gt;The code is simple enough:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public void Refresh(bool noCache)
{
    if (WebBrowser == null || string.IsNullOrEmpty(WebBrowser.Source?.ToString())) return;

    if (noCache)
    {
        WebBrowser.Dispatcher.InvokeAsync(async () =&amp;gt;
        {
        	// Hard Repload by clearing the Cache
            await WebBrowser.CoreWebView2.Profile.ClearBrowsingDataAsync(CoreWebView2BrowsingDataKinds.DiskCache);
            WebBrowser.CoreWebView2.Reload();
        }).Task.FireAndForget();
        return;
    }

    WebBrowser.CoreWebView2.Reload();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ClearBrowsingDataAsync()&lt;/code&gt; method can be called with no parameters which busts up all cached items, or you can specify which items to remove. For plain page display and related resources you typically only need the Disk Cache to be busted since related resources like images, scripts and style sheets are cached to disk in the WebView's Profile folder.&lt;/p&gt;
&lt;p&gt;Note that the &lt;code&gt;ClearBrowsingDataAsync()&lt;/code&gt; method is async, and &lt;strong&gt;you have to&lt;/strong&gt; &lt;code&gt;await&lt;/code&gt; the method for the cache clearing to complete &lt;strong&gt;before&lt;/strong&gt; you can &lt;code&gt;Reload()&lt;/code&gt; the page in order for the hard refresh to work.&lt;/p&gt;
&lt;p&gt;I'm using WPF here to go from sync to async using the &lt;code&gt;Dispatcher&lt;/code&gt;, but you could also make the entire method async and skip the Dispatcher to make this a little simpler. I'm doing that here because I have an older non-async interface I'm implementing and there's no need to explicitly make the external method async and await the &lt;code&gt;Reload()&lt;/code&gt;, since navigation and reloading are inherently &lt;em&gt;not directly awaitable&lt;/em&gt; in the WebView (you have to explicitly use events for that).&lt;/p&gt;
&lt;p&gt;This method is the safest and most reliable way to ensure the browser and dependent resources are refreshed but there may still be some resources that are not refreshed.&lt;/p&gt;
&lt;h4 id="best---hard-cache-revoke-like-browser-hard-refresh"&gt;Best - Hard Cache Revoke like Browser Hard Refresh&lt;/h4&gt;
&lt;p&gt;This brings up to the last approach which is essentially what the WebBrowser users internally and is the closest thing to pressing &lt;code&gt;ctrl-shift-R&lt;/code&gt; to force a hard reset.&lt;/p&gt;
&lt;p&gt;This solution uses the WebView DevTools API to force a refresh:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public void Refresh(bool noCache)
{
    if (WebBrowser == null || string.IsNullOrEmpty(WebBrowser.Source?.ToString())) return;

    if (noCache)
    {
        WebBrowser.Dispatcher.InvokeAsync(async () =&amp;gt;
        {
        	// Hard Reload the Page
        	if(WebBrowser?.CoreWebView2 != null) 
        	{            
	            await WebBrowser.CoreWebView2.CallDevToolsProtocolMethodAsync(&amp;quot;Network.clearBrowserCache&amp;quot;, &amp;quot;{}&amp;quot;);
	            WebBrowser.CoreWebView2.Reload();
        	}
        }).Task.FireAndForget();
        return;
    }

    WebBrowser.CoreWebView2.Reload();   // not working reliably if file initial navigate failed
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key here is the call to the &lt;a href="https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-clearBrowserCache"&gt;DevTools protocols&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-cs"&gt;await WebBrowser.CoreWebView2.CallDevToolsProtocolMethodAsync(&amp;quot;Network.clearBrowserCache&amp;quot;, &amp;quot;{}&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;CallDevToolsProtocolMethodAsync()&lt;/code&gt; API exposes a shit-ton of internal browser functionality via a command interface and &lt;code&gt;Network.clearBrowserCache&lt;/code&gt; is one of the simplest ones.&lt;/p&gt;
&lt;p&gt;But, there are some limitations to this API: it requires either a visual host running on an STA thread (which is every desktop UI app), or has to be used with a headless host explicitly in non-UI application contexts which is a lot more complicated. If you're in the latter category stick with the &lt;code&gt;ClearBrowsingDataAsync()&lt;/code&gt; API instead as that has fewer limitations.&lt;/p&gt;
&lt;h3 id="also-recommended-clearcache"&gt;Also Recommended: ClearCache()&lt;/h3&gt;
&lt;p&gt;Sometimes you may not need to or cannot do a full refresh, but you still want to refresh resources when they are re-rendered. For example, if you use JavaScript to update the DOM with Html you might re-render an image Url where the file has changed in the same way as with a full refresh. If you clear the cache and the DOM re-renders the replaced block of Html it also refreshes the image.&lt;/p&gt;
&lt;p&gt;For this reason I also recommend adding an explicit and more obvious ClearCache wrapper if for nothing else than making it more easily visible or because the WebBrowser might be hidden behind an API interface.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-cs"&gt;public Task ClearCache()
{
	if(WebBrowser?.CoreWebView2 != null) 
	   {            
		return WebBrowser.CoreWebView2.CallDevToolsProtocolMethodAsync(&amp;quot;Network.clearBrowserCache&amp;quot;, &amp;quot;{}&amp;quot;);
	}
	return Task.CompletedTask;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's a heck of a lot easier to remember to call this &lt;code&gt;ClearCache()&lt;/code&gt; method rather than the DevTools API call.&lt;/p&gt;
&lt;p&gt;If you're using the &lt;code&gt;Westwind.WebView&lt;/code&gt; library and &lt;a href="https://github.com/RickStrahl/Westwind.WebView/blob/9fd77917ccf1bad6ef091fe3cfc8f9241cfbd7b7/Westwind.WebView/Wpf/WebViewHandler.cs#L49"&gt;WebViewHandler &lt;/a&gt; which is WebView Behavior class that adds many common features and operations to your WebView, you'll find &lt;a href="https://github.com/RickStrahl/Westwind.WebView/blob/9fd77917ccf1bad6ef091fe3cfc8f9241cfbd7b7/Westwind.WebView/Wpf/WebViewHandler.cs#L540"&gt;Reload()&lt;/a&gt; and &lt;a href="https://github.com/RickStrahl/Westwind.WebView/blob/9fd77917ccf1bad6ef091fe3cfc8f9241cfbd7b7/Westwind.WebView/Wpf/WebViewHandler.cs#L617"&gt;ClearCache()&lt;/a&gt; methods on that class.&lt;/p&gt;
&lt;h3 id="also-useful-for-navigation"&gt;Also Useful For Navigation&lt;/h3&gt;
&lt;p&gt;The same approaches can also be used for Navigation instead of just for &lt;code&gt;Reload()&lt;/code&gt;. You can run into the same cache issues with plain navigation, as resources like images may have been previously rendered in other pages, and if you then load another page with the same image that image may still be coming from cache.&lt;/p&gt;
&lt;p&gt;So in my apps I typically also provide a Navigate method like this (use the Hard Refresh option of your choice):&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public void Navigate(string url, bool noCache)
{
    if (noCache)
    {                
        WebBrowser.Source = new Uri(&amp;quot;about:blank&amp;quot;);  // force a refresh
        WebBrowser.Dispatcher.InvokeAsync(async () =&amp;gt;
        {
            await WebBrowser.CoreWebView2.CallDevToolsProtocolMethodAsync(&amp;quot;Network.clearBrowserCache&amp;quot;, &amp;quot;{}&amp;quot;);
            WebBrowser.Source = new Uri(url);
        }).Task.FireAndForget();
    }            
    WebBrowser.Source = new Uri(url);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find these methods also as part of the &lt;a href="https://github.com/RickStrahl/Westwind.WebView"&gt;Westwind.WebView library&lt;/a&gt; and the &lt;code&gt;WebViewHandler&lt;/code&gt; class which includes &lt;code&gt;Navigate()&lt;/code&gt; and &lt;code&gt;Reload()&lt;/code&gt; methods with various overloads.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Browser page reloads are common, but unfortunately the WebView2 doesn't make this functionality very straightforward &lt;strong&gt;if you need to do a hard reload that refreshes the page and all of its dependencies&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Luckily there are relatively simple workarounds you can use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interact keyboard shortcuts&lt;/li&gt;
&lt;li&gt;Replacing the URL explicitly&lt;br&gt;
&lt;small&gt;&lt;em&gt;(use if you don't want to blow out your entire cache on &lt;code&gt;Reload())&lt;/code&gt;&lt;/em&gt;&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;CoreWebView2.ClearBrowsingDataAsync()&lt;/code&gt;&lt;br&gt;
&lt;small&gt;&lt;em&gt;(for the most compatible cache busting approach)&lt;/em&gt;&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;CoreWebView2.CallDevToolsProtocolMethodAsync(&amp;quot;Network.clearBrowserCache&amp;quot;)&lt;/code&gt;&lt;br&gt;
&lt;small&gt;&lt;em&gt;(for the most reliable hard cache refresh - but with some environment caveats)&lt;/em&gt;&lt;/small&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All are simple, but not so obvious solutions and you can choose for your specific scenario.&lt;/p&gt;
&lt;p&gt;In my Preview Rendering apps I'm use the Dev Tools approach since I know the Desktop applications have access to the DevTools and because I want to make sure images get refreshed. Finally in my apps all resources are local, and relatively small so blowing the cache is not a problem.&lt;/p&gt;
&lt;p&gt;As always I'm writing this down for future reference, since I'm sure I'll come looking for this information again. Maybe you will too...&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RickStrahl/Westwind.WebView/"&gt;Westwind.WebView Library on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-clearBrowserCache"&gt;DevTools protocols API Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="margin-top: 30px;font-size: 0.8em;
            border-top: 1px solid #eee;padding-top: 8px;"&gt;
    &lt;img src="https://markdownmonster.west-wind.com/favicon.png" style="height: 20px;float: left; margin-right: 10px;"&gt;
    this post created and published with the 
    &lt;a href="https://markdownmonster.west-wind.com" target="top"&gt;Markdown Monster Editor&lt;/a&gt; 
&lt;/div&gt;
&lt;div style='margin: 10px 0px'&gt;&lt;small&gt;© Rick Strahl, West Wind Technologies, 2005-2026&lt;/small&gt;&lt;/div&gt;&lt;div&gt;Posted in &lt;b&gt;&lt;a href='/ShowPosts.aspx?Category=WebView'&gt;WebView&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href='/ShowPosts.aspx?Category=Windows'&gt;Windows&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href='/ShowPosts.aspx?Category=WPF'&gt;WPF&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;/div&gt;
&lt;/small&gt;</description>
    </item>
    <item>
      <title>What the heck is a `\\.\nul` path and why is it breaking my Directory Files Lookup?</title>
      <link>https://weblog.west-wind.com/posts/2025/Dec/08/What-the-heck-is-a-nul-path-and-why-is-it-breaking-my-Directory-Files-Lookup</link>
      <guid isPermaLink="false">5133488_202512082315</guid>
      <pubDate>Mon, 08 Dec 2025 23:15:18 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Dec/08/What-the-heck-is-a-nul-path-and-why-is-it-breaking-my-Directory-Files-Lookup#Comments</comments>
      <slash:comments>8</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=5133488</wfw:commentRss>
      <category>dotnet</category>
      <description>I've been trying to track down an odd bug in my logs related to Null device failures in directory lookups which have been causing application level exceptions. In some odd scenarios these null mappings are showing up for files. In this post I take a look at what they are and how to work around them for this very edge case scenario.</description>
    </item>
    <item>
      <title>Using the new WebView2 AllowHostInputProcessing Keyboard Mapping Feature</title>
      <link>https://weblog.west-wind.com/posts/2025/Aug/20/Using-the-new-WebView2-AllowHostInputProcessing-Keyboard-Mapping-Feature</link>
      <guid isPermaLink="false">4979824_202508210317</guid>
      <pubDate>Thu, 21 Aug 2025 03:17:34 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Aug/20/Using-the-new-WebView2-AllowHostInputProcessing-Keyboard-Mapping-Feature#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4979824</wfw:commentRss>
      <category>WPF</category>
      <category>WebView</category>
      <description>If you've used the WebVIew2 control for a UI interactive Hybrid active you've probably run into some odd keyboard behavior, where some keys cannot be captured properly in the host application or are not forwarded quite the way they normally behave. In the newer releases of the WebView SDK there's a new option called `AllowHostInputProcessing` that allows for forwarding keyboard events more aggressively to the host which fixes some Windows behaviors and introduces some new issues. </description>
    </item>
    <item>
      <title>Fighting through Setting up Microsoft Trusted Signing</title>
      <link>https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing</link>
      <guid isPermaLink="false">4940804_202507210056</guid>
      <pubDate>Mon, 21 Jul 2025 00:56:23 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jul/20/Fighting-through-Setting-up-Microsoft-Trusted-Signing#Comments</comments>
      <slash:comments>38</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4940804</wfw:commentRss>
      <category>Windows</category>
      <category>Security</category>
      <category>Azure</category>
      <description>It's that time of year again to update my CodeSigning certificate, only to find out that the rules have changed since I last did this. Certs now require either a physical hardware key or a online service provides the non-exportable keys to sign binaries along with massive price increases for the privilege. So I decided to give Microsoft's new Trusted CodeSigning service a try, and while that entails all the joy of setting up Azure services, at the and of the day it works and is a considerably more economical way for CodeSigning to work. In this post I describe how to set this up hopefully to help you avoid some of the pain I went through.</description>
    </item>
    <item>
      <title>Centering a WPF TreeViewItem in the TreeView ScrollViewer</title>
      <link>https://weblog.west-wind.com/posts/2025/Jul/15/Centering-a-WPF-TreeViewItem-in-the-TreeView-ScrollViewer</link>
      <guid isPermaLink="false">4934685_202507160423</guid>
      <pubDate>Wed, 16 Jul 2025 04:23:03 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jul/15/Centering-a-WPF-TreeViewItem-in-the-TreeView-ScrollViewer#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4934685</wfw:commentRss>
      <category>WPF</category>
      <description>One of the annoying features of the TreeView in WPF is the inability to easily select and make an item prominently visible. While there is `TreeView.BringIntoView()` it doesn't do a good job dropping the item that the very bottom (or top) of the viewport with no way to center. In this post I show a few helper methods that facilitate this process and a few related tasks with some useful TreeView helpers.</description>
    </item>
    <item>
      <title>Unpacking Zip Folders into Windows Long File Paths</title>
      <link>https://weblog.west-wind.com/posts/2025/Jun/22/Unpacking-Zip-Folders-into-Windows-Long-File-Paths</link>
      <guid isPermaLink="false">4906257_202506221100</guid>
      <pubDate>Sun, 22 Jun 2025 11:00:48 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jun/22/Unpacking-Zip-Folders-into-Windows-Long-File-Paths#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4906257</wfw:commentRss>
      <category>.NET</category>
      <category>Windows</category>
      <description>Ah, long file paths bit me again today - this time with `ZipFile.ExtractToDirectory()` not unzipping long path files, even when specifying long path syntax for the output folder. In this post I briefly review Windows long path issues again, and describe what doesn't work and how to work around this particular problem. While specific to `ExtractToDirectory()` a similar approach might apply to other batch file based operations.</description>
    </item>
    <item>
      <title>Adding Runtime NuGet Package Loading to an Application</title>
      <link>https://weblog.west-wind.com/posts/2025/Jun/09/Adding-Runtime-NuGet-Package-Loading-to-an-Application</link>
      <guid isPermaLink="false">4892294_202506100440</guid>
      <pubDate>Tue, 10 Jun 2025 04:40:37 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jun/09/Adding-Runtime-NuGet-Package-Loading-to-an-Application#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4892294</wfw:commentRss>
      <category>.NET ASP.NET</category>
      <description>It's not a common use case, but if you need need to dynamically add external code at runtime, NuGet packages are the most familiar way for developers to add that functionality besides old-school direct assembly loading. In this post I look at my LiveReloadServer local Web Server tool and how I integrated both external assembly loading and NuGet package support to allow extensibility for the Razor (and Markdown) scripting functionality of LiveReloadServer.</description>
    </item>
    <item>
      <title>Distinguished Name on FileZilla Server Self-Generated Certs</title>
      <link>https://weblog.west-wind.com/posts/2025/Jun/06/Distinguished-Name-on-FileZilla-Server-SelfGenerated-Certs</link>
      <guid isPermaLink="false">4888546_202506062044</guid>
      <pubDate>Fri, 06 Jun 2025 20:44:04 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jun/06/Distinguished-Name-on-FileZilla-Server-SelfGenerated-Certs#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4888546</wfw:commentRss>
      <category>Windows</category>
      <category>FTP</category>
      <description>Renewing Filezilla certificates I've run into a 'huh?' moment a few times trying to renew the self-signed certificates for the Administration interface. Trying the obvious entries of putting in the DNS names results in an error that's not perplexingly is fixed by providing a full Common Name instead.</description>
    </item>
    <item>
      <title>Configuring Microsoft.AI.Extensions with multiple providers</title>
      <link>https://weblog.west-wind.com/posts/2025/May/30/Configuring-MicrosoftAIExtension-with-multiple-providers</link>
      <guid isPermaLink="false">4880955_202505310856</guid>
      <pubDate>Sat, 31 May 2025 08:56:33 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/May/30/Configuring-MicrosoftAIExtension-with-multiple-providers#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4880955</wfw:commentRss>
      <category>.NET</category>
      <description>Microsoft.Extensions.AI is the new base library for creating AI clients in an abstracted way. While the library does a great job with the abstraction of the interfaces it works with, the provider interfaces that create the intial abstractions like IChatClient are a lot less user friendly with hard to discover syntax based on extension methods and different syntax for each provider. In this post I review three providers and how to get them instantiated along with a small streaming example to use them.</description>
    </item>
    <item>
      <title>Lazy Loading the Mermaid Diagram Library</title>
      <link>https://weblog.west-wind.com/posts/2025/May/10/Lazy-Loading-the-Mermaid-Diagram-Library</link>
      <guid isPermaLink="false">4856296_202505110926</guid>
      <pubDate>Sun, 11 May 2025 09:26:29 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/May/10/Lazy-Loading-the-Mermaid-Diagram-Library#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4856296</wfw:commentRss>
      <category>Javascript</category>
      <category>Web</category>
      <description>The Mermaid library is a large beast, and if you're using it selectively in your Web content you probably want to make sure you don't load it unless you actually need it, due to it's download footprint and load time. If you're loading Mermaid with server only code it's pretty straight forward, but if you use it on the client there you may want to delay loading the library until you actually need to display a diagram. </description>
    </item>
    <item>
      <title>WebView2: Waiting for Document Loaded</title>
      <link>https://weblog.west-wind.com/posts/2025/May/06/WebView2-Waiting-for-Document-Loaded</link>
      <guid isPermaLink="false">4847859_202505062150</guid>
      <pubDate>Tue, 06 May 2025 21:50:16 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/May/06/WebView2-Waiting-for-Document-Loaded#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4847859</wfw:commentRss>
      <category>WebView</category>
      <category>Windows</category>
      <category>WPF</category>
      <description>WebBrowser loading is always async and the WebView2 control is no different - in fact it's more complex as there a number of events that need to be handled in order to properly handle loading the control. In this post I describe how you can create a simplified load checking routine, or use the Westwind.WebView library and WebViewHandler to wait on content and process document access using linear `await` syntax.</description>
    </item>
    <item>
      <title>Avoiding WPF Image Control Local File Locking</title>
      <link>https://weblog.west-wind.com/posts/2025/Apr/28/WPF-Image-Control-Local-File-Locking</link>
      <guid isPermaLink="false">4838355_202504282201</guid>
      <pubDate>Mon, 28 Apr 2025 22:01:46 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Apr/28/WPF-Image-Control-Local-File-Locking#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4838355</wfw:commentRss>
      <category>WPF .NET Windows</category>
      <description>WPF locks local images when referenced via a Source attribute. In this post I discuss why this might be a problem and how you can work around it using native XAML and custom binding converter that provides a consolidated approach that includes image caching for better performance of reused images.</description>
    </item>
    <item>
      <title>The Strong ARM of .NET: Wrestling with x64 and Arm64 Desktop App Deployment</title>
      <link>https://weblog.west-wind.com/posts/2025/Apr/18/The-Strong-ARM-of-NET-Wrestling-with-x64-and-Arm64-Desktop-App-Deployment</link>
      <guid isPermaLink="false">4827822_202504190835</guid>
      <pubDate>Sat, 19 Apr 2025 08:35:43 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Apr/18/The-Strong-ARM-of-NET-Wrestling-with-x64-and-Arm64-Desktop-App-Deployment#Comments</comments>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4827822</wfw:commentRss>
      <category>.NET</category>
      <category>Windows</category>
      <description>.NET  works great for cross-platform development making it easy to build apps that are cross-platform and cross-architecture specifically for x64 and Arm64. However, building a distributable application that can install and run out of box on both of these platforms, that's a bit more effort. In this post I discuss some of the gotchas and how to work around them to distribute apps that run out of the gate on both platforms.</description>
    </item>
    <item>
      <title>Using Windows.Media SpeechRecognition in WPF</title>
      <link>https://weblog.west-wind.com/posts/2025/Mar/24/Using-WindowsMedia-SpeechRecognition-in-WPF</link>
      <guid isPermaLink="false">4800107_202503250433</guid>
      <pubDate>Tue, 25 Mar 2025 04:33:00 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Mar/24/Using-WindowsMedia-SpeechRecognition-in-WPF#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4800107</wfw:commentRss>
      <category>WPF</category>
      <category>Windows</category>
      <category>.NET</category>
      <description>Windows has a pretty capable SpeechRecognition engine built-in via Windows Media services. In .NET these features are accessible via the Windows SDK (WinSdk) that expose these Windows features to .NET applications. In this post I discuss how you can integrate these features into a WPF application, and discuss some of the pitfalls along the way that you have to watch out for related to the SDK integration 'features'.</description>
    </item>
    <item>
      <title>Making Html Input Controls Truly ReadOnly</title>
      <link>https://weblog.west-wind.com/posts/2025/Mar/14/Making-Html-Input-Controls-Truly-ReadOnly</link>
      <guid isPermaLink="false">4789670_202503142026</guid>
      <pubDate>Fri, 14 Mar 2025 20:26:04 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Mar/14/Making-Html-Input-Controls-Truly-ReadOnly#Comments</comments>
      <slash:comments>6</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4789670</wfw:commentRss>
      <category>Html</category>
      <category>CSS</category>
      <description>A discussion of how to show readonly controls in user interface and ensuring that they are not UI activated. This post discusses readonly and disabled behavior and how you can make readonly behave better if you choose to use it over disabled.</description>
    </item>
    <item>
      <title>Accessing Windows Settings Dialogs from Code via Shell Commands</title>
      <link>https://weblog.west-wind.com/posts/2025/Mar/13/Accessing-Windows-Settings-Dialogs-from-Code-via-Shell-Commands</link>
      <guid isPermaLink="false">4788723_202503132240</guid>
      <pubDate>Thu, 13 Mar 2025 22:40:22 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Mar/13/Accessing-Windows-Settings-Dialogs-from-Code-via-Shell-Commands#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4788723</wfw:commentRss>
      <category>.NET</category>
      <category>Windows</category>
      <description>Windows has support for an `ms-setting:` Protocol Handler/Uri Scheme that allows you to directly open most Windows settings dialogs directly via simple Url based shell commands.</description>
    </item>
    <item>
      <title>Resolving Paths To Server Relative Paths in .NET Code</title>
      <link>https://weblog.west-wind.com/posts/2025/Mar/08/Resolving-Paths-To-Server-Relative-Paths-in-NET-Code</link>
      <guid isPermaLink="false">4783718_202503090639</guid>
      <pubDate>Sun, 09 Mar 2025 06:39:18 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Mar/08/Resolving-Paths-To-Server-Relative-Paths-in-NET-Code#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4783718</wfw:commentRss>
      <category>ASP.NET</category>
      <description>ASP.NET Core has support for resolving Urls in Controllers and Razor Pages via embedded `~/` links in Views and via `Url.Content()`. But, these features are tied to Controllers or Razor Pages - what if you need to resolve Urls elsewhere, in middleware or even inside of business logic? In this post I describe how you can build a couple of helpers that are more flexible and also provide some additional functionality of resolving site root and relative paths to full site root paths.</description>
    </item>
    <item>
      <title>Inline Confirmations in JavaScript UI</title>
      <link>https://weblog.west-wind.com/posts/2025/Feb/26/Inline-Confirmations-in-JavaScript-UI</link>
      <guid isPermaLink="false">4772830_202502270902</guid>
      <pubDate>Thu, 27 Feb 2025 09:02:10 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Feb/26/Inline-Confirmations-in-JavaScript-UI#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4772830</wfw:commentRss>
      <category>Html</category>
      <category>JavaScript</category>
      <category>ASP.NET</category>
      <description>Confirmation dialogs or modal popups can be annoying in HTML applications. What if you could instead use an inline UI to confirm an operation? In this post I describe a simple way you can use an inline UI to confirm an operation that can be easily implemented with a few lines of code and a couple of binding directives.</description>
    </item>
    <item>
      <title>Retrieving Images from the Clipboard Reliably in WPF Revisited</title>
      <link>https://weblog.west-wind.com/posts/2025/Feb/21/Retrieving-Images-from-the-Clipboard-Reliably-in-WPF-Revisited</link>
      <guid isPermaLink="false">4768057_202502220809</guid>
      <pubDate>Sat, 22 Feb 2025 08:09:36 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Feb/21/Retrieving-Images-from-the-Clipboard-Reliably-in-WPF-Revisited#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4768057</wfw:commentRss>
      <category>WPF</category>
      <category>Windows</category>
      <description>The WPF Clipboard is notoriously bad for retrieving image data, mainly because of the funky behavior of the ImageSource control into which clipboard data is loaded. WPF cuts a lot of corners when retrieving images and there are many scenarios where Clipboard.GetImage() either crashes or doesn't render the supposedly successfully retrieved image. In this post I review some of the challenges and how you can work around the retrieving an ImageSource with an intermediary load of a bitmap in between to provide reliable image retrieval from the clipboard in WPF.</description>
    </item>
    <item>
      <title>Comparing Raw ASP.NET Request Throughput across Versions: 8.0 to 9.0 Edition</title>
      <link>https://weblog.west-wind.com/posts/2025/Jan/19/Comparing-Raw-ASPNET-Request-Throughput-across-Versions-80-to-90-Edition</link>
      <guid isPermaLink="false">4734648_202501192251</guid>
      <pubDate>Sun, 19 Jan 2025 22:51:02 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2025/Jan/19/Comparing-Raw-ASPNET-Request-Throughput-across-Versions-80-to-90-Edition#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4734648</wfw:commentRss>
      <category>.NET ASP.NET</category>
      <description>Once again I'm taking a look at the newish .NET release and how it compares to the previous release - this time .NET 9.0 from .NET 8.0. I'll run my simple load tests to compare performance and also discuss a number of anecdotes from running .NET 9.0 in production apps for the last couple of months.</description>
    </item>
    <item>
      <title>Back to Basics: Using the Parallel Library to Massively Boost Loop Performance</title>
      <link>https://weblog.west-wind.com/posts/2024/Dec/27/Back-to-Basics-Using-the-Parallel-Library-to-Massively-Boost-Loop-Performance</link>
      <guid isPermaLink="false">4712020_202412272337</guid>
      <pubDate>Fri, 27 Dec 2024 23:37:19 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Dec/27/Back-to-Basics-Using-the-Parallel-Library-to-Massively-Boost-Loop-Performance#Comments</comments>
      <slash:comments>8</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4712020</wfw:commentRss>
      <category>.NET</category>
      <category>CSharp</category>
      <description>I recently had another occasion to add Parallel.ForEachAsync() into an application to improve performance of an Http look up operation drastically. When I tweeted a note on X there was quite a bit of response, so I thought I follow up and discuss Parallel use in this use case and when it makes sense to use Parallel in applications.</description>
    </item>
    <item>
      <title>Getting the Current TabItem when the Tab is not selected in WPF</title>
      <link>https://weblog.west-wind.com/posts/2024/Nov/08/Getting-the-Current-TabItem-when-the-Tab-is-not-selected-in-WPF</link>
      <guid isPermaLink="false">4666224_202411090910</guid>
      <pubDate>Sat, 09 Nov 2024 09:10:44 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Nov/08/Getting-the-Current-TabItem-when-the-Tab-is-not-selected-in-WPF#Comments</comments>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4666224</wfw:commentRss>
      <category>WPF</category>
      <description>There's no direct support in WPF to find the control that the mouse is hovering over in Items controls like the TabControl, so if you need to bring up context sensitive information like a context menu or tooltip it takes a little extra effort to get the correct item to work with in this case ContextMenuOpening. </description>
    </item>
    <item>
      <title>Using SQL Server on Windows ARM</title>
      <link>https://weblog.west-wind.com/posts/2024/Oct/24/Using-Sql-Server-on-Windows-ARM</link>
      <guid isPermaLink="false">4648676_202410242159</guid>
      <pubDate>Thu, 24 Oct 2024 21:59:54 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Oct/24/Using-Sql-Server-on-Windows-ARM#Comments</comments>
      <slash:comments>21</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4648676</wfw:commentRss>
      <category>.NET</category>
      <category>SQL Server</category>
      <category>Windows</category>
      <description>I recently got a SnapDragon X Elite ARM device to play with and while I've been impressed with all things that work very well on it, one thing did not install easily: SQL Server. There's no ARM version of SQL Server and the x64 versions don't run on ARM devices. Docker images are also amd64 so that didn't work well either. Turns out you can use LocalDb onin emulation mode, but setting it up is anything but intuitive. In this post I discuss how to get SQL Server to run on a Windows ARM device.</description>
    </item>
    <item>
      <title>Getting the ASP.NET Core Server Hosting Urls at Startup and in Requests</title>
      <link>https://weblog.west-wind.com/posts/2024/Sep/03/Getting-the-ASPNET-Core-Server-Hosting-Urls-at-Startup-and-in-Requests</link>
      <guid isPermaLink="false">4569156_202409040931</guid>
      <pubDate>Wed, 04 Sep 2024 09:31:35 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Sep/03/Getting-the-ASPNET-Core-Server-Hosting-Urls-at-Startup-and-in-Requests#Comments</comments>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4569156</wfw:commentRss>
      <category>asp.net</category>
      <description>Ever need to retrieve an ASP.NET application's hosting Urls? There are million ways to set these URLs but there's no easy fixed location where you can pick the addresses up from. Instead you have to go through a bit of a dance, and use one of two approaches depending on whether you need the addresses during startup or inside of a request.</description>
    </item>
    <item>
      <title>Nuking Local Nuget Package Sources to show newly Published Packages</title>
      <link>https://weblog.west-wind.com/posts/2024/Aug/04/Nuking-Local-Nuget-Package-Sources-to-show-newly-Published-Packages</link>
      <guid isPermaLink="false">4521831_202408042352</guid>
      <pubDate>Sun, 04 Aug 2024 23:52:12 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Aug/04/Nuking-Local-Nuget-Package-Sources-to-show-newly-Published-Packages#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4521831</wfw:commentRss>
      <category>.NET</category>
      <category>NuGet</category>
      <description>Every once in while when I publish a NuGet package and then try to use the published package in another project I end up with a situation where the new package simply is not recognized. Most of the time it shows up after a few minutes, but on more than a few occasions I've stuck waiting for quite a while waiting for the package cache to refresh. Luckily there's a way to nuke the cache and force Nuget to re-read local packages and while that is the nuclear option that requires downloading a lot of packages it works to make your project compile - right now!</description>
    </item>
    <item>
      <title>Create a .NET PlantUML Markdown Render Extension</title>
      <link>https://weblog.west-wind.com/posts/2024/Jul/29/Create-a-NET-PlantUML-Markdown-Render-Extension</link>
      <guid isPermaLink="false">4512301_202407292216</guid>
      <pubDate>Mon, 29 Jul 2024 22:16:35 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jul/29/Create-a-NET-PlantUML-Markdown-Render-Extension#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4512301</wfw:commentRss>
      <category>.NET</category>
      <category>Markdown Monster</category>
      <description>PlantUML is a Web based diagramming markup language that can be used to create diagrams using text descriptions that are rendered into images via a PlantUML server. In this post I describe how you can integrate PlantUML image rendering into your .NET application, specifically from a Markdown rendering perspective as Markdown documents are the most common mechanism that PlantUML output is delivered.</description>
    </item>
    <item>
      <title>Back to Basics: Await a Task with a Timeout</title>
      <link>https://weblog.west-wind.com/posts/2024/Jul/25/Back-to-Basics-Await-a-Task-with-a-Timeout</link>
      <guid isPermaLink="false">4505520_202407252148</guid>
      <pubDate>Thu, 25 Jul 2024 21:48:00 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jul/25/Back-to-Basics-Await-a-Task-with-a-Timeout#Comments</comments>
      <slash:comments>8</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4505520</wfw:commentRss>
      <category>.NET</category>
      <description>Sometimes it's useful to call async methods and be able to stop waiting after a given timeout period. Unfortunately there's no native support on Task to provide this. In this short post I show how you can simulate timeouts and provide a couple of helper methods to make the process generically available.</description>
    </item>
    <item>
      <title>Work around the WebView2 NavigateToString() 2mb Size Limit</title>
      <link>https://weblog.west-wind.com/posts/2024/Jul/22/Work-around-the-WebView2-NavigateToString-2mb-Size-Limit</link>
      <guid isPermaLink="false">4500913_202407230753</guid>
      <pubDate>Tue, 23 Jul 2024 07:53:44 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jul/22/Work-around-the-WebView2-NavigateToString-2mb-Size-Limit#Comments</comments>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4500913</wfw:commentRss>
      <category>WebView</category>
      <description>The WebView2 control's NavigateToString() method has a limit for the string size of 2mb, which can be a problem especially for HTML pages with embedded content. In this post I'll describe how this problem can show up and show a couple of ways to work around the issue.</description>
    </item>
    <item>
      <title>Dealing with Platform Specific Classes and Methods in CrossPlatform .NET</title>
      <link>https://weblog.west-wind.com/posts/2024/Jul/18/Dealing-with-Platform-Specific-Classes-and-Methods-in-CrossPlatform-NET</link>
      <guid isPermaLink="false">4496078_202407190702</guid>
      <pubDate>Fri, 19 Jul 2024 07:02:59 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jul/18/Dealing-with-Platform-Specific-Classes-and-Methods-in-CrossPlatform-NET#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4496078</wfw:commentRss>
      <category>.NET</category>
      <description>If you deal with old .NET library code that is sprinkled with some Windows specific code in places you've likely run into places where the Windows specific code is throwing up unwanted compiler warnings. Sometimes that matters, but often times these warnings are annoyances as these methods are highly unlikely to get called from x-platform code. In this post I describe some annoyances, how you can work around them and eventually fix the issues without throwing everything out the window.</description>
    </item>
    <item>
      <title>C# Version String Formatting</title>
      <link>https://weblog.west-wind.com/posts/2024/Jun/13/C-Version-String-Formatting</link>
      <guid isPermaLink="false">4445887_202406140612</guid>
      <pubDate>Fri, 14 Jun 2024 06:12:37 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jun/13/C-Version-String-Formatting#Comments</comments>
      <slash:comments>9</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4445887</wfw:commentRss>
      <category>.NET</category>
      <category>C#</category>
      <description>I'm tired of trying to format versions for user facing interfaces after fumbling with it again and again. In this short post I show a small helper extension method that lets you configure how to form user friendly version strings to display to end users.</description>
    </item>
    <item>
      <title>Mime Base64 is a Thing?</title>
      <link>https://weblog.west-wind.com/posts/2024/May/26/Mime-Base64-is-a-Thing</link>
      <guid isPermaLink="false">4416829_202405270750</guid>
      <pubDate>Mon, 27 May 2024 07:50:45 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/May/26/Mime-Base64-is-a-Thing#Comments</comments>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4416829</wfw:commentRss>
      <category>.NET</category>
      <description>Ran into an old legacy application recently that required that attached data was preformatted to Mime Base64 which I never even heard of before. Turns out it's a 'url-safe' version of base64 that replaces certain characters that can be present in base64 with 'safe' characters. In this short post I show a small helper that handles several Base64 Mime operations.</description>
    </item>
    <item>
      <title>Speed up your Start Menu by disabling Web Search</title>
      <link>https://weblog.west-wind.com/posts/2024/May/03/Speed-up-your-Start-Menu-by-disabling-Web-Search</link>
      <guid isPermaLink="false">4381163_202405040653</guid>
      <pubDate>Sat, 04 May 2024 06:53:30 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/May/03/Speed-up-your-Start-Menu-by-disabling-Web-Search#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4381163</wfw:commentRss>
      <category>Windows</category>
      <description>If you're like me, you've probably cursed the Windows Start menu from time to time, when it's either very slow to pop up, or in some instances fails to pop up at all when you press the Windows key. This simple tip can drastically improve performance of your Windows Start Menu by simply disabling Web search. </description>
    </item>
    <item>
      <title>ASP.NET Core Hosting Module with Shadow Copy Not Starting: Separate your Shadow Copy Folders!</title>
      <link>https://weblog.west-wind.com/posts/2024/Apr/28/ASPNET-Core-Hosting-Module-with-Shadow-Copy-Not-Starting-Separate-your-Shadow-Copy-Folders</link>
      <guid isPermaLink="false">4372790_202404290106</guid>
      <pubDate>Mon, 29 Apr 2024 01:06:35 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Apr/28/ASPNET-Core-Hosting-Module-with-Shadow-Copy-Not-Starting-Separate-your-Shadow-Copy-Folders#Comments</comments>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4372790</wfw:commentRss>
      <category>ASP.NET IIS</category>
      <description>I recently ran into a major failure related to Shadow Copying for an ASP.NET Web app on IIS which was caused by corruption of the Shadow Copy directories. The app starts with the dreaded white ANCM Error page and event log entries that point at missing application folders. It turns out that this is caused by interference of multiple applications using the same shadow copy folder. In this post I describe the problem and how to work around it.</description>
    </item>
    <item>
      <title>Programmatic Html to PDF Generation using the WebView2 Control with .NET</title>
      <link>https://weblog.west-wind.com/posts/2024/Mar/26/Html-to-PDF-Generation-using-the-WebView2-Control</link>
      <guid isPermaLink="false">4319131_202403270759</guid>
      <pubDate>Wed, 27 Mar 2024 07:59:52 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Mar/26/Html-to-PDF-Generation-using-the-WebView2-Control#Comments</comments>
      <slash:comments>14</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4319131</wfw:commentRss>
      <category>.NET ASP.NET Windows</category>
      <description>In this post I describe how to use the Microsoft WebView2 control to automate HTML to PDF generation generically for any kind of Windows application, including services. We'll look at the WebView and it's printing functionality and some of the intricacies that are involved in hosting the WebView control outside of a desktop application context to provide unattended mode even in service context.</description>
    </item>
    <item>
      <title>Comparing Raw ASP.NET Request Throughput across Versions</title>
      <link>https://weblog.west-wind.com/posts/2024/Mar/08/Comparing-Raw-ASPNET-Request-Throughput-across-Versions</link>
      <guid isPermaLink="false">4285010_202403081021</guid>
      <pubDate>Fri, 08 Mar 2024 10:21:08 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Mar/08/Comparing-Raw-ASPNET-Request-Throughput-across-Versions#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4285010</wfw:commentRss>
      <category>ASP.NET</category>
      <description>When I set up a new machine I usually use a small ASP.NET test project to get a feel of performance of the machine and when that happens I also take a moment to compare performance across recent versions of .NET to see how things are improving - and improved they have. Both due to the new hardware I'm using but also ASP.NET continues to bump up performance in every new version that comes out. In this post I describe a simple project with minimal do nothing requests to test the ASP,.NET pipeline locally and how to test these request as well as discussing the results.</description>
    </item>
    <item>
      <title>Reading Raw ASP.NET Request.Body Multiple Times</title>
      <link>https://weblog.west-wind.com/posts/2024/Feb/20/Reading-Raw-ASPNET-RequestBody-Multiple-Times</link>
      <guid isPermaLink="false">4257209_202402202308</guid>
      <pubDate>Tue, 20 Feb 2024 23:08:09 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Feb/20/Reading-Raw-ASPNET-RequestBody-Multiple-Times#Comments</comments>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4257209</wfw:commentRss>
      <category>ASP.NET</category>
      <description>Some time ago I wrote about accessing raw request body content in ASP.NET Core which ended up being one of the most popular posts on this blog. But I failed to mention one major caveat: By default Request.Body can only be read once. In this post I discuss why frequently when you need raw Request.Body access you actually need to read the body more than once, and you can enable that functionality and deal with the caveats of doing so.</description>
    </item>
    <item>
      <title>Sharing Tab Missing in Windows 11 Folder Properties</title>
      <link>https://weblog.west-wind.com/posts/2024/Jan/10/Sharing-Tab-Missing-in-Windows-11-Folder-Properties</link>
      <guid isPermaLink="false">4187850_202401102254</guid>
      <pubDate>Wed, 10 Jan 2024 22:54:27 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jan/10/Sharing-Tab-Missing-in-Windows-11-Folder-Properties#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4187850</wfw:commentRss>
      <category>Windows</category>
      <description>For some unfathomable reason, Windows 11 has removed the Sharing Tab on the Explorer Properties Context menu by default. The Sharing Tab allows you to shared folders and drives for remote access. In this post I discuss how to get the Sharing Tab back and also touch on how to make sure your machine can actually accept remote connections so you can share your folders and drives.</description>
    </item>
    <item>
      <title>Working around the WPF ImageSource Blues</title>
      <link>https://weblog.west-wind.com/posts/2024/Jan/03/Working-around-the-WPF-ImageSource-Blues</link>
      <guid isPermaLink="false">4169641_202401040536</guid>
      <pubDate>Thu, 04 Jan 2024 05:36:29 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2024/Jan/03/Working-around-the-WPF-ImageSource-Blues#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4169641</wfw:commentRss>
      <category>WPF</category>
      <category>Windows</category>
      <description>The WPF Image control and its ImageSource property can be problematic if you are loading a lot of images in a list. Depending on where you load images from, and how, you can very easily get bogged down with slow, blocking load operations, and memory leaks when the controls are released. In this post I describe a couple of specific problems I ran into loading a sizable list of images from files and show a few ways how to avoid the potential pitfalls related to ImageSource peculiarities.</description>
    </item>
    <item>
      <title>Integrating OpenAI Image Generation into a .NET Application</title>
      <link>https://weblog.west-wind.com/posts/2023/Dec/21/Integrating-OpenAI-Image-Generation-into-a-NET-Application</link>
      <guid isPermaLink="false">4146698_202312212222</guid>
      <pubDate>Thu, 21 Dec 2023 22:22:07 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Dec/21/Integrating-OpenAI-Image-Generation-into-a-NET-Application#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4146698</wfw:commentRss>
      <category>.NET</category>
      <category>AI</category>
      <description>Image Generation AIs are proving to be very good at creating images that can be used for all sorts of purposes. In this article I discuss how you can integrate image generation right into your own .NET applications using the OpenAI REST API. In addition I'll show how you can integrated this functionality into a larger application and discuss some general thoughts on image AI usage based on some of the experiences from a developer/non-designer user perspective.</description>
    </item>
    <item>
      <title>Embedding a minimal ASP.NET Web Server into a Desktop Application</title>
      <link>https://weblog.west-wind.com/posts/2023/Nov/27/Embedding-a-minimal-ASPNET-Web-Server-into-a-Desktop-Application</link>
      <guid isPermaLink="false">4108957_202311280842</guid>
      <pubDate>Tue, 28 Nov 2023 08:42:36 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Nov/27/Embedding-a-minimal-ASPNET-Web-Server-into-a-Desktop-Application#Comments</comments>
      <slash:comments>3</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4108957</wfw:commentRss>
      <category>ASP.NET</category>
      <category>.NET</category>
      <category>WPF</category>
      <category>Windows</category>
      <description>Did you ever need to embed a Web Server into a non-Web application? In this post I describe how you can use host ASP.NET in a non-Web application and specifically in a WPF desktop app. What do you need, how is it different and some of the issues that you need to consider if you want to use ASP.NET in your non-Web applications.</description>
    </item>
    <item>
      <title>Save Files With Elevated Permissions on UnauthorizedAccessException</title>
      <link>https://weblog.west-wind.com/posts/2023/Nov/03/Save-Files-With-Elevated-Permissions-on-UnauthorizedAccessException</link>
      <guid isPermaLink="false">4073408_202311031948</guid>
      <pubDate>Fri, 03 Nov 2023 19:48:56 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Nov/03/Save-Files-With-Elevated-Permissions-on-UnauthorizedAccessException#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4073408</wfw:commentRss>
      <category>Windows</category>
      <category>WPF</category>
      <description>If you have an application that generically allows you to edit and save files, you might on rare occasions need to save files in locations that where a regular user account does not have permissions to save. Rather than failing wouldn't it be nice to let the user know and optionally allow saving with elevated permissions? In this post I describe the workflow and implementation on how to do just that.</description>
    </item>
    <item>
      <title>Caching your WebView Environment to manage multiple WebView2 Controls</title>
      <link>https://weblog.west-wind.com/posts/2023/Oct/31/Caching-your-WebView-Environment-to-manage-multiple-WebView2-Controls</link>
      <guid isPermaLink="false">4068979_202310312210</guid>
      <pubDate>Tue, 31 Oct 2023 22:10:59 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Oct/31/Caching-your-WebView-Environment-to-manage-multiple-WebView2-Controls#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4068979</wfw:commentRss>
      <category>WebView</category>
      <category>WPF</category>
      <category>Windows</category>
      <description>I've been struggling with rare WebView initialization errors in one of my applications, that have been difficult to debug and track down. After a lot of trial and error I discovered that the problem is related to WebView Environment instantiations that might be stepping on each other. In this post I describe the problem and a solution that involves creating a single WebView Environment and reusing it for all WebView initialization.</description>
    </item>
    <item>
      <title>Rolling Forward to Major Versions in .NET</title>
      <link>https://weblog.west-wind.com/posts/2023/Oct/02/Rolling-Forward-to-Major-Versions-in-NET</link>
      <guid isPermaLink="false">4028801_202310030812</guid>
      <pubDate>Tue, 03 Oct 2023 08:12:27 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Oct/02/Rolling-Forward-to-Major-Versions-in-NET#Comments</comments>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4028801</wfw:commentRss>
      <category>.NET</category>
      <description>.NET Core has sophisticated policies that allows your applications that are compiled to specific versions of the .NET Runtime can roll forward to newer versions. You can specify what part of the version to roll forward and that generally works well, except for preview releases which require an extra step.</description>
    </item>
    <item>
      <title>IIS Error 500.19 with ASP.NET Core Application</title>
      <link>https://weblog.west-wind.com/posts/2023/Sep/19/IIS-Error-50019-with-ASPNET-Core-Application</link>
      <guid isPermaLink="false">4009938_202309191002</guid>
      <pubDate>Tue, 19 Sep 2023 10:02:02 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Sep/19/IIS-Error-50019-with-ASPNET-Core-Application#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=4009938</wfw:commentRss>
      <category>ASP.NET</category>
      <description>Running on IIS locally is pretty rare, but if for some odd reason you decide to run IIS locally on your dev machine you might find yourself getting a 500.19 error which relates to an issue in the web.config configuration. The solution is simple enough: Make sure the ASP.NET Core Hosting Module is installed. In this post I describe in more detail what the problem is and why you need a seemingly superfluous extra install to get IIS and ASP.NET Core to cooperate on local dev machine.</description>
    </item>
    <item>
      <title>Dotnet Tool Component not found on the Mac</title>
      <link>https://weblog.west-wind.com/posts/2023/Sep/11/Dotnet-Tool-Component-not-found-on-the-Mac</link>
      <guid isPermaLink="false">3999259_202309120205</guid>
      <pubDate>Tue, 12 Sep 2023 02:05:47 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Sep/11/Dotnet-Tool-Component-not-found-on-the-Mac#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=3999259</wfw:commentRss>
      <category>.NET</category>
      <description>I've run into this problem a few times: I install a new Mac OS and then install the .NET SDK. A bit later I install a dotnet tool using `dotnet tool install -g` and then try to run it, only to find out that the SDK is not able find it. This post is a note to self on how to fix the pathing for .NET tools to be found correctly and to be able to run your dotnet tools.</description>
    </item>
    <item>
      <title>Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET</title>
      <link>https://weblog.west-wind.com/posts/2023/Aug/15/Map-Physical-Paths-with-an-HttpContextMapPath-Extension-Method-in-ASPNET</link>
      <guid isPermaLink="false">3964818_202308160202</guid>
      <pubDate>Wed, 16 Aug 2023 02:02:14 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Aug/15/Map-Physical-Paths-with-an-HttpContextMapPath-Extension-Method-in-ASPNET#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=3964818</wfw:commentRss>
      <category>ASP.NET Core</category>
      <category>ASP.NET</category>
      <description>ASP.NET Core doesn't have a Server.MapPath() method as classic ASP.NET had, and getting at the root path in Core is a little bit more involved than in those older versions. In this post I describe how to find the application Content and Web root folders and describe a MapPath() helper that simulates the old behavior.</description>
    </item>
    <item>
      <title>A WPF Statusbar Control</title>
      <link>https://weblog.west-wind.com/posts/2023/Aug/08/A-WPF-Statusbar-Control</link>
      <guid isPermaLink="false">3954615_202308082321</guid>
      <pubDate>Tue, 08 Aug 2023 23:21:45 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Aug/08/A-WPF-Statusbar-Control#Comments</comments>
      <slash:comments>1</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=3954615</wfw:commentRss>
      <category>WPF</category>
      <description>Statusbar controls are boring, but because of the way that they are used there are a number of caveats like ensuring the UI updates even in linear code, allowing for timeouts of status messages and resetting to default, and to provide some visual clues to draw attention to the status messages displayed. In this post I talk about a custom status bar control and helper that make it super easy to use a new status bar control or attach additional functionality to an existing status bar.</description>
    </item>
    <item>
      <title>Getting the .NET Desktop Runtime Installed with a Custom Runtime Checker and Installer</title>
      <link>https://weblog.west-wind.com/posts/2023/Jun/21/Getting-the-NET-Desktop-Runtime-Installed-with-a-Custom-Runtime-Checker-and-Installer</link>
      <guid isPermaLink="false">3892897_202306220429</guid>
      <pubDate>Thu, 22 Jun 2023 04:29:41 GMT</pubDate>
      <dc:creator>Rick Strahl</dc:creator>
      <comments>https://weblog.west-wind.com/posts/2023/Jun/21/Getting-the-NET-Desktop-Runtime-Installed-with-a-Custom-Runtime-Checker-and-Installer#Comments</comments>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>https://weblog.west-wind.com/commentrss.aspx?id=3892897</wfw:commentRss>
      <category>.NET</category>
      <category>WPF</category>
      <category>Windows</category>
      <category>Desktop</category>
      <description>I've recently moved my Markdown Monster Desktop Application to .NET 7.0 and I had to make a decision on how to get the Runtime installed or packaged with my application. In this post I review the different deployment modes, the plus's and cons and the solution I ended up with which was to build a custom install wrapper that can check and install the runtime if not already present from an Installer or interactively.,</description>
    </item>
  </channel>
</rss>