امکان بررسی سلامت برنامه در ASP.NET Core 2.2
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

ASP.NET Core 2.2 به همراه تعدادی قابلیت جدید است که یکی از آن‌ها بررسی سلامت برنامه یا Health Check نام دارد. در بسیاری از اوقات ممکن است از سرویس‌های ping و یا درخواست مشاهده‌ی صفحات وب سایت در بازه‌های زمانی مشخصی، جهت اطمینان حاصل کردن از برپایی و سلامت آن استفاده کنید. اما این سرویس‌ها الزاما وضعیت سلامت برنامه را نمی‌توانند به خوبی گزارش کنند. به همین جهت امکان ارائه‌ی گزارش‌های دقیق‌تری توسط ویژگی Health Check به ASP.NET Core اضافه شده‌است.

پیاده سازی ویژگی Health Check بدون استفاده از قابلیت‌های ASP.NET Core 2.2

اگر بخواهیم در بررسی سلامت برنامه، وضعیت بانک اطلاعاتی آن‌را گزارش دهیم، می‌توان یک چنین اکشن متدی را طراحی کرد که در آن اتصالی به بانک اطلاعاتی باز شده و اگر در حین فراخوانی مسیر working/، استثنائی رخ داد، با بازگشت status code مساوی 503، عدم سلامت برنامه اعلام شود؛ کاری که سرویس‌های ping متداول نمی‌توانند آن‌را با این دقت انجام دهند:
[Route("working")]
public ActionResult Working()
{
    using (var connection = new SqlConnection(_connectionString))
    {
        try
        {
            connection.Open();
        }
        catch (SqlException)
        {
            return new HttpStatusCodeResult(503, "Generic error");
        }
    }
   return new EmptyResult();
}

بازنویسی قطعه کد فوق با ویژگی جدید Health Check در ASP.NET Core 2.2

اکنون اگر بخواهیم قطعه کد فوق را با کمک ویژگی‌های جدید ASP.NET Core 2.2 بازنویسی کنیم، روش کار به صورت زیر خواهد بود:
namespace MvcHealthCheckTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHealthChecks()
                    .AddCheck("sql", () =>
                        {
                            using (var connection = new SqlConnection(Configuration["connectionString"]))
                            {
                                try
                                {
                                    connection.Open();
                                }
                                catch (SqlException)
                                {
                                    return HealthCheckResult.Unhealthy();
                                }
                            }
                            return HealthCheckResult.Healthy();
                        });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseHealthChecks("/working");
- ابتدا توسط متد services.AddHealthChecks، سرویس بررسی سلامت برنامه، ثبت و معرفی می‌شود.
- سپس توسط متد app.UseHealthChecks، بدون اینکه نیاز باشد کنترلر و اکشن متد جدیدی را جهت بازگشت وضعیت سلامت برنامه، تعریف کنیم، مسیر working/ قابل دسترسی خواهد شد.
تا اینجا اگر این مسیر را به سرویس بررسی uptime برنامه‌ی خود معرفی کنید، صرفا وضعیت قابل دسترسی بودن مسیر working/ را دریافت خواهید کرد. اگر نیاز به گزارش دقیق‌تری وجود داشت، می‌توان به کمک متد AddCheck، یک منطق سفارشی را نیز به آن افزود؛ همانند بررسی امکان اتصال به بانک اطلاعاتی، به روشی که ملاحظه می‌کنید. در اینجا اگر منطق مدنظر با موفقیت اجرا شد، HealthCheckResult.Healthy بازگشت داده می‌شود و یا HealthCheckResult.Unhealthy در صورت عدم موفقیت. هر کدام از این متدها می‌توانند توضیحات و یا اطلاعات بیشتری را نیز توسط پارامترهای خود ارائه دهند.


امکان تهیه سرویس‌های سفارشی بررسی سلامت برنامه

در مثال قبل، منطق بررسی سلامت برنامه را همانجا داخل متد ConfigureServices، به کمک متد services.AddHealthChecks().AddCheck معرفی کردیم. امکان انتقال این کدها به سرویس‌های سفارشی، با پیاده سازی اینترفیس IHealthCheck نیز وجود دارد:
    public class SqlServerHealthCheck : IHealthCheck
    {
        private readonly IConfiguration _configuration;

        public SqlServerHealthCheck(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public Task<HealthCheckResult> CheckHealthAsync(
            HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            using (var connection = new SqlConnection(_configuration["connectionString"]))
            {
                try
                {
                    connection.Open();
                }
                catch (SqlException)
                {
                    return Task.FromResult(HealthCheckResult.Unhealthy());
                }
            }
            return Task.FromResult(HealthCheckResult.Healthy());
        }
    }
در اینجا کدهای AddCheck را به متد CheckHealthAsync منتقل کردیم. پس از آن برای معرفی آن به سیستم می‌توان از روش زیر استفاده کرد:
namespace MvcHealthCheckTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHealthChecks()
                    .AddCheck<SqlServerHealthCheck>("sql");
متد AddCheck، کلاس SqlServerHealthCheck را به صورت یک سرویس جدید با طول عمر Transient به سیستم تزریق وابستگی‌های NET Core. معرفی می‌کند (یعنی با هربار درخواست مسیر working/، یک وهله‌ی جدید از این کلاس ساخته شده و استفاده می‌شود) که امکان تزریق در سازنده‌ی کلاس آن نیز وجود دارد.


سفارشی سازی خروجی بررسی سلامت برنامه‌ها

تا اینجا از متدهای کلی Unhealthy و Healthy برای بازگشت وضعیت سلامت برنامه استفاده کردیم؛ خروجی‌های بهتری را نیز می‌توان ارائه داد:
public Task<HealthCheckResult> CheckHealthAsync(
            HealthCheckContext context,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            using (var connection = new SqlConnection(_configuration["connectionString"]))
            {
                try
                {
                    connection.Open();
                }
                catch (SqlException)
                {
                    return Task.FromResult(new HealthCheckResult(
                                                   status: context.Registration.FailureStatus,
                                                   description: "It is dead!"));
                }
            }
            return Task.FromResult(HealthCheckResult.Healthy("Healthy as a horse"));
        }
در نهایت نیاز است خروجی از نوع HealthCheckResult بازگشت داده شود. این خروجی را یا می‌توان توسط متدهای Healthy و Unhealthy با پارامترهای مخصوص آن‌ها ایجاد کرد و یا مانند این مثال، توسط وهله سازی مستقیم آن.
روش دیگر سفارشی سازی خروجی آن، استفاده از پارامتر دوم متد app.UseHealthChecks است:
namespace MvcHealthCheckTest
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseHealthChecks("/working", new HealthCheckOptions
            {
                ResponseWriter = async (context, report) =>
                {
                    var result = JsonConvert.SerializeObject(new
                    {
                        status = report.Status.ToString(),
                        errors = report.Entries.Select(e =>
                        new
                        {
                            key = e.Key,
                            value = Enum.GetName(typeof(HealthStatus), e.Value.Status)
                        })
                    });
                    context.Response.ContentType = MediaTypeNames.Application.Json;
                    await context.Response.WriteAsync(result);
                }
            });
در اینجا یک خروجی JSON، از ریز خطاهای گزارش شده، تهیه شده و توسط context.Response.WriteAsync به فراخوان ارائه می‌شود.


معرفی کتابخانه‌ای از IHealthCheckهای سفارشی

از مخزن کد AspNetCore.Diagnostics.HealthChecks می‌توانید IHealthCheckهای سفارشی مخصوص SQL Server، MySQL و غیره را نیز دریافت و استفاده کنید.
  • #
    ‫۵ سال قبل، سه‌شنبه ۵ شهریور ۱۳۹۸، ساعت ۱۷:۰۸
    ارتقاء به ASP.NET Core 3.0

    قسمت UseHealthChecks با endpoint routing به صورت زیر تغییر می‌کند که مزیت آن، امکان اعمال authorization و تنظیمات مرتبط با آن است:
    public void Configure(IApplicationBuilder app)
    {
        ...
    
        app.UseRouting();
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints
                .MapHealthChecks("/healthz")
                .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", });
        });
    }
  • #
    ‫۱ سال و ۴ ماه قبل، چهارشنبه ۹ فروردین ۱۴۰۲، ساعت ۱۸:۵۳
    با سلام؛ چرا وقتی بعد از افزودن Health به سرویس، در localhost بدون مشکل کار میکنه ولی در IIS به خطای زیر برمیخوریم؟
    An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.
    کد :
    void ConfigureHealthCheck(IServiceCollection services,IConfiguration configuration)
    {
    services.AddHealthChecks()
    .AddApplicationInsightsPublisher()
    .AddUrlGroup(new Uri(ssoSettings.BaseAddress),HttpMethod.Get,
    name: "Sso Service", 
    failureStatus: HealthStatus.Degraded, 
    tags: new[] { "Services" })
    .AddSqlServer(getLogDbConnection(configuration),
    name: "SqlServer Log Database",
    healthQuery: "select 1",
    failureStatus: HealthStatus.Degraded,
    tags: new[] { "Databases" });
    
    services.AddHealthChecksUI()
    .AddInMemoryStorage();
    }
     "connectionString": "Server =IP;Database=LogDb;User ID=sa;Password=xyz;trustServerCertificate=true",

    • #
      ‫۱ سال و ۴ ماه قبل، چهارشنبه ۹ فروردین ۱۴۰۲، ساعت ۲۱:۴۹
      این موارد را در اینجا پیگیری کنید.
    • #
      ‫۱ سال و ۴ ماه قبل، چهارشنبه ۱۶ فروردین ۱۴۰۲، ساعت ۰۳:۲۸
      جهت رفع مشکل در تنظیمات HealthCheck آدرس به صورت Absolute uri تنظیم شود
        "HealthChecksUI": {
          "HealthChecks": [
            {
              "Name": "Supported Services",
              "Uri": "https://Ip server/uaa/health-services"
            },
            {
              "Name": "Supported Databases",
              "Uri": "https://Ip server/uaa/health-databases"
            }
          ],
          "EvulationTimeInSeconds": 50
        }