
.net core 健康检测
检查应用的健康状态
ASP.NET Core 框架的健康检查功能是通过 HealthCheckMiddleware
中间件完成的。我们不仅可以利用该中间件确定当前应用的可用性,还可以注册相应的 IHealthCheck
对象来完成针对不同方面的健康检查。例如,当前应用部署或者依赖一些组件或者服务,我们可以注册相应的 IHealthCheck
对象来完成针对它们的健康检查。下面通过实例演示一些典型的健康检查应用场景。
GitHub:https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks
确定当前应用是否可用
对于部署于集群或者容器的应用或者服务来说,它需要对外暴露一个终结点,以便负载均衡器或者容器编排框架可以利用该终结点是否可用。ASP.NET Core 可以通过如下所示的编程方式来提供这个健康检查终结点。
class Program
{
static void Main(string[] args)
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder=>builder
.ConfigureServices(svcs=>svcs.AddHealthChecks())
.Configure(app=>app.UseHealthChecks("/healthcheck")))
.Build()
.Run();
}
}
从上面的代码来看,我们通过 IServiceCollection
接口的 AddHealthChecks
扩展方法注册 IHealthChecksBuilder
健康检查的服务,再通过 IApplicationBuilder
接口的 UseHealthChecks
扩展方法注册 HealthChecksMiddle
中间件,其中参数 /healthcheck
表示检查健康终结点的访问路径,最后我们只需要 Get 访问该路径便可知当前的健康状态(结果如下图所示)。
如下所显示的图片是我们请求健康检查后得到的报文,这里我们可以看到这是一个响应码200OK
媒体类型为 text\planin
说明是以文本输出的格式。通过健康检查我们想获取的是当前应用程序的状态,所以我们是不需要缓存内容的,在响应的报文中Pragma
和 Cache-Control
的报头恰好说明了这一点。
定制健康检查逻辑
生活中,我们经常也会更具自身的需求进行选择不同食物用膳,健康检查也是如此。在上一个案例中应用程序一旦启动成功所请求的状态就是Healthy
,如果我们需要在程序启动之前定制一些条件再进行判断是否健康,那这就不符合需求了。
在下面的案例中,我们通过 IServiceCollection
接口的 AddHealthChecks
扩展方法注册所需的服务依赖之后,返回 IHealthChecksBuilder
对象的 AddCheck
方法注册了一个 IHealthCheck
对象,该对象会调用 Check
方法来决定最终的健康状态。在内嵌的 Check
方法中,该方法会返回 3 种健康状态(Healthy、UnHealthy、Degraded)
class Program
{
static void Main(string[] args)
{
var random = new Random();
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder=>builder
.ConfigureServices(svcs=>svcs.AddHealthChecks()
.AddCheck("default",Check))
.Configure(app=>app.UseHealthChecks("/healthcheck")))
.Build()
.Run();
HealthCheckResult Check()
{
return (random.Next(1,4)) switch
{
1 => HealthCheckResult.Unhealthy(),
2 => HealthCheckResult.Degraded(),
_ => HealthCheckResult.Healthy()
};
}
}
}
从如上所示的代码中有3种健康检查状态的响应报文。Healthy
与 Degraded
响应的都是 200 Ok
,它们都表示是可用(Available)状态,两者之间的区别在于完全可用与部分可用, Unhealthy
的服务被视为不可用(Unavailable),所以响应状态码为 Service Unabailable
改变响应状态码
上面讲解了3种健康检查与所对应的状态码,默认的状态码虽然是一种规范,但还是无法分辨出 Healthy
与 Degraded
,所以我们可用通过自定义不同但状态码进行区分。
class Program
{
static void Main(string[] args)
{
var random = new Random();
var option = new HealthCheckOptions{
ResultStatusCodes = new Dictionary<HealthStatus,int>{
[HealthStatus.Healthy] = 99,
[HealthStatus.Degraded] = 299,
[HealthStatus.Unhealthy] = 503
}
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder=>builder
.ConfigureServices(svcs=>svcs.AddHealthChecks()
.AddCheck("default",Check))
.Configure(app=>app.UseHealthChecks("/healthcheck",option)))
.Build()
.Run();
HealthCheckResult Check()
{
return (random.Next(1,4)) switch
{
1 => HealthCheckResult.Unhealthy(),
2 => HealthCheckResult.Degraded(),
_ => HealthCheckResult.Healthy()
};
}
}
}
HealthChecksMiddleware
提供了 HealthCheckOptions
对象作为对应的配置选项。HealthCheckOptions
对象通过 ResultStatusCodes
属性字段返回的字典维护了3种健康状态与所对应的状态码,这里我们只修改 Healthy
与 Degraded
这两种健康状态的状态码,分别为 99 与 299。
细粒度的健康检查
如果当应用的本身依赖了其他服务与组件时,这个时候就可以针对它们做细粒度的健康检查。前面通过 IHealthCheck
对象对应用级别的健康检查做了定制,同样我们可以通过 IHealthCheck
对象对某个组件或者服务注册相应对 IHealthCheck
对象来确定它们的健康状态。
class Program
{
static void Main(string[] args)
{
var random = new Random();
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder=>builder
.ConfigureServices(svcs=>svcs.AddHealthChecks()
.AddCheck("aaa",Check)
.AddCheck("bbb",Check)
.AddCheck("ccc",Check))
.Configure(app=>app.UseHealthChecks("/healthcheck")))
.Build()
.Run();
HealthCheckResult Check()
{
return (random.Next(1,4)) switch
{
1 => HealthCheckResult.Unhealthy(),
2 => HealthCheckResult.Degraded(),
_ => HealthCheckResult.Healthy()
};
}
}
}
这里以自定义的3个服务,通过3个 IHealthCheck
对象来完成对它们对健康检查。由于注册的 3 个 IHealthCheck
采用的不同同一个 Check
方法决定最后的健康状态,所以也只有3种不同的结果。(这里我就不上图了)
从这个案例可以反应出所有得到的结果有点以面盖全了,如果是
Healthy
那么所有的服务以及所依赖的组件都是Healthy
,…所以这并不是我们想要的,应该对服务与依赖进行定制响应内容。
定制响应内容
上面演示的实例所得到的应用整体健康状态,如果要得到对服务与依赖的插件一份比较完整且详细“健康报告”,我们将程序做适当修改。
class Program
{
static void Main(string[] args)
{
var random = new Random();
var options = new HealthCheckOptions{
ResponseWriter = ReportAsync
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder=>builder
.ConfigureServices(svcs=>svcs.AddHealthChecks()
.AddCheck("aaa",Check,new string[]{ "aaa1","bbb2" })
.AddCheck("bbb",Check,new string[]{ "bbb1","bbb2" })
.AddCheck("ccc",Check,new string[]{ "ccc1","ccc1" }))
.Configure(app=>app.UseHealthChecks("/healthcheck",options)))
.Build()
.Run();
static Task ReportAsync(Microsoft.AspNetCore.Http.HttpContext content,HealthReport report){
content.Response.ContentType = "application/json";
var settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.Converters.Add(new StringEnumConverter());
return content.Response.WriteAsync(JsonConvert.SerializeObject(report,settings));
}
HealthCheckResult Check()
{
return (random.Next(1,4)) switch
{
1 => HealthCheckResult.Unhealthy("Unavailable"),
2 => HealthCheckResult.Degraded("Degraded"),
_ => HealthCheckResult.Healthy("Normal")
};
}
}
}
对改写的内容体现以下几点:首先,为 Check
方法返回的表示健康检查结果的 HealthCheckResult
对象设置对应的描述性文字(Normal、Degraded 和 Unavailable);其次,在调用 IHealthChecksBuilder
接口的 AddCheck
方法注册相应的 IHealthCheck
对象时,指定了两个的标签(Tag),如针对服务 aaa
的 IHealthCheck
对象的标签设置为 aaa1
和 aaa2
; 最后,在调用 IApplicationBuilder
接口的 UseHealthChecks
扩展方法注册 HealthCheckMiddleware
中间件时,指定了作为配置选项的 HealthCheckOptions
对象,并通过设置其 ResponseWriter
属性的方式完成了对健康报告的呈现。HealthCheckOption
的 ResponseWriter
属性返回的是一个 Func<HttpContext,HealthReport,Task>
对象,其中 HealthReport
对象是 HealthCheckMiddleware
中间件针对健康报告的表达。我们设置的委托对象应应对的方法为 ReportAsync
,该方法会直接将指定的 HealthReport
对象序列化成 JSON
格式并作为响应主题内容。我们并没有设置相应的状态码,所以可以直接在浏览器种看到这份完整的健康报告。
过滤 IHealthCheck 对象
HealthCheckMiddleware
中间件提取注册的 IHealthCheck
对象完成具体的健康检查工作之前,我们可以做进一步过滤。对于 IHealthCheck
对象的过滤逻辑依然是利用 HealthCheckOptions
配置来进行实现,同时我们也需要设置它的 Predicate
属性,该属性返回一个 Func<HealthCheckRegistration, bool>
类型的委托对象,其中 HealthCheckRegistration
对象代表针对 IHealthCheck
对象的注册。
在如下代码中我们通过设置配置选项 HealthCheckOptions
对象的 Predicate
属性使之选择 Tag
前缀不为 ccc
的 IHealthCheck
对象
class Program
{
static void Main(string[] args)
{
var random = new Random();
var options = new HealthCheckOptions
{
ResponseWriter = ReportAsync,
Predicate = reg => reg.Tags.Any(tag => !tag.StartsWith("ccc", StringComparison.OrdinalIgnoreCase))
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(svcs => svcs
.AddHealthChecks()
.AddCheck("aaa", Check, new string[] { "aaa1", "bbb2" })
.AddCheck("bbb", Check, new string[] { "bbb1", "bbb2" })
.AddCheck("ccc", Check, new string[] { "ccc1", "ccc1" })
)
.Configure(app => app.UseHealthChecks("/healthcheck", options)))
.Build()
.Run();
static Task ReportAsync(Microsoft.AspNetCore.Http.HttpContext content, HealthReport report)
{
content.Response.ContentType = "application/json";
var settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.Converters.Add(new StringEnumConverter());
return content.Response.WriteAsync(JsonConvert.SerializeObject(report, settings));
}
HealthCheckResult Check()
{
return (random.Next(1, 4)) switch
{
1 => HealthCheckResult.Unhealthy("Unavailable"),
2 => HealthCheckResult.Degraded("Degraded"),
_ => HealthCheckResult.Healthy("Normal")
};
}
}
}
由于我们这里过滤了 ccc
服务的健康检查,所以在浏览器中我们就看不了所对应的健康状态。
针对 Entity Framework Core 的健康检查
如果应用需要用到对数据库的访问,那么就需要通过健康检查判断数据库的可用性。Entity Framework Core作为我们最常用数据库的存取框架,就可以利用健康检查来确定 DbContext
是否可用。针对 DbContext
的健康检查是通过 DbContextHealthCheck<TContext>
这个内部类型完成的,该类型由 NuGet 包 Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
来提供。
基于 DbContext 的健康检查
下面通过简单的示例来介绍如何利用该注册 DbContextHealth<TContext>
对象来检查对 DbContext
的可用性。该类型所在的 NuGet 包 Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
的依赖。除此之外,我们的演示实例采用的数据库类型为 SQL Server ,所以还需要为演示程序添加针对 NuGet 包 Microsoft.EntityFrameworkCore.SqlServer
的依赖。在添加了上述两个 NuGet 包的依赖之后,我们定义了如下两个空的 DbContext
类型(FooContext 和 BarContext)。
public class FooContext:DbContext
{
public FooContext(DbContextOptions<FooContext> options) : base(options)
{}
}
public class BarContext : DbContext
{
public BarContext(DbContextOptions<BarContext> options) : base(options)
{}
}
在如下所演示程序中,我们调用 IServiceCollection
接口的 AddDbContext<TDbContext>
扩展方法注册针对 Entity Framework Core
的相关服务,并完成了针对上述两个自定义 DbContext
类型的注册。我们为 FooContext
和 BarContext
分别指出了两个针对 SQL Server 的连接字符串,其中前者是有效的,后者是无效的。
static void Main(string[] args)
{
var options = new HealthCheckOptions
{
ResponseWriter = ReportAsync
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(svcs => svcs
.AddDbContext<FooContext>(options => options.UseSqlServer("<Connection String>"))
.AddDbContext<BarContext>(options => options.UseSqlServer("<Connection String>"))
.AddHealthChecks()
.AddDbContextCheck<FooContext>()
.AddDbContextCheck<BarContext>()
)
.Configure(app => app.UseHealthChecks("/healthcheck", options)))
.Build()
.Run();
static Task ReportAsync(Microsoft.AspNetCore.Http.HttpContext content, HealthReport report)
{
var builder = new StringBuilder();
builder.AppendLine($"Status: {report.Status}");
foreach (var name in report.Entries.Keys)
{
builder.AppendLine($"{name}:{report.Entries[name].Status}");
}
return content.Response.WriteAsync(builder.ToString());
}
在调用 IServiceCollection
接口的 AddHealthChecks
扩展方法得到 IHealthChecksBuilder
对象之后,我们针对两个 DbContext
类型(FooContent 和 BarContext)调用 AddDbContextCheck<TContext>
扩展方法,它们会创建并注册对应的 DbContextHealthCheck<TContext>
对象。为了得到针对两个 DbContext
类型的健康报告,我们依然在注册 HealthCheckMiddleware
中间件时指定了对应的配置选项,并通过指定其 ResponseWrite
属性将每个健康检查条目的状态呈现到响应内容中。如果直接利用浏览器发送健康检查请求,就会得到如下的健康报告。由于 FooContext
连接的数据库是可用的,所以针对它的状态为 Healthy
.BarContext
采用的连接字符串是无效的,所以它对应的状态为 UnHealthy
我们基于上一次的序列化完整输出,如下图所示
发布健康报告
我们通过如下实例来介绍健康报告的定期发布。健康报告的发布是通过 IHealthCheck Publisher
服务来完成的。我们实现该接口的实现类型 ConsolePublisher
将健康报告输出到控制台上。如下所示的代码片段展示了如何利用 ConsolePublisher
对象将收集的健康报告以设定的时间间隔输出到控制台上。
var random = new Random();
var options = new HealthCheckOptions
{
ResponseWriter = ReportAsync
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(svcs => svcs
.AddHealthChecks()
.AddCheck("aaa", Check)
.AddCheck("bbb", Check)
.AddCheck("ccc", Check)
.AddConsolePublisher()
.ConfigurePublisher(options =>
options.Period = TimeSpan.FromSeconds(5)))
)
.Configure(app => app.UseHealthChecks("/healthcheck", options)))
.Build()
.Run();
static Task ReportAsync(Microsoft.AspNetCore.Http.HttpContext content, HealthReport report)
{
content.Response.ContentType = "application/json";
var settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.Converters.Add(new StringEnumConverter());
return content.Response.WriteAsync(JsonConvert.SerializeObject(report, settings));
}
HealthCheckResult Check()
{
return (random.Next(1, 4)) switch
{
1 => HealthCheckResult.Unhealthy("Unavailable"),
2 => HealthCheckResult.Degraded("Degraded"),
_ => HealthCheckResult.Healthy("Normal")
};
}
如上代码我们注册了3个 IHealthCheckBuilder
对象,它们会随机返回3种状态的健康状态。ConsolePublisher
对象的注册体现在针对 AddConsolePublisher
方法的调用上,这是专门为 IHealthCheckBuilder
接口定义的扩展方法。借助调用 ConfigurePublisher
方法也是自定义扩展方法,我们利用它将健康报告间隔设置为5秒。
public static class Extensions
{
public static IHealthChecksBuilder AddConsolePublisher(this IHealthChecksBuilder builder)
{
builder.Services.AddSingleton<IHealthCheckPublisher, ConsolePublisher>();
return builder;
}
public static IHealthChecksBuilder ConfigurePublisher(this IHealthChecksBuilder builder, Action<HealthCheckPublisherOptions> configure)
{
builder.Services.Configure(configure);
return builder;
}
}
public class ConsolePublisher : IHealthCheckPublisher
{
private readonly ObjectPool<StringBuilder> _stringBuilderPool;
public ConsolePublisher(ObjectPoolProvider provider)
{
_stringBuilderPool = provider.CreateStringBuilderPool();
}
public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var builder = _stringBuilderPool.Get();
try
{
builder.AppendLine($"Status: {report.Status}[{ DateTimeOffset.Now.ToString("yy-MM-dd hh:mm:ss")}]");
foreach (var name in report.Entries.Keys)
{
builder.AppendLine($" {name}: {report.Entries[name].Status}");
}
Console.WriteLine(builder);
return Task.CompletedTask;
}
finally
{
_stringBuilderPool.Return(builder);
}
}
}
健康检查(UI)
虽然官方为我们提供的运行检查库已经足够轻量和简单。但是为了避免重复造轮子,我们可以使用AspNetCore.Diagnostics.HealthChecks
包,该项目包含了许多情况的检查,比如 Sql Server
、MySql
、Elasticsearch
、Redis
、Kafka
等等。
并且还为我们提供一个UI界面,可供查看,通过 NuGet 包AspNetCore.HealthChecks.UI.Client
提供客户端独特的输出格式,改动原有代码:
static void LastPractice()
{
var random = new Random();
var options = new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse//ReportAsync
};
var options2 = new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
Predicate = reg => reg.Name == "ccc"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(svcs => svcs
.AddHealthChecks()
.AddCheck("aaa", Check)
.AddCheck("bbb", Check)
.AddCheck("ccc", Check)
.AddConsolePublisher()
.ConfigurePublisher(option=>option.Period = TimeSpan.FromSeconds(5))
)
.Configure(app => {
app.UseHealthChecks("/healthcheck", options);
app.UseHealthChecks("/healthcheck2", options2);
}))
.Build()
.Run();
static Task ReportAsync(Microsoft.AspNetCore.Http.HttpContext content, HealthReport report)
{
content.Response.ContentType = "application/json";
var settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.Converters.Add(new StringEnumConverter());
return content.Response.WriteAsync(JsonConvert.SerializeObject(report, settings));
}
HealthCheckResult Check()
{
return (random.Next(1, 4)) switch
{
1 => HealthCheckResult.Unhealthy("Unavailable"),
2 => HealthCheckResult.Degraded("Degraded"),
_ => HealthCheckResult.Healthy("Normal")
};
}
}
通过 IApplicationBuilder
接口的 UseHealthChecks
扩展方法去注册 2 个 HealthChecksMiddle
配置不一的中间件,同时也映射出两种不同的路径 /healthcheck
与 /healthcheck2
,前者包括所有注册的服务与插件可以进行健康检查,后者只能检查名为 ccc
的服务。
创建一个项目名为
HealthDashboard
的 webApi 网站,添加健康面板AspNetCore.HealthChecks.UI
以及AspNetCore.HealthChecks.UI.InMemory.Storage
依赖包。注册HealthCheck
健康面板的相关服务,并映射相关路径,默认通过/healthchecks-ui
即可访问。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services
.AddHealthChecksUI()
.AddInMemoryStorage();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app
.UseRouting()
.UseEndpoints(config =>
{
config.MapHealthChecksUI();
});
}
}
对 appsetting.json 我们也需要对其进行修改。主要是针对 HealthChecksUI
的配置,我们从中可以看到 HealthChecks
节点下添加了两个检测节点。接下来我们通过浏览器访问 /healthchecks-ui
查看二者的连接情况。
{
"HealthChecksUI": {
"HealthChecks": [
{
"Name": "IHealthCheckConsole",
"Uri": "http://localhost:5000/healthcheck"
},
{
"Name": "IHealthCheckConsole-Only-CCC",
"Uri": "http://localhost:5000/healthcheck2"
}
],
"Webhooks": [
{
"Name": "Default",
"Uri": "",
"Payload": "{\"text\":\"The HealthCheck [[LIVENESS]] is failing with the error message: [[FAILURE]]. [[DESCRIPTIONS]]. <http://yourappstatus|Click here> to get more details.\",\"channel\":\"#general\",\"link_names\": 1,\"username\":\"monkey-bot\",\"icon_emoji\":\":monkey_face:\"}",
"RestoredPayload": "{\"text\":\"The HealthCheck [[LIVENESS]] is recovered. All is up and running\",\"channel\":\"#general\",\"link_names\": 1,\"username\":\"monkey-bot\",\"icon_emoji\":\":monkey_face:\"}"
}
],
"EvaluationTimeinSeconds": 10,
"MinimumSecondsBetweenFailureNotifications": 60
}
}
我们从健康检测UI中直关的看到每个注册点下,服务和插件的运行情况。关于 appsettings.json 文件中的配置参数可以参考如下。
HealthChecks
默认情况下,HealthChecks
返回一个简单的状态码(200或503),而不包含 HealthReport
数据。如果您希望 HealthCheck-UI
显示来自 HealthCheck
的 HealthReport
数据,则可以启用它以添加特定的 ResponseWriter
。要在HealthCheck-UI中显示这些HealthCheck,必须通过HealthCheck-UI设置对其进行配置。同时也等同于如下代码:
public void ConfigureServices(IServiceCollection services)
{
services
.AddHealthChecksUI(setup=> {
setup.AddHealthCheckEndpoint("IHealthCheckConsole", "http://localhost:5000/healthcheck");
setup.AddHealthCheckEndpoint("IHealthCheckConsole-Only-CCC", "http://localhost:5000/healthcheck2");
})
.AddInMemoryStorage();
}
Webhooks
您可以使用IConfiguration提供程序(应用程序设置,用户机密,环境变量)配置这些Healthcheck和Webhooks,也可以使用AddHealthChecksUI(setupSettings:setup =>)方法。具体请参考 Webhooks 在这里等同于如下代码:
public void ConfigureServices(IServiceCollection services)
{
services
.AddHealthChecksUI(setup=> {
setup.AddHealthCheckEndpoint("IHealthCheckConsole", "http://localhost:5000/healthcheck");
setup.AddHealthCheckEndpoint("IHealthCheckConsole-Only-CCC", "http://localhost:5000/healthcheck2");
setup.AddWebhookNotification("Default", uri: "", payload: "{...}");
})
.AddInMemoryStorage();
}
如果配置了WebHooks部分,则HealthCheck-UI会自动将新通知发布到webhook集合中。HealthCheckUI对webhook的Payload和RestorePayload属性中的值使用简单的替换方法。目前,我们支持两个书签:
[[LIVENESS]] 返回Down的活动的名称。
[[FAILURE]] 带有失败的详细消息。
[[DESCRIPTIONS]] 故障描述
Webhooks可以使用配置提供程序进行配置,也可以通过代码进行配置。使用代码可以进行更大程度的自定义,因为您可以设置自己的用户功能来自定义输出消息或配置是否将有效负载发送到给定的Webhook端点。
EvaluationTimeinSeconds
运行状况检查之间经过的秒数。
MinimumSecondsBetweenFailureNotifications
故障通知之间的最小秒数,以避免接收器满溢。
UI自定义样式表
UI通过使用自定义样式表和css变量支持自定义样式和品牌。要添加自定义样式表,请使用UI设置方法
添加示例文件以及样式
dotnet.css 样式如下
:root {
--primaryColor: #68217a;
--secondaryColor: #f4f4f4;
--bgMenuActive: #8e47a0;
--bgButton: #68217a;
--logoImageUrl: url('../../logo.png');
--bgAside: var(--primaryColor);
}
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStaticFiles();
app
.UseRouting()
.UseEndpoints(config =>
{
config.MapHealthChecksUI(setup=> {
setup.AddCustomStylesheet("wwwroot\\dotnet.css");
});
});
}
更多请参考:https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/doc/styles-branding.md
HealthCheck 与 Kubernetes
https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks/blob/master/doc/k8s-operator.md
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

