2026-07-16

How to Self-Host Tabler Icons in a .NET Project Using LibMan (No NPM or CDNs!)

How to Self-Host Tabler Icons in a .NET Blazor Project Using LibMan (No NPM or CDNs!)

When building a modern .NET Blazor application using Tailwind CSS or daisyUI, you often need a rich icon set like Tabler Icons. While using a CDN link is easy, it introduces external dependencies. On the other hand, installing Node.js/NPM just for icons adds massive overhead to a clean .NET project.

The ultimate solution is LibMan (Library Manager). It allows you to download and self-host the exact icon files you need locally on your server without NPM or live CDN runtimes.

Here is a step-by-step guide to setting this up and updating it for future projects.


Step 1: Install the LibMan Build Package

To ensure your icons automatically download during project compilation or deployment pipelines, add the LibMan build tool to your Blazor project (.csproj) file:

<ItemGroup>
  <PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
</ItemGroup>

(Alternatively, right-click your project in Visual Studio, choose Manage NuGet Packages, and install Microsoft.Web.LibraryManager.Build).


Step 2: Create the libman.json Configuration

Create a file named libman.json directly in the root folder of your Blazor project and paste the following configuration.

Note: In newer versions of the Tabler package, production assets live inside a dist/ subfolder. We also deliberately exclude the old .woff file, as modern browsers only need the highly-compressed .woff2 font file.

{
  "version": "3.0",
  "defaultProvider": "unpkg",
  "libraries": [
    {
      "library": "@tabler/icons-webfont@3.44.0",
      "destination": "wwwroot/lib/tabler-icons/",
      "files": [
        "dist/tabler-icons.min.css",
        "dist/fonts/tabler-icons.woff2"
      ]
    }
  ]
}

Step 3: Trigger the Local File Download

Simply saving the JSON file will not immediately download the files. You need to explicitly run the restore command:

  1. In Visual Studio, right-click on your libman.json file in the Solution Explorer.
  2. Click Restore Client-Side Libraries.
  3. Verify your wwwroot folder. You will see a newly populated local folder path: wwwroot/lib/tabler-icons/dist/.

(If you are using VS Code or the CLI, simply run libman restore in your project terminal).


Step 4: Link the Local CSS in Your Blazor Shell

Your Blazor application needs to know where to find the styles. Open your root HTML shell file:

  • For Blazor Web Apps (.NET 8+): Open Components/App.razor
  • For Blazor Server/WASM (Older versions): Open wwwroot/index.html or Pages/_Host.cshtml

Add the local CSS link tag inside the <head> section:

<head>
    <!-- Local Tabler Icons (Downloaded via LibMan) -->
    <link rel="stylesheet" href="lib/tabler-icons/dist/tabler-icons.min.css" />
    
    <!-- Your existing site/tailwind styles -->
    <link rel="stylesheet" href="css/site.css" />
</head>

Step 5: Use Icons in Your Components

Now you can jump into any Blazor component (.razor) and display icons alongside your daisyUI classes using standard <i> tags:

<button class="btn btn-primary">
    <i class="ti ti-plus-circle text-lg"></i>
    Add New Record
</button>

How to Update to a New Version in the Future

When a newer version of Tabler Icons is released, you do not need to rewrite your code or hunt down CDN scripts.

  1. Go to the @tabler/icons-webfont npm page to find the latest version number string.
  2. Open your libman.json file and change the version tag in the library name string (e.g., change @3.44.0 to the new version).
  3. Right-click libman.json and select Clean Client-Side Libraries, then click Restore Client-Side Libraries.

LibMan will automatically clear the old assets and safely grab the brand-new ones directly into your project!


Note: If you change your file to "3.0" and encounter restore errors during compilation, it means your current project build tools require the standard "1.0" schema. Simply switch it back to "1.0" to resolve the validation check.

2026-06-19

How to Fix Blazor Kestrel Error: Unsupported Compression Method for Static HTML

If you are building a Blazor application and need to serve static HTML files directly (like a design system, documentation, or legacy pages), you probably tossed them straight into your wwwroot folder.

Everything works beautifully in your production environment. But when you hit F5 to test locally, you are greeted with a nasty System.IO.InvalidDataException crash in your Kestrel server logs:

fail: Microsoft.AspNetCore.Server.Kestrel Connection id "...", Request id "...": An unhandled exception was thrown by the application. System.IO.InvalidDataException: The archive entry was compressed using an unsupported compression method. at System.IO.Compression.Inflater.Inflate(FlushCode flushCode) ... at Microsoft.AspNetCore.Watch.BrowserRefresh.ResponseStreamWrapper.DisposeAsync()

The Root Cause: Local Browser Refresh Tooling

At first this looked strange, because I was not using any custom compression code. The problem turned out to be related to the development-time BrowserLink / Browser Refresh pipeline in ASP.NET Core, not the HTML file itself.

This error is not a bug in my code, nor is it an issue with the HTML files. It is caused by a known development-time bug in ASP.NET Core's Hot Reload / Browser Refresh middleware.

When you run your project locally, Visual Studio (version 2026) or the dotnet watch CLI dynamically injects a tiny JavaScript snippet into your HTML responses. This script allows your browser to automatically refresh when you save changes in your code.

However, when you directly request a static .html file from wwwroot in development, the BrowserRefreshMiddleware attempts to read the underlying data stream to inject its script. If the framework compresses or buffers this static stream under certain local configurations, the middleware misinterprets the compression headers, corrupts the stream, and crashes Kestrel.

In .NET 10, static assets can be processed through the SDK's static web assets pipeline. In development, BrowserLink tries to inject its refresh script into HTML responses. That is usually fine for normal HTML, but if the response is being served through the compressed static asset path, the browser refresh middleware can fail while trying to rewrite it.

That is why the issue appeared only for HTML files and not for images like:

	https://localhost:7075/assets/logo/blazor.png

Images do not get HTML script injection, so they do not hit the same BrowserLink path.

Why does it work in Production?

This issue completely vanishes in production because Hot Reload and Browser Refresh tools are entirely stripped out when your app runs outside of the Development environment.


How to Fix It

Since the problem lies entirely within local development tooling, you can fix it by telling ASP.NET Core to skip loading the browser tools for your debugging profile.

Solution 1: Update launchSettings.json (Recommended)

The cleanest fix is to append an environment variable to your local launch profile. This fixes the issue for anyone pulling down your repository without breaking their global IDE settings.

  1. Open your project's Properties/launchSettings.json file.
  2. Locate the profile you use to run the application (e.g., "https" or "http").
  3. Under the "environmentVariables" object, add "ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES": "Microsoft.WebTools.BrowserLink.Net".

Your configuration file should look like this:

"profiles": { "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy", "applicationUrl": "https://localhost:7075;http://localhost:5242", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES": "Microsoft.WebTools.BrowserLink.Net" } } }

Solution 2: Disable via Visual Studio Settings

If you prefer a global fix across your IDE without altering your source control files, you can turn off the features directly inside Visual Studio:

  1. Click the dropdown arrow next to the Hot Reload button (the fire icon 🔥) in the top toolbar and uncheck Enable Hot Reload on File Save.
  2. Click the dropdown arrow next to the Browser Link icon in the toolbar and uncheck Enable Browser Link.

Other quick fixes or debugging (use wisely in Production env):

  1. Clear browser cache and rebuild
    • Close the browser entirely.
    • Delete bin/ and obj/ folders locally.
    • In Visual Studio: Build → Clean Solution, then Build → Build Solution.
    • Run the app fresh (F5).

  2. Disable gzip compression for static files temporarily (test if it's the culprit)
    • Open Program.cs.
    • Look for lines with .UseResponseCompression() or gzip middleware.
    • Temporarily comment them out or add a condition to skip .html files.
    • Rebuild and test.

  3. Added this to [YOUR_PROJECT.csproj]:
    • <DisableBuildCompression>true</DisableBuildCompression>
      or
      <DisableBuildCompression Condition="'$(Configuration)' == 'Debug'">true</DisableBuildCompression>

Summary

When serving raw HTML assets straight out of wwwroot, local stream manipulation by .NET's developer tools can accidentally break payload compression. By excluding BrowserLink.Net from your development startup assemblies, you bypass the buggy middleware entirely, making your local development environment behave exactly like your stable production server.

2026-06-18

How to Install OpenAI Codex CLI on Windows (and Fix 404 Not Found Errors)

Setting up your terminal environment for local AI-assisted engineering tools is amazing—until your initial installation command hits a roadblock. If you attempted to set up OpenAI Codex and were blocked by an registry error, you are not alone.

The Problem: npm error code E404

When running a guessed or outdated package command in the Windows Command Prompt, the npm registry throws a missing resource exception:

C:\Users\User>npm install -g @openai/codex-cli npm error code E404 npm error 404 Not Found - GET https://npmjs.org - Not found npm error 404 The requested resource '@openai/codex-cli@*' could not be found...

Why this happens: The package identifier name @openai/codex-cli does not exist on the npm server. The core executable CLI logic is bundled directly inside the foundational engine scope name.

The Solution: Step-by-Step Installation Guide

Follow these steps to clean up your environment registry context and download the correct global binaries securely:

  1. Run the Correct Package Command: Open your terminal window and point npm to the official, integrated framework tool distribution location:
    npm install -g @openai/codex@latest
  2. Verify Package Linkage Success: Once terminal dependency resolution completes, it will report the package structural allocation:
    added 7 packages in 31s
  3. Query the System Shell Mapping: Confirm your system execution PATH variables accurately point to the newly registered node engine variables by checking the deployment version:
    codex --version
    You will see the active system architecture footprint print out cleanly:
    codex-cli 0.141.0


Launching Your Agent Environment

Now that the CLI is correctly linked to your terminal profile, you can open up your local interactive development session instantly by inputting:

codex --interactive

💡 Troubleshooting Tips for AI IDE Engineers

Missing Binary Fallbacks: On isolated Windows machines, if your global npm prefix scripts are blocked by Execution Policies, bypass npm completely. Head to the official repository releases, download codex-x86_64-pc-windows-msvc.exe, drop it into your local directory, and rename it to codex.exe.

Google Antigravity Mapping: If you are moving this workflow into the Google Antigravity IDE workspace, you don't even need npm dependencies! Use the internal extension channel path instead:

/plugin marketplace add obra/superpowers-marketplace
/plugin install superpowers@superpowers-marketplace

2026-06-08

How to Crawl and Download Your Localhost Site as Static HTML on Windows

Have you ever built a beautiful local web application and needed to extract it into static HTML files? Maybe you want to backup a local database-driven project, preview a static build, or archive a site.

If you are on Windows and tried to install:

winget install GNU.Wget
and you may get error message:
No package found matching input criteria.

or typing a quick wget command into PowerShell like:

wget.exe --no-check-certificate --recursive --page-requisites --adjust-extension --convert-links --no-parent https://localhost:7249/
You probably got smacked with a nasty, confusing error message:
Invoke-WebRequest : A positional parameter cannot be found that accepts argument '--recursive'.

Don't worry, you didn't write the command wrong. You just fell into a classic Windows PowerShell trap! Here is exactly why that happens and how to easily crawl your https://localhost site with the real tool in under two minutes.


The PowerShell identity crisis: Why wget failed

By default, Windows PowerShell uses aliases (shortcuts). When you type wget, PowerShell doesn't actually run the famous GNU Wget data-grabbing tool. Instead, it secretly runs its own built-in command called Invoke-WebRequest.

Because Microsoft’s tool doesn't understand advanced web crawling flags like --recursive or --page-requisites, it crashes instantly.

To fix this, we need to install the authentic, full-powered version of GNU Wget on your system.


Step 1: Install the real GNU wget tool

Windows 10 and 11 come with a built-in package manager called winget. We will use it to pull down the correct software.

  1. Open your PowerShell window.
  2. Run this exact command to target the authentic application ID:
winget install -e --id JernejSimoncic.Wget

(If prompted to accept source agreements, simply type Y and press Enter).


Step 2: Refresh your terminal environment

Once the installer finishes, the system needs to recognize the newly added software paths.

  1. Close your current PowerShell window completely.
  2. Open a brand new PowerShell window.
  3. Navigate to the exact folder where you want your static HTML files to drop:
cd "C:\Users\YourUsername\Desktop\MyStaticSite"

Step 3: Run the magic localhost crawl command

Now we execute the crawl. To bypass PowerShell's fake shortcut, we explicitly add .exe to our command.

If your local development site is running on an HTTPS port (e.g., https://localhost:7249/), execute this line:

wget.exe --no-check-certificate --recursive --page-requisites --adjust-extension --convert-links --no-parent https://localhost:7249/

What do all those flags actually do?

  • --no-check-certificate: Crucial for local dev environments! It forces the crawler to ignore self-signed SSL/TLS certificate warnings.
  • --recursive: Tells the tool to map out your site layout and follow local links automatically.
  • --page-requisites: Grabs all assets required to render the site properly offline (CSS stylesheets, background images, and scripts).
  • --adjust-extension: Automatically appends .html to raw local routing endpoints so your web browser can open them like normal files.
  • --convert-links: Rewrites the internal code paths so your local files point to each other instead of trying to look for the live web server.

How to uninstall it

Open your PowerShell window and run:

winget uninstall JernejSimoncic.Wget

The Result

Once the script finishes downloading, check your directory! You will find a brand-new folder named localhost:7249.

Inside, you will find a fully functional, offline-ready index.html alongside neatly organized folders containing your JavaScript, style sheets, and local media assets. You can open index.html in any browser, and your site layout will render completely intact without requiring your local development server to be turned on!

Developer Note: Keep in mind that static crawlers like wget download raw elements rendered by the server. If your localhost application depends entirely on runtime client-side frameworks (like React or Angular components fetching API data dynamically after the page loads), you may need to use an automated browser script like Puppeteer instead.

2026-01-06

Why Your SQL Server 2025 Isn't Connecting: Diagnosing Network and Instance-Specific Errors in SQL Server Management Studio (SSMS) New UI

If you've ever tried to connect to a SQL Server and received an error message like "Could not open a connection to SQL Server" or "Named Pipes Provider: error 40," you know how frustrating it can be. But don’t worry—these errors are common, and fixing them is often straightforward once you understand the root causes.


This issue has become far more common in recent versions of SQL Server Management Studio (SSMS) 21 and 25, not because the problem is new, but because the new UI has changed in ways that actively hide critical connection options. 
  • Expand the Connection Window: You may notice that the "Browse" section is hidden. To fix this, expand the connection window to see the full interface.

  • Adjust the Window Size: Look at the top-right corner of the SSMS window. Drag the edges of the window to resize it so that you can see the "Browse" section and hierarchy more clearly.

  • Select the Server: Once you resize the window, you should see the hierarchy on the left under "Local." The "Server Name" field will now be visible, allowing you to select the appropriate server.

  • Choose the Correct Server: Click on your server, in this case, it should show something like LAPTOP-XXXXX\SQLEXPRESS2025.