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.
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
Install-Package WebSpark.Bootswatch
dotnet add package WebSpark.Bootswatch
<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();
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:
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:
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
- Check Network Requests
Use browser developer tools (F12) to inspect network requests for CSS files. - Verify Middleware Order
EnsureUseBootswatchStaticFiles()
is called beforeUseStaticFiles()
. - Check Cache Initialization
Verify StyleCache initializes correctly by checking application logs. - Clear Browser Cache
Hard refresh with Ctrl+F5 to clear cached CSS files.
Missing Themes
- Check API Connection
Ensure your application can reach the Bootswatch API. - Inspect Logs
Look for any error messages during StyleCache initialization. - 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