interval(1000).subscribe(() => {
this._getLatest().subscribe(latest => {
//...
});
});
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
Insert into a MsSQL table that only has auto-generated columns
INSERT INTO table_name DEFAULT VALUES
New angular app is missing environment.ts and environment.prod.ts
The ng new
command no longer automatically includes environments. You must run the following:
ng g environments
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>
Display enums as strings in Swagger/Swashbuckle (.net6)
// Program.cs
builder.Services.AddControllers().AddJsonOptions(opt =>
{
opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
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
Do not ignore case with git cli
git config --global core.ignorecase false
Show environmental PATH variable in Windows cmd / terminal
echo %PATH:;=&echo.%
Assert DoesNotThrow in XUnit
// Act
var ex = await Record.ExceptionAsync(() => _thing.DoSomethingAsync());
// Assert
Assert.Null(ex);
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.