WebSpark.Bootswatch

A .NET Razor Class Library that integrates Bootswatch themes into ASP.NET Core applications.

Overview

WebSpark.Bootswatch is a .NET Razor Class Library that integrates Bootswatch themes into ASP.NET Core applications. This library allows you to easily switch between multiple Bootstrap themes at runtime.

Last Updated: May 18, 2025

Installation

Prerequisites

Before installing WebSpark.Bootswatch, ensure you have:

  • .NET SDK 8.0 or later
  • An ASP.NET Core web application (MVC or Razor Pages)
  • Basic understanding of Bootstrap framework

Installation Options

Via NuGet Package Manager
Install-Package WebSpark.Bootswatch
Via .NET CLI
dotnet add package WebSpark.Bootswatch
Via Project Reference
<ItemGroup>
  <ProjectReference Include="..\WebSpark.Bootswatch\WebSpark.Bootswatch.csproj" />
</ItemGroup>

Basic Setup

1. Register Services

Add the necessary using statements at the top of your Program.cs file:

using WebSpark.Bootswatch;
using WebSpark.Bootswatch.Provider;
using WebSpark.Bootswatch.Model;

Register Bootswatch services in the dependency injection container:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddRazorPages(); // or AddControllersWithViews() for MVC

// Register Bootswatch services
builder.Services.AddBootswatchStyles();

var app = builder.Build();

2. Configure Middleware

Configure the HTTP request pipeline to use Bootswatch static files:

// Configure middleware
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Register Bootswatch static files middleware BEFORE standard static files
app.UseBootswatchStaticFiles();

// Standard static files middleware
app.UseStaticFiles();

app.UseRouting();
app.UseAuthorization();
app.MapRazorPages(); // or MapControllerRoute() for MVC

app.Run();
Important: app.UseBootswatchStaticFiles() must be called before app.UseStaticFiles() to ensure proper serving of embedded static files.

Usage

Including Styles in Layout

Add the following to your _Layout.cshtml file:

@inject WebSpark.Bootswatch.Model.IStyleProvider StyleProvider
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    
    <!-- Reference the current Bootswatch theme -->
    <link rel="stylesheet" href="@StyleProvider.GetCurrentStyleUrl()" />
    
    <!-- Your other CSS references -->
</head>
<body>
    <!-- Your layout content -->
</body>
</html>

Theme Switching Implementation

1. Update Service Registration

Register the theme switcher services in your Program.cs file:

// Add Bootswatch theme switcher services (includes StyleCache)
builder.Services.AddBootswatchThemeSwitcher();

// Later in the pipeline configuration:
// Use all Bootswatch features (includes StyleCache and static files)
app.UseBootswatchAll();

2. Update Layout

Modify your _Layout.cshtml file to use the theme switcher:

<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebSpark.Bootswatch Documentation</title>


    <link id="bootswatch-theme-stylesheet" rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css" />
    <script src="/_content/WebSpark.Bootswatch/js/bootswatch-theme-switcher.js"></script>
</head>

3. Add Theme Switcher Component

Add the theme switcher component where you want it to appear in your layout:

Note: The theme switcher component is now included in the WebSpark.Bootswatch package, so you don't need to create your own implementation.

4. For More Details

See the Theme Switcher Example page for a complete example or refer to the Theme Switcher Guide.

Available Themes

WebSpark.Bootswatch includes all standard Bootswatch themes plus some custom themes:

Default Bootstrap
Cerulean
Cosmo
Cyborg
Darkly
Flatly
Journal
Litera
Lumen
Lux
Materia
Minty
Morph
Pulse
Quartz
Sandstone
Simplex
Sketchy
Slate
Solar
Spacelab
Superhero
United
Vapor
Yeti
Zephyr
Mom (Custom)
Texecon (Custom)
Note: To see these themes in action, use the theme switcher in the top navigation bar.

Advanced Configuration

1. Create StyleCache Service

Create a StyleCache.cs file in your Services folder to cache Bootswatch styles:

using Microsoft.Extensions.Logging;
using WebSpark.Bootswatch.Model;
using WebSpark.Bootswatch.Provider;

namespace WebSpark.Bootswatch.Demo.Services;

public class StyleCache
{
    private readonly List<StyleModel> _styles = new();
    private readonly IServiceProvider _serviceProvider;
    private bool _isInitialized = false;
    private readonly object _lockObject = new();
    private Task? _initializationTask = null;
    private readonly ILogger<StyleCache>? _logger;

    public StyleCache(IServiceProvider serviceProvider, ILogger<StyleCache>? logger = null)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }

    // Get all styles method (abbreviated)
    public List<StyleModel> GetAllStyles()
    {
        // Implementation details...
        return _styles.ToList(); 
    }

    // Get specific style method
    public StyleModel GetStyle(string name)
    {
        var styles = GetAllStyles();
        return styles.FirstOrDefault(s => s.name == name) ?? new StyleModel();
    }

    // Initialize styles in background
    public void StartInitialization()
    {
        // Implementation details...
    }

    // Load styles from provider
    public async Task LoadStyles()
    {
        // Implementation details...
    }

    // Static initialization helper
    public static void InitializeInBackground(IServiceProvider serviceProvider)
    {
        var styleCache = serviceProvider.GetRequiredService<StyleCache>();
        styleCache.StartInitialization();
    }
}

2. Register and Initialize StyleCache

Add these lines to your Program.cs file:

// Register StyleCache as a singleton
builder.Services.AddSingleton<StyleCache>();
builder.Services.AddLogging();

var app = builder.Build();

// Initialize StyleCache in the background without blocking application startup
StyleCache.InitializeInBackground(app.Services);

3. Custom HTTP Request Implementation (Optional)

If you need custom HTTP request handling:

// Use custom implementation for HTTP requests
builder.Services.AddScoped<IHttpRequestResultService, HttpRequestResultService>();

4. Custom Theme Implementation

You can implement your own themes by creating a custom StyleProvider:

public class CustomStyleProvider : IStyleProvider
{
    private readonly List<StyleModel> _styles = new();
    
    public CustomStyleProvider()
    {
        // Add your custom themes
        _styles.Add(new StyleModel { Name = "custom-theme", DisplayName = "Custom Theme", Url = "/css/custom-theme.css" });
    }
    
    // Implement the interface methods
}

Caching Implementation

Add Cache Control Headers

Enhance performance by adding cache control headers for static files:

app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        // Cache static files for 1 day
        ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=86400");
    }
});

For better performance, consider using a caching service:

public class StyleCache : IStyleCache
{
    private readonly IMemoryCache _cache;
    
    public StyleCache(IMemoryCache cache)
    {
        _cache = cache;
    }
    
    public BootswatchStyle GetCachedStyle(string styleName)
    {
        return _cache.GetOrCreate($"style_{styleName}", entry => {
            entry.SlidingExpiration = TimeSpan.FromHours(1);
            // Load and return the style
        });
    }
}

Troubleshooting

Theme Not Loading

  1. Check Network Requests
    Use browser developer tools (F12) to inspect network requests for CSS files.
  2. Verify Middleware Order
    Ensure UseBootswatchStaticFiles() is called before UseStaticFiles().
  3. Check Cache Initialization
    Verify StyleCache initializes correctly by checking application logs.
  4. Clear Browser Cache
    Hard refresh with Ctrl+F5 to clear cached CSS files.

Missing Themes

  1. Check API Connection
    Ensure your application can reach the Bootswatch API.
  2. Inspect Logs
    Look for any error messages during StyleCache initialization.
  3. Add Fallback Themes
    Modify the StyleCache to include default themes if API calls fail.

Add Logging for Troubleshooting

Add middleware to log theme loading issues:

app.Use(async (context, next) =>
{
    var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
    var path = context.Request.Path.Value;

    // Log all requests that look like they're trying to access theme CSS files
    if (path?.Contains("bootstrap.min.css") == true)
    {
        logger.LogInformation("Requested theme CSS: {Path}", path);
    }

    await next();

    // Log if the response is a 404 for theme CSS files
    if (context.Response.StatusCode == 404 && path?.Contains("bootstrap.min.css") == true)
    {
        logger.LogWarning("404 Not Found for theme CSS: {Path}", path);
    }
});

Best Practices

Non-Blocking Initialization

Initialize the StyleCache in the background to avoid blocking application startup.

Error Handling

Always provide fallback styles if theme loading fails.

User Preferences

Store user theme preferences in cookies or user profile for persistence.

Performance Optimization

Cache theme styles to reduce API calls and improve page load times.

CDN Fallbacks

Implement fallbacks for CDN-hosted theme files in case of CDN failures.

Responsive Testing

Test themes across different screen sizes to ensure responsive behavior.

License

WebSpark.Bootswatch is licensed under the MIT License.

View License