ASP.NET CORE [Razor Pages] realtids webAPP med SignalR og Typescript


Jeg arbejder med SignalR og realtids webudvikling lige nu.

Jeg er lidt forvirret på grund af JavaScript og TypeScript.

Der er to scenarier, jeg arbejder på:

Første scenarie med TypeScript: ./clients/index.html ser sådan ud:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
<script defer src="/main.509cbdfefce2f16684e8.js"></script></head>
<body>
    <h1>Watching connection list</h1>
    <p>People watching this page: <span id="viewCounter">0</span></p>

    <h1>Passing arguments to the hub with a button</h1>
    <p>
        <input id="inputFirstName" />
        <input id="inputLastName" />
        <button id="btnGetFullName">Get Full Name</button>
    </p>
</body>
</html>

./clients/index.ts ser sådan ud:

import * as signalR from "@microsoft/signalr";


//COUNTER
var counter = document.getElementById("viewCounter");

//BUTTON - PASSING VALUES FROM WEBSITE TO HUB CONTROLLER
var button = document.getElementById("btnGetFullName");


// create connection
let connection = new signalR.HubConnectionBuilder()
    .configureLogging(signalR.LogLevel.Trace)
    .withUrl("/hub/view")
    .build();

// client event
connection.on("viewCountUpdate", (value: number) => {
    counter.innerText = value.toString();
});


//BUTTON - PASSING VALUES FROM WEBSITE TO HUB CONTROLLER
button.addEventListener("click", function (evt) {
    var firstName = (document.getElementById("inputFirstName") as HTMLInputElement).value;
    var lastName = (document.getElementById("inputLastName") as HTMLInputElement).value;
    connection.invoke("getFullName", firstName, lastName).then((name: string) => { alert(name); });
});

// notify server we're watching
function notify() {
    connection.send ("notifyWatching");
}
// start the connection
function startSuccess() {
    console.log("Connected.");
    //COUNTER
    notify();
}
function startFail() {
    console.log("Connection failed.");
}

connection.start().then(startSuccess, startFail);

og i Program.cs bruger jeg UseStaticFiles og UseDefaultFiles, og det ser sådan ud: using RealTimeApp.Hubs;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
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.UseDefaultFiles();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();
app.UseEndpoints(configure => {
    configure.MapHub<DevHub>("/hub/view");
});
app.Run();

Nu er sagen:

Jeg vil kombinere Razor Pages med SignalR for at lave nogle funktioner omkring projektet i realtid og nogle ikke.

Er det muligt at kombinere Razor og foretage opkald til min HUB fra for eksempel ./Pages/Account/Details (og omvendt) [fra hub til Razor-side] [fra Razor-side til hub]

Hvis ja, bedes du give mig instruktioner om, hvordan man...

Andet scenarie er: at arbejde med JS, men jeg prøvede at gå videre med det, men det virker ikke for mig.

Jeg vil prøve TypeScript, fordi det passer mig bedre.

Med venlig hilsen,

####OPDATERING

Jeg kan se, at min index.ts genererer filen "main.~~~~~~.js"

Er det muligt at bruge nogle referencer som med afsnittet?

#####OPDATERING

Jeg kan kalde min metode fra Razor-side med en knap, og det ser sådan ud: Razor.cshtml:

<form method="post" asp-page-handler="Test">
    <button>OnClickTest</button>
</form>

Razor.cshtml.cs

public class SiteModel : PageModel
    {
        private readonly IHubContext<DevHub> _hub;
        public SiteModel(IHubContext<DevHub> hub)
        {
            _hub = hub;
        }
        public void OnGet()
        {
        }
        public async Task OnPostTest()
        {
            await _hub.Clients.All.SendAsync("viewCountUpdate", 66);
        }
    }

Hvis du har nogen idéer til, hvordan man kan gå videre med det, så venligst efterlad en kommentar eller endda en løsning.

Svar #1

Jeg er ikke sikker på, om dette er, hvad du har brug for, men du kan definere en render-sektion inde i _Layout.cshtml

<body>
    ...
    ...
    ...

    @RenderSection("Scripts", required: false)
</body>

Indsæt derefter følgende i din razor-side:

<div id="counter"></div>

@section Scripts {
     <script defer src="/main.509cbdfefce2f16684e8.js"></script>
}

https://learn.microsoft.com/da-dk/aspnet/core/mvc/views/layout?view=aspnetcore-6.0#sections

Rediger:

I din Hub kan du definere en metode, der sender viewCountUpdate-begivenheden til klienterne.

public class DevHub : Hub
{
    public async Task CountUpdate()
        => await Clients.All.SendAsync("viewCountUpdate", 66);
}

Kald det derefter fra TypeScript ved hjælp af

await connection.invoke("CountUpdate");

Svar #2

Nu, få timer senere, kommer jeg her for at fortælle dig, hvordan jeg fandt ud af mit problem.

Jeg beslutter mig for at forlade TS, og jeg beslutter mig for at følge med JS.

Dette er en simpel forklaring:

Min Hub-klasse:

 public class MainHub : Hub<IMainHub>
    {
        public static int ViewCount { get; set; } = 0;

        //FROM HUB TO CLIENT
        public async override Task OnConnectedAsync()
        {
            ViewCount++;
            await Clients.All.ViewCountUpdate(ViewCount);
            await base.OnConnectedAsync();
        }
        public async override Task OnDisconnectedAsync(Exception exception)
        {
            ViewCount--;
            await Clients.All.ViewCountUpdate(ViewCount);
            await base.OnDisconnectedAsync(exception);
        }

Min Hub-grænseflade:

public interface IMainHub
{
    Task ViewCountUpdate(int viewCount);

}

Razor Index.cshtml:

<h1>Watching connection list</h1>
<p>People watching this page: <span id="viewCounter">0</span></p>

@section Scripts{
    <script src="~/lib/signalr/signalr.js"></script>
    <script src="~/index.js"></script>
}

Min index.js

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/testhub")
    .configureLogging(signalR.LogLevel.Trace)
    .withAutomaticReconnect([0, 10, 30, 60, 90, 150])
    .build();

async function start() {
    try {
        await connection.start();
        console.log("SignalR Connected.");
    } catch (err) {
        console.log(err);
        setTimeout(start, 5000);
    }
};

connection.onclose(async () => {
    await start();
});

//FROM HUB TO CLIENT [EVENTS]
connection.on("ViewCountUpdate", (viewCount) => {
    counter.innerHTML = viewCount;
});


// Start the connection.
start();

Og nu kan jeg tilføje reference til JS-scripts på hver eneste side, og det virker.

Relaterede artikler