skip to Main Content

i am working with SignalR and real time web development atm.

I am little confused because of JavaScript and TypeScript.

There are two scenarios i am working on:

First scenario with TypeScript:
./clients/index.html looks like this:

<!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 looks like this:

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

and in Program.cs i am using UseStaticFiles and UseDefaultFiles and it looks like this:
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();

Now the thing is:

I want to combine Razor Pages with SignalR to make some functions around the project in real time and some not.

Is this possible to combine razor and make calls to my HUB from in example ./Pages/Account/Details (and vice versa)
[from hub to razor page] [from razor page to hub]

If yes, please leave me instruction how to..

Second scenario is:
working with JS, but i was trying to go with it, but it doesnt work for me.

i want to try typescript because it fits me more.

Best Regards,

####UPDATE

I see my index.ts is generating file "main.~~~~~~.js

Is this possible to use some references like with section?

#####UPDATE

I can invoke my method from Razor Page with button and it looks like this:
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);
        }
    }

If you have any ideas how to go along with it, please leave a comment or even a solution.

2

Answers


  1. I’m not sure if this is what you need but you can define a render section inside _Layout.cshtml

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

    Then inside your razor page add:

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

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

    Edit:

    In your Hub you can define a method that pushes the viewCountUpdate event to the clients.

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

    Then call it from typescript using

    await connection.invoke("CountUpdate");
    
    Login or Signup to reply.
  2. Now, few hours later i am comming here to tell you how i find out of my problem.

    I decide to leave TS and i decide to go along with JS.

    This is simple explanation:

    My Hub class:

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

    My Hub Interface:

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

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

    And now i can add reference to js scripts in everysingle page and it works.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search