ค้นหาเว็บไซต์

ASP.NET CORE [Razor Pages] แอปเว็บเรียลไทม์ด้วย SignalR และ Typescript


ฉันกำลังทำงานกับ SignalR และการพัฒนาเว็บแบบเรียลไทม์อยู่ในตอนนี้

ฉันสับสนเล็กน้อยเพราะ JavaScript และ TypeScript

มีสองสถานการณ์ที่ฉันกำลังทำงานอยู่:

สถานการณ์แรกกับ TypeScript: ./clients/index.html ดูเหมือนดังนี้:

<!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 ดูเหมือนดังนี้:

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

และใน Program.cs ฉันกำลังใช้ UseStaticFiles และ UseDefaultFiles และมันดูเหมือนแบบนี้: 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();

ตอนนี้เรื่องมันคือ:

ฉันต้องการรวม Razor Pages กับ SignalR เพื่อทำฟังก์ชันบางอย่างรอบ ๆ โครงการแบบเรียลไทม์และบางอย่างไม่แบบเรียลไทม์

เป็นไปได้ไหมที่จะรวม Razor และทำการเรียกไปยัง HUB ของฉันจากตัวอย่างเช่น ./Pages/Account/Details (และในทางกลับกัน) [จาก hub ไปยังหน้า razor] [จากหน้า razor ไปยัง hub]

ถ้าใช่ โปรดฝากคำแนะนำให้ฉันว่าควรทำอย่างไร..

สถานการณ์ที่สองคือ: การทำงานกับ JS แต่ฉันพยายามใช้มัน แต่ก็ไม่สำเร็จสำหรับฉัน

ฉันอยากลองใช้ไทป์สคริปต์เพราะมันเหมาะกับฉันมากกว่า

ด้วยความเคารพอย่างสูง,

####อัปเดต

ฉันเห็นว่าไฟล์ index.ts ของฉันกำลังสร้างไฟล์ "main.~~~~~~.js

เป็นไปได้ไหมที่จะใช้บางข้อมูลอ้างอิงเช่นกับส่วนนั้น?

#####อัปเดต

ฉันสามารถเรียกใช้วิธีของฉันจากหน้า Razor ด้วยปุ่มและมันมีลักษณะดังนี้: 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);
        }
    }

ถ้าคุณมีไอเดียว่าควรทำตามมันอย่างไร กรุณาฝากความคิดเห็นหรือแม้แต่เสนอวิธีแก้ไข

คำตอบ #1

ฉันไม่แน่ใจว่านี่คือสิ่งที่คุณต้องการหรือไม่ แต่คุณสามารถกำหนดส่วนการแสดงผลภายใน _Layout.cshtml ได้

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

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

จากนั้นภายในหน้าเรเซอร์ของคุณให้เพิ่ม:

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

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

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

แก้ไข:

ใน Hub ของคุณ คุณสามารถกำหนดวิธีการที่ส่งเหตุการณ์ viewCountUpdate ไปยังลูกค้าได้

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

จากนั้นเรียกใช้มันจาก TypeScript โดยใช้

await connection.invoke("CountUpdate");

คำตอบ #2

ตอนนี้ ผ่านไปไม่กี่ชั่วโมงฉันกำลังมาที่นี่เพื่อบอกคุณว่าฉันค้นหาวิธีแก้ปัญหาของฉันอย่างไร

ฉันตัดสินใจที่จะออกจาก TS และฉันตัดสินใจที่จะไปกับ JS

นี่คือคำอธิบายแบบง่าย:

ชั้น Hub ของฉัน:

 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);
        }

อินเทอร์เฟซของฮับของฉัน:

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>
}

ไฟล์ 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();

และตอนนี้ฉันสามารถเพิ่มการอ้างอิงไปยังสคริปต์ JS ในทุกหน้าและมันก็ทำงานได้