вторник, 2 сентября 2025 г.

25.09.02, RazorzzSln, Sine, Cycle, RazorPage, Singletone, State, Render, PartialView, Work well

https://giga.chat/link/gcsMrDeddV - this from next RazorSine05.csproj

F:\Projects\VS\RazorzzSln\RazorzzSln.sln
F:\Projects\VS\RazorzzSln\RazorSine04\RazorSine04.csproj WORK WELL
Programm.cs
----------------------------------------------------------
using RazorSine04;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSingleton<IRunningSineState, RunningSineState>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.MapStaticAssets();
app.MapRazorPages()
   .WithStaticAssets();

app.Run();
--------------------------------------------------------------
Simpleline.cshtml
--------------------------------------------------------------
@page
@using ChartDirector
@model RazorSine04.Pages.SimplelineModel
@{
    ViewData["Title"] = "Simple Line Chart";
    var initialHtml = ((RazorChartViewer)ViewData["Viewer"]).RenderHTML();
}
<h2>@ViewData["Title"]</h2>
<div id="chart-container">
    @Html.Raw(initialHtml)
</div>
<script>
    (function(){
    const container = document.getElementById('chart-container');
    async function refreshChart() {
        try {
            const resp = await fetch('@Url.Page("SimpleLine", "ChartHtml")', {
                method: 'GET',
                headers: { 'Accept': 'text/html' },
                cache: 'no-store'
            });
            if (!resp.ok) return;
            const html = await resp.text();

            // Без мерцания: заменяем весь HTML блока (img + map), чтобы usemap и tooltips были корректны
            container.innerHTML = html;
        } catch(e) {
            // можно логировать в консоль
            // console.error(e);
        }
    }

    // Обновляем каждые 1000 мс. Можете поставить 250-500 мс.
    const intervalMs = 1000;
    setInterval(refreshChart, intervalMs);
    })();
</script>

@* @{
    Layout = "_Layout";
}
 *@
@* @{
    if (ViewBag.Viewer is Array)
    {
        // Display multiple charts
        for (int i = 0; i < ViewBag.Viewer.Length; ++i)
        {
            @:@Html.Raw(ViewBag.Viewer[i].RenderHTML())
        }
    }
    else
    {
        // Display one chart only
        @:@Html.Raw(ViewBag.Viewer.RenderHTML())
    }
} *@

@* Вариант с meta: *@
@* <head>
    <meta http-equiv="refresh" content="1" />
</head> *@

@* @section Scripts {
    <script>
        setTimeout(function () { window.location.reload(); }, 1000);
    </script>
} *@
-----------------------
Simpleline.cshtml.cs
-----------------------
using ChartDirector;
using MathLib;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorSine04;

//namespace RazorChartDirApp07.Pages
namespace RazorSine04.Pages
{
    public class SimplelineModel : PageModel
    {
        private readonly IRunningSineState _state;
        private readonly ILogger<IndexModel> _logger;

        private const int Points = 36;

        public SimplelineModel(IRunningSineState state, ILogger<IndexModel> logger)
        {
            _state = state;
            _logger = logger;
        }
        public RazorChartViewer Viewer { get; private set; } = default!; // ***
        public void OnGet()
        {
            ViewData["Title"] = "Simple Line Chart";
            RazorChartViewer viewer = new(HttpContext, "chart1");
            ViewData["Viewer"] = viewer;
            createChart(viewer);
            ViewData["Viewer"] = viewer; // ***
        }

        // *********************************
        // AJAX-эндпоинт: вернуть HTML графика целиком (img + map)
        public IActionResult OnGetChartHtml()
        {
            var viewer = new RazorChartViewer(HttpContext, "chart1");
            createChart(viewer);
            // Вернем просто HTML-строку
            return Content(viewer.RenderHTML(), "text/html; charset=utf-8");
        }
        // *********************************
        private void createChart(RazorChartViewer viewer)
        {
            // _logger.Log(LogLevel.Information, "CurrentIndex: " + _state.CurrentIndex.ToString());
            var dataArg = MathSeries.Linspace(0.0, 2 * Math.PI, Points, _state.CurrentIndex);
            var data = MathSeries.Evaluate(dataArg, Math.Sin);
            var nextIndex = _state.NextIndex(Points);
            // _logger.Log(LogLevel.Information, "CurrentIndex: " + _state.CurrentIndex.ToString());
            // The labels for the line chart
            string[] labels = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24",
"25", "26", "27","28", "29", "30", "31","32","33", "34", "35"};

            // Create a XYChart object of size 250 x 250 pixels
            XYChart c = new XYChart(450, 450);

            // Set the plotarea at (30, 20) and of size 200 x 200 pixels
            c.setPlotArea(30, 20, 400, 400);

            // Add a line chart layer using the given data
            c.addLineLayer(data);

            // Set the labels on the x axis.
            c.xAxis().setLabels(labels);

            // Display 1 out of 3 labels on the x-axis.
            c.xAxis().setLabelStep(3);

            // Output the chart
            viewer.Image = c.makeWebImage(Chart.SVG);

            // Include tool tip for the chart
            viewer.ImageMap = c.getHTMLImageMap("", "", "title='Hour {xLabel}: Traffic {value} GBytes'");
        }
    }
}
----------------------
RunningSineState.cs
----------------------
namespace RazorSine04
{
    public interface IRunningSineState
    {
        int NextIndex(int period);
        int CurrentIndex { get; }
    }

    public class RunningSineState : IRunningSineState
    {
        private int _currentIndex = 0;
        private int period;

        public int CurrentIndex => Volatile.Read(ref _currentIndex) % 36; // 36;

        // Вернёт индекс для следующего запроса (0..period-1), затем по кругу
        public int NextIndex(int period)
        {
            // атомарно увеличиваем и берём по модулю
            int next = Interlocked.Increment(ref _currentIndex);
            // после инкремента next начинается с 1, поэтому нормализуем
            int normalized = next % period;
            return normalized;
        }
    }
}
----------------------------
_Layout.cshtml
----------------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
@*     <meta http-equiv="refresh"
          content="1" /> *@
    <title>@ViewData["Title"] - RazorSine04</title>
    <script type="importmap"></script>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/RazorSine04.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">RazorSine04</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Simpleline">Chart</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2025 - RazorSine04 - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>
---------------------------
Warning
---------------------------

Это предупреждение связано с Browser Link в Visual Studio. Оно безвредно и появляется, когда middleware пытается внедрить скрипт в ответ, а тип ответа или пайплайн этому не способствует (например, JSON, streaming, уже начатый ответ, отключены cookies, HTTPS/HTTP2 с определенными настройками, или вы не используете стандартный Razor Layout).

Что можно сделать:

  • Проще всего: отключить Browser Link. В Visual Studio откройте меню Debug > Options > Projects and Solutions > Web Projects и снимите галочку Enable Browser Link. Либо на панели VS (обычно вверху) отключите кнопку Browser Link.
  • В appsettings.Development.json установите:
    {
    "Logging": {
    "LogLevel": {
    "Microsoft.WebTools.BrowserLink": "None"
    }
    }
    }
    Это просто скрывает предупреждение в логах.
  • Удалите/комментируйте UseBrowserLink в Startup/Program для Development:
    if (app.Environment.IsDevelopment())
    {
    // app.UseBrowserLink(); // отключить
    }
  • Если хотите оставить Browser Link, но уменьшить предупреждения, не отдавайте через тот же middleware ответы, куда нельзя внедрять скрипты. Например, для API-эндпоинтов, которые возвращают JSON/ChartDirector изображения/stream, держите их под /api и не пропускайте через Razor/Layout. Это не всегда избавит от предупреждения, но сократит частоту.
  • Очистите кэш Browser Link. В Visual Studio закройте все браузеры, остановите отладку, удалите папку %LocalAppData%\Microsoft\VisualStudio{версия}\Browser Link, перезапустите.
  • Если используете HTTPS с HTTP/2, иногда помогает принудительно использовать HTTP/1.1 для отладки, потому что Browser Link опирается на инъекцию скрипта и не всегда дружит с определенными комбинациями заголовков и протокола.

Итого: это не ошибка и не влияет на ваш функционал графиков. Самый быстрый вариант — отключить Browser Link в VS или убрать UseBrowserLink в Development.


Комментариев нет:

Отправить комментарий