Allen Conway
Exploring all things software engineering and beyond...
Tuesday, February 6, 2024
How to Fix the GitHub Copilot Chat Error: 'Cannot read properties of undefined (reading 'split')'
Sunday, November 12, 2023
Blazor WebAssembly Lazy Loading Changes from .NET 7 to .NET 8
.csproj file updates
Unable to find 'EngineAnalyticsWebApp.TestLazy.dll' to be lazy loaded later. Confirm that project or package references are included and the reference is used in the project" error on build
Friday, November 3, 2023
Dealing with Time Skew and SAS Azure Blob Token Generation: 403 Failed to Authenticate Error
Status 403: The request is not authorized to perform this operation using this permission
Here is a sample of code that might throw this error in which the startsOn value is set to the current time:
Before you start double checking all of the user permissions in Azure and going through all the Access Control and Role Assignments in Blob Storage (assuming you do have them configured correctly), this might be a red herring for a different issue with the startsOn value for the call to GetUserDelegationKeyAsync(). The problem is likely with clock skew and differences in times from the server and client.
It is documented in SAS best practices from the Azure docs (found here), the following issue with clock skew and how to remedy the issue:
Be careful with SAS start time. If you set the start time for a SAS to the current time, failures might occur intermittently for the first few minutes. This is due to different machines having slightly different current times (known as clock skew). In general, set the start time to be at least 15 minutes in the past. Or, don't set it at all, which will make it valid immediately in all cases. The same generally applies to expiry time as well--remember that you may observe up to 15 minutes of clock skew in either direction on any request. For clients using a REST version prior to 2012-02-12, the maximum duration for a SAS that does not reference a stored access policy is 1 hour. Any policies that specify a longer term than 1 hour will fail.
There is a simple fix for this as instructed to modify the startsOn value to be either not set or 15 minutes (or greater) in the past. With this updated code, the 403 error is fixed and will proceed as expected.
Wednesday, October 18, 2023
Fixing PowerShell Scripting Error in C# Code: "Exception calling ""ToString"" with ""0"" argument(s). There is no Runspace available to run scripts in this thread."
New-Service -Name "MyWindowsService" -BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe"
When running this in a PowerShell terminal, it will generate the following output which as documented is an object representing the new service:Status Name DisplayName
------ ---- -----------
Stopped MyWindowsService MyWindowsService
This is actually helpful output for a human, and maybe even for logging, bu when running this same command in C# via a PowerShell instance, the command will technically work, but you'll get the following cryptic error:
"The following exception occurred while retrieving the string: ""Exception calling ""ToString"" with ""0"" argument(s): ""There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.ServiceName""""", System.Object,System.ServiceProcess.ServiceController,System.WeakReference`1[System.Management.Automation.Runspaces.TypeTable], System.Management.Automation.PSObject+AdapterSet,None,System.Management.Automation.DotNetAdapter,"",System.Management.Automation.PSObject+AdapterSet, System.ServiceProcess.ServiceController,System.ServiceProcess.ServiceController,"PSStandardMembers {DefaultDisplayPropertySet}",False,False,False,False,False, "","",NoneOK not very helpful. It took a while but I deduced the output from the New-Service cmdlet was causing this issue. There are 2 ways I found to handle this.
- Suppress the Output: Since this is running in C# without human intervention, pipe in the option to suppress the output if you are not logging it or using it for some meaningful purpose. Remember, you can still get the status by using Get-Service to inspect the newly installed service, as opposed to reading the output. Use the updated command to accomplish this:
New-Service -Name "MyWindowsService" -BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe" | out-null
- Return the Output to a Variable: The other option is simply to return the output of the cmdlet typically for use to inspect. This could be done with the following updated statement:
Keep in mind he return value is of type System.ServiceProcess.ServiceController, so you can use that as needed.$newServiceResult = New-Service -Name "MyWindowsService" -BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe"
Thursday, September 21, 2023
How to Disable Either Classic or YAML Pipelines in Azure DevOps (ADO)
If you have pipelines in Azure DevOps that you don't want to trigger automatically either because they are legacy and remain for reference, not currently being used, or just need to temporarily disable, there are different ways to accomplish this based on the type of pipeline.
Classic Pipelines
- Select the Classic Pipeline and press the 'Edit' button
YAML Pipelines
- Select the Classic Pipeline and press the 'Edit' button
- Select the ellipsis (3 dots) in the top-right hand corner, and select 'Settings'
- Select the 'Disabled' radio button, and press 'Save'
- The pipeline is confirmed disabled via the label next to the name
Wednesday, September 20, 2023
Leveraging IntelliSense for Azure DevOps YAML Pipelines in Visual Studio Code
Friday, July 28, 2023
Reading Environment Variables, AppSettings, LocalSettings, and User Secrets Seamlessly Across Environments in ASP.NET
For a sample use case, we might have a database connection string with sensitive information that needs to work seamlessly in code for local, Dev, QA, Stage, Prod, etc. without a lot of special hooks or handling in code. One way to handle this in the cloud regardless of deployment resource or setup is to expose a single key name with unique value per-environment. This can be configured via scripting in deployment pipelines per environment to take care of the DevOps side of this equation. However in code we want this single-read of a key to work in all environments. This is where in .NET the Configuration provider offered in Microsoft.Extensions.Configuration works so well.
CosmosDbConnectionString | AccountEndpoint=https://cosmos-acct-{env}-eus-001.documents.azure.com:443/;AccountKey=abc123...
- Create your own environment variable on your local OS with the identical key name and whatever value you choose
- Add the identical key and again whatever value you require as a 'User Secret' within Visual Studio or VS Code (VS Code requires an extension download to work with secrets)
Using the default configuration, the EnvironmentVariablesConfigurationProvider loads configuration from environment variable key-value pairs after reading appsettings.json, appsettings.Environment.json, and Secret manager. Therefore, key values read from the environment override values read from appsettings.json, appsettings.Environment.json, and Secret manager.
The : delimiter doesn't work with environment variable hierarchical keys on all platforms. For example, the : delimiter is not supported by Bash. The double underscore (__), which is supported on all platforms, automatically replaces any : delimiters in environment variables.
CosmosDb__ConnectionString