Error: [/usr/share/dotnet/host/fxr] does not exist

When

Occurs when running dotnet publish --configuration Release or dotnet run

Cause

conflict between the microsoft and ubuntu package repository when dotnet was installed

Solution

Remove all installed dotnet packages

sudo apt remove dotnet* aspnetcore* netstandard*

create a dotnet preference file in /etc/apt/preferences.d with a name like dotnet.pref

Package: *
Pin: origin "packages.microsoft.com"
Pin-Priority: 1001

reinstall dotnet

sudo apt update
sudo apt install -y dotnet-sdk-6.0

Set static IP in linux

determine the name of your network interface

ip a

make a backup of the netplan configuration

sudo cp /etc/netplan/01-network-manager-all.yaml /etc/netplan/01-network-manager-all.yaml.backup

edit the config file

sudo vim.tiny /etc/netplan/01-network-manager-all.yaml

make the following changes, replacing “interface_name” with the intended interface

network:
  version: 2
  renderer: networkd
  ethernets:
    interface_name:
      addresses:
        - 192.168.1.101/24
      nameservers:
        addresses: [8.8.8.8]
      routes:
        - to: default
          via: 192.168.1.1

try the new configuration

sudo netplan try

If all is good, press ENTER

Disable the Windows “Shake” feature

Shaking the mouse while dragging another window’s title bar minimizes all other Windows. The UI to disable this “feature” is no longer obvious and I was able to disable it by making the following registry change. Note: This worked even on a gpo machine since it only modified CURRENT_USER.

registry location

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced

Add the following DWORD key with value 1

DisallowShaking 

Angular pipe to replace characters in a string

Generate a new pipe using the Angular CLI

ng g pipe pipes/replace

Code inside the new pipe (pipes/replace.pipe.ts)

...
transform(input: string, from: string, to: string): string {
   const regEx = new RegExp(from, 'g');
   return input.replace(regEx, to);
}

Usage

// page.component.html
// replaces underscores with spaces
...
<span>{{ myString | replace:'_':' '}}</span>

Mock a non-singleton Angular service in a component unit test

describe('MyComponent', () => {
  let mockService: jasmine.SpyObj<MyService>;

  beforeEach(async () => {
    mockService = jasmine.createSpyObj<MyService>(['download']);

    await TestBed.configureTestingModule({
    ...
    }).overrideComponent(MyComponent, {
      set: {
        providers: [
          { provide: MyService, useValue: mockService }]
      }
  }).compileComponents();

  beforeEach(() => {
    ...
  });

  it('should create', () => {
    ...
  });
});

Add theme switching to Angular Material

// styles.scss
$dark-theme: mat.define-dark-theme(
    vars.$primaryPalette, 
    vars.$accentPalette, 
    vars.$warnPalette);

$light-theme: mat.define-light-theme(
    vars.$primaryPalette,
    vars.$accentPalette,
    vars.$warnPalette);

.light-theme {
  @include mat.all-component-themes($light-theme);
}

.dark-theme {
  @include mat.all-component-themes($dark-theme);
}

// app.component.ts
constructor(
  private _settingsService: SettingsService,
   @Inject(DOCUMENT) private _document: Document) { }

  ngOnInit(): void {
    this._settingsService.theme$.subscribe(theme => {

      if (theme === Themes.DARK) {
        this._setDarkTheme();
      } else {
        this._setLightTheme();
      }
    });
  }

  private _setDarkTheme(): void {
    this._document.documentElement.classList.add(Themes.DARK);
    this._document.documentElement.classList.remove(Themes.LIGHT);
  }

  private _setLightTheme(): void {
    this._document.documentElement.classList.add(Themes.LIGHT);
    this._document.documentElement.classList.remove(Themes.DARK);
  }

This is just a summary, so some of the more trivial parts are omitted.

ref: https://octoperf.com/blog/2021/01/08/angular-material-multiple-themes

Configuration Extension Examples

AutoMapper Configuration

using AutoMapper;
using Christopher.Snay.Sample.Configuration.AutoMapperProfiles;
using Christopher.Snay.Sample.Configuration.AutoMapperProfiles.Dtos;
using Microsoft.Extensions.DependencyInjection;

namespace Christopher.Snay.Sample.Configuration
{
	public static class AutoMapperConfiguration
	{
		public static void AddAutoMapperConfiguration(this IServiceCollection services)
		{
			services.AddSingleton(new MapperConfiguration(config =>
			{
				config.AddProfile<SampleMapperProfile1>();
				config.AddProfile<SampleMapperProfile2>();		
			}).CreateMapper());
		}
	}
}

CORS Configuration

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace Christopher.Snay.Sample.Configuration
{
	public static class CorsConfiguration
	{
		public static IApplicationBuilder UseCorsConfiguration(this IApplicationBuilder app)
		{
			return app.UseCors("CorsPolicy");
		}

		public static IServiceCollection AddCorsConfiguration(this IServiceCollection services)
		{
			var origins = new List<string>
			{
				"http://localhost:4200",
				
				"http://sample-server",
			};

			return services.AddCors(options =>
			{
				options.AddPolicy("CorsPolicy", builder =>
				{
					builder
						.WithOrigins(origins.ToArray())
						.AllowAnyMethod()
						.AllowAnyHeader()
						.AllowCredentials();
				});
			});
		}
	}
}

HttpClientFactory Configuration

using System.Net.Http.Headers;
using System.Net.Mime;
using Christopher.Snay.Sample.Services.RetailerServices;
using Microsoft.Extensions.DependencyInjection;

namespace Christopher.Snay.Sample.Configuration
{
	public static class HttpConfiguration
	{
		public static void AddHttpClientConfiguration(this IServiceCollection services)
		{
			services.AddHttpClient(nameof(ISampleService1), x => x.BaseAddress
				= new Uri("https://www.api.sample.com/search"));

			services.AddHttpClient(nameof(ISampleService2), x => x.BaseAddress
				= new Uri("https://www.api.sample2.com/search"));

			services.AddHttpClient(nameof(ISampleService3), x =>
			{
				x.BaseAddress = new Uri("https://www.api.sample3.com/search");
				x.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue("Mozilla", "5.0")));
				x.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
				x.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
				x.DefaultRequestHeaders.Host = "www.sample.com";
				x.DefaultRequestHeaders.Connection.Add("keep-alive");
				x.DefaultRequestHeaders.Add("cookie", "Bearer ABC123");
			}
		}
	}
}

Scrape rendered HTML with .NET6 C#

using HtmlAgilityPack;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.PhantomJS;

namespace Christopher.Snay.Sample.Services.Scrapers
{
	internal class ChromeScraper : IChromeScraper
	{
		public HtmlDocument ScrapeHtml(Uri url)
		{
			return ScrapeHtml(url.ToString());
		}

		public HtmlDocument ScrapeHtml(string url)
		{
			HtmlDocument doc = new();

			using (PhantomJSDriverService driverService = PhantomJSDriverService.CreateDefaultService())
			{
				driverService.HideCommandPromptWindow = true;
				driverService.LoadImages = false;
				driverService.IgnoreSslErrors = true;

				driverService.Start();

				using IWebDriver driver = new ChromeDriver();

				driver.Navigate().GoToUrl(url);

				Thread.Sleep(3000);

				doc.LoadHtml(driver.PageSource);
			}

			return doc;
		}
	}

	public interface IChromeScraper
	{
		HtmlDocument ScrapeHtml(string url);
		HtmlDocument ScrapeHtml(Uri url);
	}
}

Requirements – The following executables must be in /bin

  • phantonjs.exe
  • chrome.exe
  • chromedriver.exe
  • + the chrome portable binaries directory, currently named \107.0.5304.88
<!-- To copy directly to bin without being placed in a sub-folder -->
<ItemGroup>
	<ContentWithTargetPath Include="Assets\phantomjs.exe">
		<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
		<TargetPath>phantomjs.exe</TargetPath>
	</ContentWithTargetPath>
	<ContentWithTargetPath Include="Assets\chrome.exe">
		<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
		<TargetPath>chrome.exe</TargetPath>
	</ContentWithTargetPath>
	<ContentWithTargetPath Include="Assets\chromedriver.exe">
		<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
		<TargetPath>chromedriver.exe</TargetPath>
	</ContentWithTargetPath>

	<None Include="Assets\phantomjs.exe" />
	<None Include="Assets\chrome.exe" />
	<None Include="Assets\chromedriver.exe" />
</ItemGroup>

I’ve used Chrome portable to avoid having to install Chrome. If Chrome is installed, the chrome.exe steps can probably be skipped.