Показаны сообщения с ярлыком RazorPage. Показать все сообщения
Показаны сообщения с ярлыком RazorPage. Показать все сообщения

пятница, 28 ноября 2025 г.

Giga, RazorPage,BackGroundService, RandomQoutesGenerator, Separate, Chart, Render,

Giga, RazorPage,BackGroundService, RandomQoutesGenerator, Separate, Chart, Render,

new BackGroundService to Separate RandomQoutesGenerator from Chart Render

F:\Projects\VS\RazorChartDirFinanceSln\RazorChartDirFinanceSln.sln

F:\Projects\VS\RazorChartDirFinanceSln\RazorChartDirFin0224\RazorChartDirFin0224.csproj

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

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

25.09.02, RazorzzSln, Sine, Cycle, RazorPage, Singletone, State, Render, PartialView, Work well,
From Giga  - Exelent Project
BEST CODE
F:\Projects\VS\RazorzzSln\RazorzzSln.sln
F:\Projects\VS\RazorzzSln\RazorSine05\RazorSine05.csproj WORK WELL
------------------------------------------------------------------------------------------------------------

SimpleLine.cshtml.cs

-----------------------------------------------------------------------------------------------------------
using ChartDirector;
using LinSpace;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorChartDirApp07.Services;

namespace RazorChartDirApp07.Pages
{
    public class SimpleLineModel : PageModel
    {
        private readonly IRunningSineState _state;
        private readonly ILogger<SimpleLineModel> _logger;

        public SimpleLineModel(IRunningSineState state, ILogger<SimpleLineModel> logger)
        {
            _state = state;
            _logger = logger;
        }

        public void OnGet()
        {
            ViewData["Title"] = "Simple Line Chart";
            RazorChartViewer viewer = new RazorChartViewer(HttpContext, "chart1");
            ViewData["Viewer"] = viewer;
            createChart(viewer);
        }

        private void createChart(RazorChartViewer viewer)
        {
            var dataArg = MathSeries.Linspace(0.0, 2 * Math.PI, 36, _state.CurrentIndex);
            var data = MathSeries.Evaluate(dataArg, Math.Sin);
            var nextIndex = _state.NextIndex(36);
            
            string[] labels = Enumerable.Range(0, 36).Select(i => i.ToString()).ToArray();

            XYChart c = new XYChart(450, 450);
            c.setPlotArea(30, 20, 400, 400);
            c.addLineLayer(data);
            c.xAxis().setLabels(labels);
            c.xAxis().setLabelStep(3);

            viewer.Image = c.makeWebImage(Chart.SVG);
            viewer.ImageMap = c.getHTMLImageMap("", "",
                "title='Hour {xLabel}: Traffic {value} GBytes'");
        }
    }
}
-----------------------------

SimpleLine.cshtml

-----------------------------
@page
@model RazorChartDirApp08.Pages.SimpleLineModel
@using ChartDirector
@{
    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();
                container.innerHTML = html;
            } catch(e) {}
        }
    
        const intervalMs = 1000;
        setInterval(refreshChart, intervalMs);
    })();
</script>
-----------------------------------------------------------------

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.


25.09.02, RazorzzSln, Sine, Cycle, RazorPage, Singletone, State

https://ask.chadgpt.ru/share/be4cddc1-2afc-43c5-9f71-b40d71d688b9

F:\Projects\VS\RazorzzSln\RazorzzSln.sln

Sine, Cycle, with Singletone State 

F:\Projects\VS\RazorzzSln\RazorSine03\RazorSine03.csproj

F:\Projects\VS\RazorzzSln\Razorzz02\Razorzz02.csproj

----------------------------------------------

Sin03
Автообновление

@* Вариант с meta: *@

@* <head>

    <meta http-equiv="refresh" content="1" />

</head> *@

-----------------------------

@section Scripts {

    <script>

        setTimeout(function () { window.location.reload(); }, 1000);

    </script>

}

-----

И в createChart:

var dataArg = LinspaceShifted(0.0, 2 * Math.PI, Points, currentIndex);
var data = MathSeries.Evaluate(dataArg, Math.Sin);

Важно: Такой “сдвиг массива аргументов” визуально даст эффект бегущей синусоиды, потому что значения sin вычисляются в новом порядке.

Альтернатива с фазовым сдвигом
Можно вместо перестановки точек применять фазовый сдвиг равномерной сетке: sin(x + phi). Тогда не нужно переставлять X, достаточно изменить функцию:

double phase = 2 * Math.PI * currentIndex / Points;
var dataArg = MathSeries.Linspace(0.0, 2 * Math.PI, Points);
var data = MathSeries.Evaluate(dataArg, x => Math.Sin(x + phase));

Оба подхода дают “пробег” по синусоиде. Вы выбираете тот, что соответствует вашей идее “стартовать с увеличенного индекса”.

https://ask.chadgpt.ru/share/be4cddc1-2afc-43c5-9f71-b40d71d688b9

  1. Автообновление Razor Page каждые 1 секунду
    В файле .cshtml для этой страницы добавьте мета-рефреш в секцию Head или простой скрипт:

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

Или скриптом:
<script>
setTimeout(function () { window.location.reload(); }, 1000);
</script>

Meta проще и надежнее для быстрого прототипа.

  1. Итоги по использованию
  • Регистрируете RunningSineState как Singleton.
  • В PageModel через конструктор получаете IRunningSineState.
  • На каждом OnGet берёте currentIndex = _state.NextIndex(36).
  • Создаёте данные или через Linspace(..., currentIndex), или через Linspace + фазовый сдвиг.
  • В Razor-странице включаете автообновление раз в 1 секунду.
---

Коротко:

  • Метатег refresh добавляется в секцию <head> итогового HTML-документа. В Razor это делается через секцию Head в макете (_Layout.cshtml).
  • Скрипт перезагрузки ставьте в конец <body> (или в секцию Scripts), чтобы не мешать рендерингу графика.

Если у вас есть макет _Layout.cshtml, правильнее не дублировать <head> на странице, а воспользоваться секциями.

Вариант 1. Через метатег refresh в секции Head:

  1. В _Layout.cshtml убедитесь, что есть вызов @RenderSection("Head", required: false) внутри <head>:
    <head>
    ...
    @RenderSection("Head", required: false)
    </head>
  2. В вашей странице добавьте секцию:
    @section Head {
    <meta http-equiv="refresh" content="1" />
    }

Вариант 2. Через JS-таймер:

  1. В _Layout.cshtml убедитесь, что есть @RenderSection("Scripts", required: false) перед </body>:
    <body>
    ...
    @RenderSection("Scripts", required: false)
    </body>
  2. В вашей странице:
    @section Scripts {
    <script>
    setTimeout(function () { window.location.reload(); }, 1000);
    </script>
    }

Если у вас нет секций в макете, то:

  • метатег можно временно вставить прямо в _Layout.cshtml внутри <head>;
  • скрипт — внизу _Layout.cshtml перед закрывающим .

Советы:

  • Не вставляйте отдельный <head> прямо в контент страницы, если используется Layout — это создаст вложенный head и некорректный HTML.
  • Для локальной автообновляемой страницы используйте JS-таймер. Он гибче: можно останавливать, менять интервал, не трогает историю навигации.

среда, 20 августа 2025 г.

ChartDirector, RazorPage, Chad, JS-timer

https://ask.chadgpt.ru/share/be4cddc1-2afc-43c5-9f71-b40d71d688b9

D:\VC2508\Charts\WpfChartSln\WpfChartDir\WpfChartDir.sln

D:\VC2508\Charts\WpfChartSln\WpfChartDir\RazorChartDirApp08\RazorChartDirApp08.csproj - work well

Работает с локальным Rendering

Разберу по частям, зачем здесь каждый фрагмент, как работает обновление, и почему редактор подчеркивает приведение типа (RazorChartViewer)ViewData["Viewer"] зеленой волной.

Что делает страница

  • Директивы @page, @model: это Razor Page. Модель страницы — RazorChartDirApp08.Pages.SimpleLineModel. В ней, как правило, в OnGet вы готовите данные и кладете в ViewData["Viewer"] экземпляр RazorChartViewer (обертка ChartDirector для Razor).
  • @using ChartDirector: подключает типы ChartDirector/RazorChartViewer.
  • ViewData["Title"] = "Simple Line Chart": задает заголовок.
  • var initialHtml = ((RazorChartViewer)ViewData["Viewer"]).RenderHTML();: берёт из ViewData подготовленный на сервере Viewer, приводит к RazorChartViewer и рендерит стартовый HTML (обычно это <img ... /> плюс <map ...> для тултипов/кликабельных регионов).
  • В разметке <div id="chart-container"> @Html.Raw(initialHtml) </div>: вставляет HTML диаграммы в контейнер.
  • Скрипт: каждые intervalMs миллисекунд делает GET на эндпоинт @Url.Page("SimpleLine", "ChartHtml") и получает свежий HTML диаграммы. Затем заменяет container.innerHTML целиком, чтобы одновременно обновить <img /> и связанный <map> (иначе сломаются usemap/тултипы).

Почему обновление без мерцания

  • Вы не перерисовываете весь документ, а только содержимое одного контейнера.
  • Меняете сразу и картинку, и карту областей. Это важно: если заменить только <img />, то подсказки и кликабельные зоны могут отстать.
  • fetch с cache: 'no-store' гарантирует, что браузер не возьмет кэш, а запросит новый HTML/изображение.

Про адрес @Url.Page("SimpleLine", "ChartHtml")

  • Это вызов хендлера OnGetChartHtml в SimpleLine.cshtml.cs. Он должен вернуть ContentResult с text/html, где вы делаете viewer.RenderHTML() заново на каждом запросе (и, возможно, обновляете данные перед этим).

Зачем ViewData["Viewer"]

  • В OnGet вы создаете данные и на их основе создаете ChartDirector.Chart и RazorChartViewer. Viewer вы кладете в ViewData["Viewer"], чтобы страница могла получить готовый HTML уже при первом рендере без ожидания fetch.

Почему редактор подчеркивает (RazorChartViewer)ViewData["Viewer"] зеленой волной

  • Зеленая волнистая — это предупреждение (warning), а не ошибка. Обычно это:
    • CS8619/CS8600/CS8602/CS8605 из-за nullable reference types: ViewData возвращает object? (может быть null), и явное приведение к RazorChartViewer без проверки на null рискует NRE. Редактор предупреждает о потенциальном null.
    • Или IDE0004/IDE0019/IDE0020 стилистика: явное приведение может считаться небезопасным/избыточным с точки зрения стиля, лучше использовать безопасное «as» и проверить на null, или вынести в локальную переменную с pattern matching.
  • В Razor ViewData — это словарь Dictionary<string, object?>. Компилятор не знает, что по ключу "Viewer" всегда лежит RazorChartViewer и не null, поэтому и ругается.

Как убрать предупреждение корректно

  • Вариант с безопасным приведением и проверкой:
    @{
    var viewer = ViewData["Viewer"] as RazorChartViewer;
    if (viewer == null)
    {
    throw new InvalidOperationException("Viewer is not provided in ViewData[&quot;Viewer&quot;].");
    }
    var initialHtml = viewer.RenderHTML();
    }
  • Вариант с pattern matching:
    @{
    if (ViewData["Viewer"] is RazorChartViewer viewer)
    {
    var initialHtml = viewer.RenderHTML();
    }
    else
    {
    throw new InvalidOperationException("Viewer is not provided or has wrong type.");
    }
    }
  • Если вы уверены, что null быть не может, можно использовать оператор null-forgiving, чтобы успокоить анализатор, но это на ваш риск:
    @{
    var initialHtml = ((RazorChartViewer)ViewData["Viewer"]!).RenderHTML();
    }
  • Или задать строго типизированную модель/свойство, чтобы не тащить через ViewData:
    В модели страницы:
    public RazorChartViewer Viewer { get; private set; } = default!;
    public void OnGet()
    {
    // ... создаете chart и viewer
    Viewer = yourViewer;
    }
    В Razor:
    var initialHtml = Model.Viewer.RenderHTML();
    Это самый чистый и безопасный способ, а предупреждение исчезнет, потому что тип известен.

Типичные места, где еще появляются такие предупреждения

  • Когда используете HttpContext.Items, TempData, ViewBag/ViewData — везде, где тип object?.
  • Когда в проекте включены nullable reference types (обычно в .csproj <nullable>enable</nullable>), анализатор строго следит за возможными null.

Итого

  • Код у вас правильный по логике и архитектуре: стартовый HTML — через сервер, дальше — легкое обновление через fetch без мерцания.
  • Зеленая волна — это предупреждение анализа null-безопасности из-за приведения типа из ViewData. Исправьте через as + проверка, pattern matching, null-forgiving оператор, либо, лучше, используйте свойство Model.Viewer и не храните viewer в ViewData.
А вот сообщения в консоли выводятся warn
warn: Microsoft.WebTools.BrowserLink.Net.BrowserLinkMiddleware[3]
Unable to configure Browser Link script injection on the response.
ЧТо делать ?
Это предупреждение связано с 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.

--------------------------------------------------------------------------------------------

D:\VC2508\Charts\WpfChartSln\WpfChartDir\RazorChartDirApp07\RazorChartDirApp07.csproj

Под “JS-таймером” я имел в виду обычные функции таймера в браузере: setInterval и setTimeout. Они просто планируют вызов вашего кода через заданный интервал. Сейчас вы используете таймер, но дергаете window.location.reload(), из‑за этого перезагружается вся страница, мигает меню и иконка Refresh.

Если цель — автообновлять только график, оставив страницу и меню статичными, замените полную перезагрузку на частичную подгрузку HTML или данных и обновление DOM. Есть три рабочих варианта под Razor Pages + ChartDirector:

  1. Подгружать готовый HTML графика из отдельного endpoint
  • В SimpleLineModel рендерить только график (как сейчас), но вынести это в отдельную страницу/handler, например /SimpleLine?handler=Chart.
  • В основной странице оставить контейнер <div id="chartHost"></div>.
  • Каждую секунду подменять innerHTML этого контейнера свежим HTML через fetch.

Пример:

Razor (страница с меню и контейнером):

  • Вместо @Html.Raw(ViewBag.Viewer.RenderHTML()):
    <div id="chartHost"></div>

@section Scripts {
<script>
async function refreshChart() {
try {
const r = await fetch('@Url.Page("SimpleLine", null, new { handler = "Chart" }, Context.Request.Scheme)', { cache: "no-store" });
const html = await r.text();
document.getElementById('chartHost').innerHTML = html;
} catch(e) {
console.error(e);
}
}
refreshChart();
const timerId = setInterval(refreshChart, 1000);
// при навигации можно clearInterval(timerId)
</script>
}

C# (в той же Razor Page):
public IActionResult OnGetChart()
{
ViewData["Title"] = "Simple Line Chart";
var viewer = new RazorChartViewer(HttpContext, "chart1");
createChart(viewer);
// Вернем только HTML графика без layout
return Content(viewer.RenderHTML(), "text/html");
}

  1. Возвращать только данные (JSON) и перерисовывать график клиентом
  • Написать OnGetData(), который отдает массив значений синуса и метки.
  • На клиенте рисовать через Canvas/SVG библиотеку (Chart.js, ECharts, uPlot). Плюс: вообще не дергаете ChartDirector на каждом тике; минус: надо один раз настроить клиентскую библиотеку.
  1. Если ChartDirector отдает URL на изображение/SVG, обновлять только src
  • Если viewer.RenderHTML() вставляет <img src="..." />, то можно менять src на тот же URL с anti-cache параметром, не перерисовывая остальной DOM.
    Пример:
  • Оберните <img /> в контейнер с id, найдите <img /> и раз в секунду делайте img.src = baseUrl + "?t=" + Date.now();
  • Если это SVG-вставка, можно подменять весь innerHTML контейнера через fetch как в варианте 1.

Почему мигал браузер

  • window.location.reload() полностью перезагружает документ, поэтому перерисовывается весь layout, меню, обновляется вкладка — это норма для полной перезагрузки.
  • Таймер тут лишь триггер; “волшебство” в том, что вместо reload вы вызываете частичную загрузку и замену нужного куска DOM.

Минимальная правка вашего кода

  • Замените блок Scripts на:

@section Scripts {
<script>
async function refreshChart() {
try {
const res = await fetch('@Url.Page("SimpleLine", null, new { handler = "Chart" }, Context.Request.Scheme)', { cache: "no-store" });
const html = await res.text();
document.getElementById('chartHost').innerHTML = html;
} catch (err) {
console.error('Refresh failed', err);
}
}
refreshChart();
const timerId = setInterval(refreshChart, 1000);
</script>
}

  • И в разметке вместо текущего блока с RenderHTML выведите только контейнер:
    <div id="chartHost"></div>
  • Добавьте в PageModel handler OnGetChart(), который создает viewer и возвращает Content(viewer.RenderHTML(), "text/html"); как показано выше.

Так вы сохраните стабильный layout, а обновляться будет только график. Если расскажете, какой HTML генерирует RazorChartViewer (img или inline svg), подскажу самый простой способ адресной подмены. Если хотите совсем без опроса, можно перейти на SignalR/WebSocket и пушить обновления по событию.

RazorPage, Project, ChartDirector, Sine

RazorPage, Project, ChartDirector, Sine

D:\VC2508\Charts\WpfChartSln\WpfChartDir\WpfChartDir.sln

D:\VC2508\Charts\WpfChartSln\WpfChartDir\RazorChartDirApp07\RazorChartDirApp07.csproj

ChartDirector, Синусоида, work well

Page work well

---------------------------------------------------------------------------
SimpleLine.cshtml

@* @page

@model RazorChartDirApp07.Pages.SimpleLineModel

@{

} *@


@page

@model SimpleLineModel

@using ChartDirector

@{

    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())

    }

}


@section Scripts {

    <script>

        setTimeout(function () { window.location.reload(); }, 1000);

    </script>

}

-------------------------------
SimpleLine.cshtml.cs
------------------------------

using ChartDirector;

using LinSpace;

using Microsoft.AspNetCore.Mvc;

using Microsoft.AspNetCore.Mvc.RazorPages;

using RazorChartDirApp07.Services;


namespace RazorChartDirApp07.Pages

{

    public class SimpleLineModel : PageModel

    {

        private readonly IRunningSineState _state;

        private readonly ILogger<IndexModel> _logger;


        public SimpleLineModel(IRunningSineState state, ILogger<IndexModel> logger)

        {

            _state = state;

            _logger = logger;

        }

        public void OnGet()

        {

            ViewData["Title"] = "Simple Line Chart";

            RazorChartViewer viewer = new RazorChartViewer(HttpContext, "chart1");

            ViewData["Viewer"] = viewer;

            createChart(viewer);

        }

        private void createChart(RazorChartViewer viewer)

        {

            _logger.Log(LogLevel.Information, "CurrentIndex: " + _state.CurrentIndex.ToString());

            var dataArg = MathSeries.Linspace(0.0, 2 * Math.PI, 36, _state.CurrentIndex);

            var data = MathSeries.Evaluate(dataArg, Math.Sin);

            var nextIndex = _state.NextIndex(36);

            _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'");

        }

    }

}


воскресенье, 17 августа 2025 г.