Skip to main content

How To Create a Custom UserStore in ASP.NET Core 6

· One min read
Mark Burton
Software Engineer & Technical Writer
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();

builder.Services.AddTransient<IUserStore<ApplicationUser>, DirectUserStore<ApplicationUser>>();

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-custom-storage-providers?view=aspnetcore-6.0

https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/security/authentication/identity-custom-storage-providers/sample/CustomIdentityProviderSample

Making pizza in my Ooni Koda 12

· 2 min read
Mark Burton
Software Engineer & Technical Writer

I love pizza but nothing you can buy from the shop comes close to freshly made pizza and delivery is usually getting cold by the time it arrives. Luckily for Christmas I received an Ooni Koda 12 (Thanks Caitriona), just connect the bottle of gas turn it on and after 15 minutes you have a 400°C oven ready to cook a pizza in only 90 seconds. Ooni have great recipes on their website for Classic Pizza Dough and Classic Pizza Sauce but the dough recipe doesn't seem to be quite right for the Ooni Koda 12, the bases just seem too big for the peels, but this could be my lack of knowledge with making bases, but I find a little less is better and I only usually want 2 pizzas each time I use the oven. ## My Tweaked Recipe The proportions remain the same, but the accuracy of the proportions are all important. :::primary 242g “00” flour 2.8g instant dried yeast (3.7g active dried yeast, 8g fresh yeast) 48.5ml boiled water 97ml cold water 7.2g salt ::: For everything else follow the Classic Pizza Dough instructions for 2 perfectly sized pizzas for your Ooni Koda 12.

Centralizing VSTO add in exception management with postsharp 6

· 3 min read
Mark Burton
Software Engineer & Technical Writer

After much reading around trying to find the best way to implement a global exception handler for a VSTO add-in on social msdn, stackoverflow and the Add-in Express forum I came across this solution using postsharp, this was the best solution I found but was 11 years old and relevant to postsharp 2, the library has changed a lot since then and the PostSharp.Laos namespace no longer exists as explained the postsharp support forum. ## The Solution in PostSharp 6 Happily this is still possible with PostSharp Community and is well documented in the postsharp handling exceptions documentation. First create a class which inherits from OnExceptionAspect for example VstoUnhandledExceptionAttribute. csharp using Microsoft.Extensions.Logging; using PostSharp.Aspects; using PostSharp.Serialization; namespace MarkZither.KimaiDotNet.ExcelAddin \\\{ [PSerializable] public class VstoUnhandledExceptionAttribute : OnExceptionAspect \{ public override void OnException(MethodExecutionArgs args) { ExcelAddin.Globals.ThisAddIn.Logger.LogCritical(args.Exception, "Handled by postsharp OnExceptionAspect"); args.FlowBehavior = FlowBehavior.Return; \\} } } This step will vary depending on how you are doing logging in your VSTO Add-In, I chose to use Microsoft.Extensions.Logging, while it arrived with .NET Core it is a .NETStandard 2.0 library and compatible all the way back to .NETFramework 4.6.1. csharp private void ThisAddIn_Startup(object sender, System.EventArgs e) \\{ instantiate and configure logging. Using serilog here, to log to console and a text-file. var loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory(); var loggerConfig = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.File("c:\\temp\\logs\\myapp.txt", rollingInterval: RollingInterval.Day) .CreateLogger(); loggerFactory.AddSerilog(loggerConfig); // create logger and put it to work. var logProvider = loggerFactory.CreateLogger<ThisAddIn />(); logProvider.LogDebug("debiggung"); Logger = logProvider; Configure PostSharp Logging to use Serilog LoggingServices.DefaultBackend = new MicrosoftLoggingBackend(loggerFactory); Globals.ThisAddIn.ApiUrl = Settings.Default?.ApiUrl; Globals.ThisAddIn.ApiUsername = Settings.Default?.ApiUsername; this.Application.WorkbookActivate += Application_WorkbookActivate; this.Application.WorkbookOpen += Application_WorkbookOpen; \} There is one important line in the logging setup which differs to the PostSharp Logging documentation at the time of writing, LoggingServices.DefaultBackend = new MicrosoftLoggingBackend(loggerFactory); which needs using PostSharp.Patterns.Diagnostics.Backends.Microsoft;. This is also useful for trace logging which I will explain further in the next section. Now decorate methods or entire classes with the [VstoUnhandledException] attribute and every exception will be handled by the OnException method. ## Bonus functionality in PostSharp community As I had logging working I also made use of the features of PostSharp Logging

First add a postsharp.config file, to comply with the license it is required to set the LoggingDeveloperMode to true. Be sure it has the Build Action set to Content so that it is copied to the output directory.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
<Property Name="LoggingDeveloperMode" Value="True" />
</Project>

This still gives you 24 hours of trace logging after every publish of your VSTO Add-In and full tracing while debugging.

To control what is logged create a class called GlobalAspects, this is explained in the Adding logging to your projects section.

using PostSharp.Patterns.Diagnostics;
using PostSharp.Extensibility; [assembly: Log(AttributePriority = 1, AttributeTargetMemberAttributes = MulticastAttributes.Protected | MulticastAttributes.Internal | MulticastAttributes.Public)]
[assembly: Log(AttributePriority = 2, AttributeExclude = true, AttributeTargetMembers = "get_*")]
``` Now the logging will contain all the entry and exits from methods along with the parameters which were passed, providing valuable debug information for free for a whole day after pushing out and update to the Add-In.

My First Skydive @ LuxFly

· 3 min read
Mark Burton
Software Engineer & Technical Writer

For a birthday present I received a voucher to do an indoor skydive at LuxFly at the Luxembourg and Belgium border. Thanks to Covid 19 lockdowns I had another birthday before I could actually make use of the Falcon9 experience. ## Arrival As Covid restrictions were still in place there were not many people there when I arrived, but the staff were very welcoming and efficient finding my booking, checking me in and explaining how things would work. I was early so had time to watch some experienced people flying around, hovering in a seated position, doing headstands and slow motion backflips, sometimes it reminded me of wire work in a Wuxia movie. I remember it something like this...

or more far fetched a bit of Money Magic

## The group I was surprised when I noticed that an RTL camera crew had turned up for my skydive. Unfortunately, despite the fact that there only being 2 of us in the group at that point, the camera was for the other person, who, based on the car outside was there for "de Journal". ## The Briefing After being greeted by our instructor, Lane, we were shown a short video explaining the basics of the skydive, the "simple instructions" were: * relax, Lane will help guide you into the correct position.

  • 2 straight fingers means straighten your legs
  • bent fingers means bend your legs
  • finger pointing up means look upwards That's it! Simple, right? ## The Reality I was assured I was good for a first timer, after 3 flights of 1 minute 20 seconds each I was able to hover without assistance, spin left and right by moving my hands a little, move forward and back by straightening and bending my legs and control myself up and down to some extent by pushing my hips through or straightening my body. In truth that also included belly flopping into the floor and crashing into the window and crumpling a little which caused me to drop quickly and get caught by Lane before I hit the floor again, not to mention the far from elegant wrestling to get me to the door at the end of my first go. Somehow when you are in free fall those simple instructions I mentioned earlier become much more difficult, my eyes saw 2 straight fingers, but it took an age to convince my legs to move. ## The Grand Finale The HighFly, this was truly a heart in mouth stomach turning experience which I can't wait to do again.

https://www.tvlux.be/video/info/arlon-le-luxfly-skydive-a-ouvert-ses-portes_34978.html

KimaiDotNet based Office Add-ins

· 2 min read
Mark Burton
Software Engineer & Technical Writer

As of v1.0.0.0 released on 09032023 the VSTO is signed with an open source code signing cert from Certum this should mean the installation is automatically trusted. If you installed a version before v1.0.0.0 you must uninstall it before installing v1.0.0.0 as the change in signing cert will prevent the upgrade working. Until I get a real certificate you will need to install this self-signed certificate as a trusted root certification authority to be able to install the add-in. Download Excel Add-in ## Create an API password in Kimai

warning

WARNING!!! If you try and login with your normal password it will fail!

Create an API Password in Kimai ## Set the API credentials in the Excel Add-in Set the API credentials in the Excel Add-in ## Save the API credentials to activate the sync Set the API credentials in the Excel Add-in ## Usage of the Add-in For now the Add-in only supports reading existing timesheets and adding new ones, and editing of timesheets will need to be done in Kimai. ## Questions and suggestions The GitHub repo can be found at the KimaiDotNet on GitHub. ### Milestones Follow the Milestones. ### Issues Create any bugs or suggestions on GitHub Issues. ### Discussions Start a discussion on the GitHub Discussions.

Reset Forgotten Domain Admin Password

· 3 min read
Mark Burton
Software Engineer & Technical Writer

Following a series of errors I found myself in a very similar situation to that described by Rob Beekmans, just without the excuse of a bout of flu. But it was just a lab environment so The basic mistakes I made were: * Only having a single domain admin in the domain.

  • Setting up a DSRM password but not testing it
  • Creating a single snapshot of the VM over 2 years ago
  • Allowing Windows update to reboot the machine with the new password unsaved in the vault.
  • Using Hyper-V with an external Virtual Switch, but that is a that is for a different post
  • Using a keyboards with different layouts to type passwords So there was no reason to find myself in this position really, but having ended up there and having found Robs post it looked like the solution was still quite easy, however I am running Windows Server 2019 Core, so there is not GUI and therefore no UTILMAN.exe. ## The Recovery Boot using the installation media, choose Repair your computer, Troubleshoot and Command Prompt. You will now be in the command prompt at X:\Sources. To find your Windows install change directory cd /d c:\Windows\System32 Where Rob suggests to overwrite UTILMAN.exe with cmd.exe that is not possible in Windows Server Core, instead we can replace LogonUI.exe ``` copy LogonUI.exe LogonUI.exe.BAK copy CMD.EXE LogonUI.exe
Answer yes when asked if you want to overwrite LogonUI.exe and then reboot normally.  ```
shutdown /r /t 1
``` When it reboots you will be taken straight to `cmd.exe`, you can now set the Administrator password with the command ```
net user Administrator "new password"
``` Boot again using the installation media to change the file names back ```
copy LogonUI.exe.BAK LogonUI.exe
del LogonUI.exe.BAK
``` Reboot a final time and login with your new Administrator password ## Other options
Various blogs suggest it is possible to get to safe mode using F8 or Ctrl+Shift+Alt+F8 from a cold boot.
https:/www.surfacetablethelp.com201801how-to-use-f8-key-to-boot-hyper-v-vm-into-safe-mode-on-windows-10.html I was not able to make that work reliably, in fact it worked once and caused much frustration trying to make it happen again. I found 2 more reliable ways to get to the safe boot menu:
boot from the installation media to access to troubleshoot menu and boot to a command prompt. At the command prompt type the following command to enable to boot menu. ```
bcdedit /set displaybootmenu yes
``` The next command sets the timeout after which the boot will continue to the OS, 5 second should be plenty to press F8 without adding excessive time to the boot. ```
bcdedit /set timeout 5
``` It is then possible to login with the Test it, shut it down, cold boot it, test it again
https:/docs.microsoft.comen-ustroubleshootwindows-serveridentityreset-directory-services-restore-mode-admin-pwd https:/docs.microsoft.comen-ustroubleshootazurevirtual-machinescannot-connect-rdp-azure-vm#:~:text=The%20remote%20computer%20that%20you,the%20System%20Properties%20dialog%20box.

First Look at Project Tye

· 3 min read
Mark Burton
Software Engineer & Technical Writer
PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> tye deploy --interactive
Loading Application Details...
Verifying kubectl installation...
Drats! 'deploy' failed: Cannot apply manifests because kubectl is not installed.
``` ```
C:\WINDOWS\system32>choco install kubernetes-cli
Chocolatey v0.10.15
Installing the following packages:
kubernetes-cli
By installing you accept licenses for the packages.
Progress: Downloading kubernetes-cli 1.20.2... 100% kubernetes-cli v1.20.2 [Approved]
kubernetes-cli package files install completed. Performing other installation steps.
The package kubernetes-cli wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Note: To confirm automatically next time, use '-y' or consider:
choco feature enable -n allowGlobalConfirmation
Do you want to run the script?([Y]es[A]ll - yes to all[N]o[P]rint): y Extracting 64-bit C:\ProgramData\chocolatey\lib\kubernetes-cli\tools\kubernetes-client-windows-amd64.tar.gz to C:\ProgramData\chocolatey\lib\kubernetes-cli\tools...
C:\ProgramData\chocolatey\lib\kubernetes-cli\tools
Extracting 64-bit C:\ProgramData\chocolatey\lib\kubernetes-cli\tools\kubernetes-client-windows-amd64.tar to C:\ProgramData\chocolatey\lib\kubernetes-cli\tools...
C:\ProgramData\chocolatey\lib\kubernetes-cli\tools ShimGen has successfully created a shim for kubectl.exe The install of kubernetes-cli was successful. Software installed to 'C:\ProgramData\chocolatey\lib\kubernetes-cli\tools' Chocolatey installed 11 packages. See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log). C:\WINDOWS\system32>cd C:\Source\GitRepos\SwaggerAndHealthCheckBlog C:\Source\GitRepos\SwaggerAndHealthCheckBlog>tye deploy --interactive
Loading Application Details...
Verifying kubectl installation...
Drats! 'deploy' failed: Cannot apply manifests because kubectl is not installed. C:\Source\GitRepos\SwaggerAndHealthCheckBlog>kubectl version --client
Client Version: version.Info\\{Major:"1", Minor:"20", GitVersion:"v1.20.2", GitCommit:"faecb196815e248d3ecfb03c680a4507229c2a56", GitTreeState:"clean", BuildDate:"2021-01-13T13:28:09Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"windowsamd64"\} C:\Source\GitRepos\SwaggerAndHealthCheckBlog>cd %USERPROFILE% C:\Users\mburton>mkdir .kube C:\Users\mburton>cd .kube C:\Users\mburton\.kube>New-Item config -type file
'New-Item' is not recognized as an internal or external command,
operable program or batch file. C:\Users\mburton\.kube>pwsh PowerShell 7.0.3 Copyright (c) Microsoft Corporation. All rights reserved. https:/aka.mspowershell Type 'help' to get help. A new PowerShell stable release is available: v7.1.0 Upgrade now, or check out the release page at: https:/aka.msPowerShell-Release?tag=v7.1.0 PS C:\Users\mburton\.kube> New-Item config -type file Directory: C:\Users\mburton\.kube Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 07022021 00:36 0 config PS C:\Users\mburton\.kube> cd C:\Source\GitRepos\SwaggerAndHealthCheckBlog\
PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> tye deploy --interactive
Loading Application Details...
Verifying kubectl installation...
Drats! 'deploy' failed: Cannot apply manifests because kubectl is not installed.
PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> Install-Script -Name 'install-kubectl' -Scope CurrentUser -Force
PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> install-kubectl.ps1 c:\kubectl
==>Getting download link from https:/kubernetes.iodocstaskstoolsinstall-kubectl/
==>analyzing Downloadlink
==>starting Download from https:/dl.k8s.ioreleasev1.20.0binwindowsamd64kubectl.exe using Bitstransfer
==>starting 'c:\kubectl\kubectl.exe version'
Client Version: version.Info\\{Major:"1", Minor:"20", GitVersion:"v1.20.0", GitCommit:"af46c47ce925f4c4ad5cc8d1fca46c7b77d13b38", GitTreeState:"clean", BuildDate:"2020-12-08T17:59:43Z", GoVersion:"go1.15.5", Compiler:"gc", Platform:"windowsamd64"\}
Unable to connect to the server: dial tcp [::1]:8080: connectex: No connection could be made because the target machine actively refused it. You can now start kubectl from c:\kubectl\kubectl.exe
copy your remote kubernetes cluster information to C:\Users\mburton\.kubeconfig PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> tye deploy --interactive
Loading Application Details...
Verifying kubectl installation...
Drats! 'deploy' failed: Cannot apply manifests because kubectl is not installed.
PS C:\Source\GitRepos\SwaggerAndHealthCheckBlog> kubectl
kubectl controls the Kubernetes cluster manager. Find more information at: https:/kubernetes.iodocsreferencekubectloverview/
``` Tye picked random ports while the project app config already specified ports.
https:/github.comdotnettyeissues178