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 ในทุกหน้าและมันก็ทำงานได้
