ASP.NET Core SignalR JavaScript istemcisi

Tarafından Rachel Appel

ASP.NET Core SignalR JavaScript istemci kitaplığı, geliştiricilerin sunucu tarafı SignalR hub kodunu çağırmasına olanak tanır.

SignalR İstemci paketini yükleme

SignalR JavaScript istemci kitaplığı bir npm paketi olarak teslim edilir. Aşağıdaki bölümlerde istemci kitaplığını yüklemenin farklı yolları özetlenmiştir.

npm ile yükleme

Paket Yöneticisi Konsolu'ndan aşağıdaki komutları çalıştırın:

npm init -y
npm install @microsoft/signalr

npm, paket içeriğini node_modules\@microsoft\signalr\dist\browser klasörüne yükler. wwwroot/lib/signalr klasörünü oluşturun. signalr.js Dosyayı wwwroot/lib/signalr klasörüne kopyalayın.

öğesinde SignalR JavaScript istemcisine <script> başvurun. Örneğin:

<script src="~/lib/signalr/signalr.js"></script>

Content Delivery Network (CDN) kullanma

İstemci kitaplığını npm önkoşulu olmadan kullanmak için istemci kitaplığının CDN tarafından barındırılan bir kopyasına başvurun. Örneğin:

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

İstemci kitaplığı aşağıdaki CDN'lerde kullanılabilir:

LibMan ile yükleme

LibMan , CDN tarafından barındırılan istemci kitaplığından belirli istemci kitaplığı dosyalarını yüklemek için kullanılabilir. Örneğin, projeye yalnızca küçültüldü JavaScript dosyasını ekleyin. Bu yaklaşımla ilgili ayrıntılar için bkz. İstemci kitaplığınıSignalR ekleme.

Hub'a Bağlan

Aşağıdaki kod bir bağlantı oluşturur ve başlatır. Hub'ın adı büyük/küçük harfe duyarlı değildir:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .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();
});

// Start the connection.
start();

Çıkış noktaları arası bağlantılar (CORS)

Genellikle, tarayıcılar istenen sayfayla aynı etki alanından bağlantıları yükler. Ancak, başka bir etki alanına bağlantının gerekli olduğu durumlar vardır.

Etki alanları arası isteklerde bulunurken istemci kodunun göreli URL yerine mutlak bir URL kullanması gerekir. Etki alanları arası istekler için olarak .withUrl("https://{App domain name}/chathub")değiştirin.withUrl("/chathub").

Kötü amaçlı bir sitenin başka bir siteden hassas verileri okumasını önlemek için çıkış noktaları arası bağlantılar varsayılan olarak devre dışı bırakılır. Çıkış noktaları arası bir isteğe izin vermek için CORS'yi etkinleştirin:

using SignalRChat.Hubs;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(
        builder =>
        {
            builder.WithOrigins("https://example.com")
                .AllowAnyHeader()
                .WithMethods("GET", "POST")
                .AllowCredentials();
        });
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

// UseCors must be called before MapHub.
app.UseCors();

app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");

app.Run();

UseCors çağrılmadan MapHubönce çağrılmalıdır.

İstemciden çağrı hub'ı yöntemleri

JavaScript istemcileri Hub Bağlan ion'ın invoke yöntemi aracılığıyla hub'larda genel yöntemleri çağırır. invoke yöntemi aşağıdakileri kabul eder:

  • Hub yönteminin adı.
  • Hub yönteminde tanımlanan tüm bağımsız değişkenler.

Aşağıdaki vurgulanan kodda, hub'daki yöntem adı şeklindedir SendMessage. Hub yönteminin user ve bağımsız değişkenleriyle eşlemek için invoke geçirilen ikinci ve message üçüncü bağımsız değişkenler:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

İstemciden hub yöntemlerini çağırmak yalnızca Azure SignalR Hizmeti Varsayılan modda kullanılırken desteklenir. Daha fazla bilgi için bkz . Sık Sorulan Sorular (azure-signalr GitHub deposu).

invoke yöntemi bir JavaScript Promisedöndürür. Promise, sunucudaki yöntem döndürdüğünde dönüş değeriyle (varsa) çözümlenir. Sunucudaki yöntem bir hata oluşturursa, Promise hata iletisiyle reddedilir. Bu durumları işlemek için ve await veya thenPromiseve catch yöntemlerini kullanınasync.

JavaScript istemcileri, gönderme yöntemi aracılığıyla hub'larda genel yöntemleri HubConnectionde çağırabilir. yönteminden invoke farklı olarak send , yöntemi sunucudan yanıt beklemez. send yöntemi bir JavaScript Promisedöndürür. , Promise ileti sunucuya gönderildiğinde çözülür. İleti gönderilirken bir hata varsa, Promise hata iletisiyle reddedilir. Bu durumları işlemek için ve await veya thenPromiseve catch yöntemlerini kullanınasync.

kullanmak send, sunucu iletiyi alana kadar beklemez . Sonuç olarak, sunucudan veri veya hata döndürmek mümkün değildir.

Hub'dan istemci yöntemlerini çağırma

Hub'dan ileti almak için on yöntemini kullanarak bir yöntem HubConnectiontanımlayın.

  • JavaScript istemci yönteminin adı.
  • Hub'ın yöntemine geçirdiği bağımsız değişkenler.

Aşağıdaki örnekte yöntem adı şeklindedir ReceiveMessage. Bağımsız değişken adları şunlardıruser:message

connection.on("ReceiveMessage", (user, message) => {
    const li = document.createElement("li");
    li.textContent = `${user}: ${message}`;
    document.getElementById("messageList").appendChild(li);
});

içindeki connection.on önceki kod, sunucu tarafı kodu yöntemini kullanarak SendAsync çağırdığında çalışır:

using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs;

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

SignalRve connection.oniçinde SendAsync tanımlanan yöntem adı ve bağımsız değişkenleriyle eşleşerek hangi istemci yönteminin çağrıldığını belirler.

En iyi yöntem, sonrasında onbaşlangıç yöntemini çağırmaktırHubConnection. Bunun yapılması, herhangi bir ileti alınmadan önce işleyicilerin kaydedilmesini sağlar.

Hata işleme ve günlüğe kaydetme

İstemci bağlanamaz veya ileti gönderemezse tarayıcının konsoluna hata çıkarmak için kullanın console.error :

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Bağlantı kurulurken günlüğe kaydedilecek bir günlükçü ve olay türünü geçirerek istemci tarafı günlük izlemesini ayarlayın. İletiler belirtilen günlük düzeyinde ve daha yüksek bir değerle günlüğe kaydedilir. Kullanılabilir günlük düzeyleri aşağıdaki gibidir:

  • signalR.LogLevel.Error: Hata iletileri. Yalnızca iletileri günlüğe kaydeder Error .
  • signalR.LogLevel.Warning: Olası hatalar hakkında uyarı iletileri. Error ve iletilerini günlüğe kaydederWarning.
  • signalR.LogLevel.Information: Hatasız durum iletileri. , Warningve Error iletilerini günlüğe kaydederInformation.
  • signalR.LogLevel.Trace: İletileri izleme. Hub ile istemci arasında taşınan veriler de dahil olmak üzere her şeyi günlüğe kaydeder.

Günlük düzeyini yapılandırmak için Hub Bağlan ionBuilder'da configureLogging yöntemini kullanın. İletiler tarayıcı konsoluna kaydedilir:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .build();

İstemcileri yeniden bağlama

Otomatik olarak yeniden bağlanma

için SignalR JavaScript istemcisi, Hub Bağlan ionBuilder'da WithAutomaticReconnect yöntemi kullanılarak otomatik olarak yeniden bağlanacak şekilde yapılandırılabilir. Varsayılan olarak otomatik olarak yeniden bağlanmaz.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect()
    .build();

Herhangi bir parametre olmadan, WithAutomaticReconnect her yeniden bağlanma girişimini denemeden önce istemciyi sırasıyla 0, 2, 10 ve 30 saniye bekleyecek şekilde yapılandırılır. Dört başarısız denemeden sonra yeniden bağlanma denemesi durdurulur.

Yeniden bağlanma girişimlerini başlatmadan önce, :HubConnection

  • Duruma geçişler HubConnectionState.Reconnecting ve geri çağırmalarını tetikler onreconnecting .
  • Duruma geçiş Disconnected yapmaz ve otomatik yeniden bağlanma yapılandırılmamış gibi HubConnection geri çağırmalarını tetikleronclose.

Yeniden bağlanma yaklaşımı aşağıdakiler için bir fırsat sağlar:

  • Bağlantıyı kaybettiği konusunda kullanıcıları uyarın.
  • Kullanıcı arabirimi öğelerini devre dışı bırakın.
connection.onreconnecting(error => {
    console.assert(connection.state === signalR.HubConnectionState.Reconnecting);

    document.getElementById("messageInput").disabled = true;

    const li = document.createElement("li");
    li.textContent = `Connection lost due to error "${error}". Reconnecting.`;
    document.getElementById("messageList").appendChild(li);
});

İstemci ilk dört denemesinde başarıyla yeniden bağlanırsa, HubConnection duruma geri Connected döner ve geri çağrılarını tetikler onreconnected . Bu, kullanıcılara bağlantının yeniden kuruldığını bildirmek için bir fırsat sağlar.

Bağlantı sunucu için tamamen yeni göründüğünden, geri çağırmaya onreconnected yeni connectionId bir sağlanır.

onreconnected geri çağırmanın connectionId parametresi, anlaşması atlamak üzere yapılandırıldıysa HubConnection tanımlanmamıştır.

connection.onreconnected(connectionId => {
    console.assert(connection.state === signalR.HubConnectionState.Connected);

    document.getElementById("messageInput").disabled = false;

    const li = document.createElement("li");
    li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
    document.getElementById("messageList").appendChild(li);
});

withAutomaticReconnect ilk başlatma hatalarını yeniden denemek için öğesini yapılandırmaz HubConnection , bu nedenle başlatma hatalarının el ile işlenmesi gerekir:

async function start() {
    try {
        await connection.start();
        console.assert(connection.state === signalR.HubConnectionState.Connected);
        console.log("SignalR Connected.");
    } catch (err) {
        console.assert(connection.state === signalR.HubConnectionState.Disconnected);
        console.log(err);
        setTimeout(() => start(), 5000);
    }
};

İstemci ilk dört denemesinde başarıyla yeniden bağlanamazsa, HubConnection duruma geçişler Disconnected ve onclose geri çağırmalarını tetikler. Bu, kullanıcıları bilgilendirmek için bir fırsat sağlar:

  • Bağlantı kalıcı olarak kesildi.
  • Sayfayı yenilemeyi deneyin:
connection.onclose(error => {
    console.assert(connection.state === signalR.HubConnectionState.Disconnected);

    document.getElementById("messageInput").disabled = true;

    const li = document.createElement("li");
    li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
    document.getElementById("messageList").appendChild(li);
});

Bağlantıyı kesmeden veya yeniden bağlanma zamanlamasını değiştirmeden önce özel sayıda yeniden bağlanma girişimi yapılandırmak için, withAutomaticReconnect her yeniden bağlantı girişimine başlamadan önce beklenmesi gereken gecikmeyi milisaniye cinsinden gösteren bir sayı dizisini kabul eder.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect([0, 0, 10000])
    .build();

    // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

Yukarıdaki örnek, bağlantı kesildikten hemen sonra yeniden bağlanmayı başlatacak şekilde yapılandırılır HubConnection . Varsayılan yapılandırma yeniden bağlanmayı denemesi için de sıfır saniye bekler.

İlk yeniden bağlanma girişimi başarısız olursa, ikinci yeniden bağlanma girişimi de varsayılan yapılandırmayı kullanarak 2 saniye beklemek yerine hemen başlar.

İkinci yeniden bağlanma girişimi başarısız olursa, üçüncü yeniden bağlanma girişimi varsayılan yapılandırmayla aynı olan 10 saniye içinde başlar.

Yapılandırılan yeniden bağlantı zamanlaması, 30 saniye içinde bir yeniden bağlantı denemesi daha denemek yerine üçüncü yeniden bağlantı girişimi hatasından sonra durdurularak varsayılan davranıştan farklıdır.

Otomatik yeniden bağlanma girişimlerinin zamanlaması ve sayısı üzerinde daha fazla denetim için, withAutomaticReconnect adlı nextRetryDelayInMillisecondstek bir yöntemi olan arabirimini uygulayan IRetryPolicy bir nesneyi kabul eder.

nextRetryDelayInMilliseconds türünde RetryContexttek bir bağımsız değişken alır. üç RetryContext özelliğe sahiptir: previousRetryCountelapsedMilliseconds ve retryReason sırasıyla , numbera number ve şeklindedirError. İlk yeniden bağlanma girişiminden önce hem hem elapsedMilliseconds de previousRetryCount sıfır olur ve retryReason bağlantının kaybolmasına neden olan Hata olur. Her başarısız yeniden deneme girişiminden sonra bir previousRetryCount artırılır, elapsedMilliseconds şimdiye kadar yeniden bağlanmaya harcanan süreyi milisaniye cinsinden yansıtacak şekilde güncelleştirilir ve retryReason son yeniden bağlanma girişiminin başarısız olmasına neden olan Hata olur.

nextRetryDelayInMilliseconds bir sonraki yeniden bağlanma girişiminden önce beklenmesi gereken milisaniye sayısını veya null yeniden bağlanmayı durdurması HubConnection gerektiğini gösteren bir sayı döndürmelidir.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect({
        nextRetryDelayInMilliseconds: retryContext => {
            if (retryContext.elapsedMilliseconds < 60000) {
                // If we've been reconnecting for less than 60 seconds so far,
                // wait between 0 and 10 seconds before the next reconnect attempt.
                return Math.random() * 10000;
            } else {
                // If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
                return null;
            }
        }
    })
    .build();

Alternatif olarak, aşağıdaki bölümde gösterildiği gibi istemciyi el ile yeniden bağlayan kod yazılabilir.

El ile yeniden bağlanma

Aşağıdaki kod tipik bir el ile yeniden bağlanma yaklaşımını gösterir:

  1. Bağlantıyı başlatmak için bir işlev (bu durumda start işlev) oluşturulur.
  2. Bağlantının start olay işleyicisinde işlevini çağırın onclose .
async function start() {
    try {
        await connection.start();
        console.log("SignalR Connected.");
    } catch (err) {
        console.log(err);
        setTimeout(start, 5000);
    }
};

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

Üretim uygulamaları genellikle üstel bir geri çekilme kullanır veya belirtilen sayıda yeniden dener.

Tarayıcı uyku sekmesi

Bazı tarayıcılarda, etkin olmayan sekmeler için bilgisayar kaynağı kullanımını azaltmak için sekme dondurma veya uyku özelliği vardır. Bu, bağlantıların kapanmasına neden SignalR olabilir ve istenmeyen bir kullanıcı deneyimine neden olabilir. Tarayıcılar, aşağıdakiler gibi bir sekmenin uyku moduna alınması gerekip gerekmediğini bulmak için buluşsal yöntemler kullanır:

  • Ses çalma
  • Web kilidi tutma
  • Kilit tutma IndexedDB
  • USB cihazına bağlı olma
  • Video veya ses yakalama
  • Yansıtılıyor
  • Pencere veya ekran yakalama

Tarayıcı buluşsal yöntemleri zaman içinde değişebilir ve tarayıcılar arasında farklılık gösterebilir. Destek matrisini gözden geçirin ve senaryolarınız için en uygun yöntemin hangisi olduğunu öğrenin.

Bir uygulamayı uyku moduna almaktan kaçınmak için, uygulamanın tarayıcının kullandığı buluşsal yöntemlerden birini tetiklemesi gerekir.

Aşağıdaki kod örneğinde, bir sekmeyi uyanık tutmak ve beklenmeyen bir bağlantının kapatılmasını önlemek için Web Kilidi'nin nasıl kullanılacağı gösterilmektedir.

var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
    const promise = new Promise((res) => {
        lockResolver = res;
    });

    navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
        return promise;
    });
}

Yukarıdaki kod örneği için:

  • Web Kilitleri deneyseldir. Koşullu denetim, tarayıcının Web Kilitleri'ni desteklediğini onaylar.
  • Promise çözümleyicisi, lockResolversekmenin uyku moduna alınması kabul edilebilir olduğunda kilidin serbest bırakılabilmesi için depolanır.
  • Bağlantı kapatılırken kilit çağrılarak lockResolver()serbest bırakılır. Kilit serbest bırakıldığında sekmenin uyku moduna girmesine izin verilir.

Ek kaynaklar

Tarafından Rachel Appel

ASP.NET Core SignalR JavaScript istemci kitaplığı, geliştiricilerin sunucu tarafı hub kodunu çağırmasına olanak tanır.

Örnek kodu görüntüleme veya indirme (indirme)

SignalR İstemci paketini yükleme

SignalR JavaScript istemci kitaplığı bir npm paketi olarak teslim edilir. Aşağıdaki bölümlerde istemci kitaplığını yüklemenin farklı yolları özetlenmiştir.

npm ile yükleme

Visual Studio için, kök klasördeyken Paket Yöneticisi Konsolu'ndan aşağıdaki komutları çalıştırın. Visual Studio Code için, Tümleşik Terminal'den aşağıdaki komutları çalıştırın.

npm init -y
npm install @microsoft/signalr

npm, paket içeriğini node_modules\@microsoft\signalr\dist\browser klasörüne yükler. wwwroot\lib klasörünün altında signalr adlı yeni bir klasör oluşturun. signalr.js Dosyayı wwwroot\lib\signalr klasörüne kopyalayın.

öğesinde SignalR JavaScript istemcisine <script> başvurun. Örneğin:

<script src="~/lib/signalr/signalr.js"></script>

Content Delivery Network (CDN) kullanma

İstemci kitaplığını npm önkoşulu olmadan kullanmak için istemci kitaplığının CDN tarafından barındırılan bir kopyasına başvurun. Örneğin:

<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>

İstemci kitaplığı aşağıdaki CDN'lerde kullanılabilir:

LibMan ile yükleme

LibMan , CDN tarafından barındırılan istemci kitaplığından belirli istemci kitaplığı dosyalarını yüklemek için kullanılabilir. Örneğin, projeye yalnızca küçültüldü JavaScript dosyasını ekleyin. Bu yaklaşımla ilgili ayrıntılar için bkz. İstemci kitaplığınıSignalR ekleme.

Hub'a Bağlan

Aşağıdaki kod bir bağlantı oluşturur ve başlatır. Hub'ın adı büyük/küçük harfe duyarlı değildir:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .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();
});

// Start the connection.
start();

Çıkış noktaları arası bağlantılar

Genellikle, tarayıcılar istenen sayfayla aynı etki alanından bağlantıları yükler. Ancak, başka bir etki alanına bağlantının gerekli olduğu durumlar vardır.

Önemli

İstemci kodu göreli URL yerine mutlak BIR URL kullanmalıdır. .withUrl("/chathub") değerini .withUrl("https://myappurl/chathub") olarak değiştirin.

Kötü amaçlı bir sitenin başka bir siteden hassas verileri okumasını önlemek için çıkış noktaları arası bağlantılar varsayılan olarak devre dışı bırakılır. Çıkış noktaları arası bir isteğe izin vermek için bunu sınıfında etkinleştirin Startup :

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SignalRChat.Hubs;

namespace SignalRChat
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddSignalR();

            services.AddCors(options =>
            {
                options.AddDefaultPolicy(builder =>
                {
                    builder.WithOrigins("https://example.com")
                        .AllowCredentials();
                });
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();
            app.UseRouting();

            app.UseCors();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapHub<ChatHub>("/chathub");
            });
        }
    }
}

İstemciden çağrı hub'ı yöntemleri

JavaScript istemcileri Hub Bağlan ion'ın invoke yöntemi aracılığıyla hub'larda genel yöntemleri çağırır. invoke yöntemi aşağıdakileri kabul eder:

  • Hub yönteminin adı.
  • Hub yönteminde tanımlanan tüm bağımsız değişkenler.

Aşağıdaki örnekte, hub'daki yöntem adı şeklindedir SendMessage. Hub yönteminin user ve bağımsız değişkenleriyle eşlemek için invoke geçirilen ikinci ve message üçüncü bağımsız değişkenler:

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Dekont

İstemciden hub yöntemlerini çağırmak yalnızca Azure SignalR Hizmeti Varsayılan modda kullanılırken desteklenir. Daha fazla bilgi için bkz . Sık Sorulan Sorular (azure-signalr GitHub deposu).

invoke yöntemi bir JavaScript Promisedöndürür. Promise, sunucudaki yöntem döndürdüğünde dönüş değeriyle (varsa) çözümlenir. Sunucudaki yöntem bir hata oluşturursa, Promise hata iletisiyle reddedilir. Bu durumları işlemek için ve await veya thenPromiseve catch yöntemlerini kullanınasync.

JavaScript istemcileri, gönderme yöntemi aracılığıyla hub'larda genel yöntemleri HubConnectionde çağırabilir. yönteminden invoke farklı olarak send , yöntemi sunucudan yanıt beklemez. send yöntemi bir JavaScript Promisedöndürür. , Promise ileti sunucuya gönderildiğinde çözülür. İleti gönderilirken bir hata varsa, Promise hata iletisiyle reddedilir. Bu durumları işlemek için ve await veya thenPromiseve catch yöntemlerini kullanınasync.

Dekont

kullanmak send , sunucu iletiyi alana kadar beklemez. Sonuç olarak, sunucudan veri veya hata döndürmek mümkün değildir.

Hub'dan istemci yöntemlerini çağırma

Hub'dan ileti almak için on yöntemini kullanarak bir yöntem HubConnectiontanımlayın.

  • JavaScript istemci yönteminin adı.
  • Hub'ın yöntemine geçirdiği bağımsız değişkenler.

Aşağıdaki örnekte yöntem adı şeklindedir ReceiveMessage. Bağımsız değişken adları şunlardıruser:message

connection.on("ReceiveMessage", (user, message) => {
    const li = document.createElement("li");
    li.textContent = `${user}: ${message}`;
    document.getElementById("messageList").appendChild(li);
});

içindeki connection.on önceki kod, sunucu tarafı kodu yöntemini kullanarak SendAsync çağırdığında çalışır:

public async Task SendMessage(string user, string message)
{
    await Clients.All.SendAsync("ReceiveMessage", user, message);
}

SignalRve connection.oniçinde SendAsync tanımlanan yöntem adı ve bağımsız değişkenleriyle eşleşerek hangi istemci yönteminin çağrıldığını belirler.

Dekont

En iyi uygulama olarak, sonrasında üzerinde başlangıç yöntemini çağırın HubConnection.on Bunun yapılması, herhangi bir ileti alınmadan önce işleyicilerinizin kaydedilmesini sağlar.

Hata işleme ve günlüğe kaydetme

catch İstemci tarafı hatalarını işlemek için ve await ile async veya catchPromiseile yöntemini kullanıntry. Tarayıcının konsolunda hata çıktısı almak için kullanın console.error :

try {
    await connection.invoke("SendMessage", user, message);
} catch (err) {
    console.error(err);
}

Bağlantı kurulurken günlüğe kaydedilecek bir günlükçü ve olay türünü geçirerek istemci tarafı günlük izlemesini ayarlayın. İletiler belirtilen günlük düzeyinde ve daha yüksek bir değerle günlüğe kaydedilir. Kullanılabilir günlük düzeyleri aşağıdaki gibidir:

  • signalR.LogLevel.Error: Hata iletileri. Yalnızca iletileri günlüğe kaydeder Error .
  • signalR.LogLevel.Warning: Olası hatalar hakkında uyarı iletileri. Error ve iletilerini günlüğe kaydederWarning.
  • signalR.LogLevel.Information: Hatasız durum iletileri. , Warningve Error iletilerini günlüğe kaydederInformation.
  • signalR.LogLevel.Trace: İletileri izleme. Hub ile istemci arasında taşınan veriler de dahil olmak üzere her şeyi günlüğe kaydeder.

Günlük düzeyini yapılandırmak için Hub Bağlan ionBuilder'da configureLogging yöntemini kullanın. İletiler tarayıcı konsoluna kaydedilir:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .configureLogging(signalR.LogLevel.Information)
    .build();

İstemcileri yeniden bağlama

Otomatik olarak yeniden bağlanma

için SignalR JavaScript istemcisi, Hub Bağlan ionBuilder'da yöntemi kullanılarak withAutomaticReconnect otomatik olarak yeniden bağlanacak şekilde yapılandırılabilir. Varsayılan olarak otomatik olarak yeniden bağlanmaz.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect()
    .build();

Herhangi bir parametre olmadan, withAutomaticReconnect() istemciyi her yeniden bağlanma girişimini denemeden önce sırasıyla 0, 2, 10 ve 30 saniye bekleyecek şekilde yapılandırarak başarısız olan dört denemeden sonra durdurulmasını sağlar.

Yeniden bağlanma girişimlerine başlamadan önce, HubConnection duruma onreconnecting geçiş HubConnectionState.Reconnecting ve otomatik yeniden bağlanma yapılandırılmamış gibi HubConnection geri çağırmalarını tetikleme onclose yerine Disconnected duruma geçiş ve geri çağırmaları tetikler. Bu, kullanıcıları bağlantının kaybolduğu konusunda uyarmak ve kullanıcı arabirimi öğelerini devre dışı bırakmak için bir fırsat sağlar.

connection.onreconnecting(error => {
    console.assert(connection.state === signalR.HubConnectionState.Reconnecting);

    document.getElementById("messageInput").disabled = true;

    const li = document.createElement("li");
    li.textContent = `Connection lost due to error "${error}". Reconnecting.`;
    document.getElementById("messageList").appendChild(li);
});

İstemci ilk dört denemesinde başarıyla yeniden bağlanırsa, HubConnection duruma geri Connected döner ve geri çağrılarını tetikler onreconnected . Bu, kullanıcılara bağlantının yeniden kuruldığını bildirmek için bir fırsat sağlar.

Bağlantı sunucu için tamamen yeni göründüğünden, geri çağırmaya onreconnected yeni connectionId bir sağlanacaktır.

Uyarı

onreconnected geri çağırma connectionId parametresi, anlaşma atlayacak şekilde yapılandırıldıysa HubConnectiontanımlanmamış olur.

connection.onreconnected(connectionId => {
    console.assert(connection.state === signalR.HubConnectionState.Connected);

    document.getElementById("messageInput").disabled = false;

    const li = document.createElement("li");
    li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
    document.getElementById("messageList").appendChild(li);
});

withAutomaticReconnect() ilk başlatma hatalarını yeniden denemek için öğesini yapılandırmaz HubConnection , bu nedenle başlatma hatalarının el ile işlenmesi gerekir:

async function start() {
    try {
        await connection.start();
        console.assert(connection.state === signalR.HubConnectionState.Connected);
        console.log("SignalR Connected.");
    } catch (err) {
        console.assert(connection.state === signalR.HubConnectionState.Disconnected);
        console.log(err);
        setTimeout(() => start(), 5000);
    }
};

İstemci ilk dört denemesinde başarılı bir şekilde yeniden bağlanamazsa, duruma geçirilecek Disconnected ve onclose geri çağırmalarını tetikleyecektir.HubConnection Bu, kullanıcılara bağlantının kalıcı olarak kaybolduğunu bildirmek ve sayfayı yenilemeyi önermek için bir fırsat sağlar:

connection.onclose(error => {
    console.assert(connection.state === signalR.HubConnectionState.Disconnected);

    document.getElementById("messageInput").disabled = true;

    const li = document.createElement("li");
    li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
    document.getElementById("messageList").appendChild(li);
});

Bağlantıyı kesmeden veya yeniden bağlanma zamanlamasını değiştirmeden önce özel sayıda yeniden bağlanma girişimi yapılandırmak için, withAutomaticReconnect her yeniden bağlantı girişimine başlamadan önce beklenmesi gereken gecikmeyi milisaniye cinsinden gösteren bir sayı dizisini kabul eder.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect([0, 0, 10000])
    .build();

    // .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

Yukarıdaki örnek, bağlantı kesildikten hemen sonra yeniden bağlanmayı başlatacak şekilde yapılandırılır HubConnection . Bu, varsayılan yapılandırma için de geçerlidir.

İlk yeniden bağlanma girişimi başarısız olursa, ikinci yeniden bağlanma girişimi de varsayılan yapılandırmada olduğu gibi 2 saniye beklemek yerine hemen başlar.

İkinci yeniden bağlanma girişimi başarısız olursa, üçüncü yeniden bağlanma girişimi 10 saniye içinde başlar ve bu yeniden varsayılan yapılandırmaya benzer.

Daha sonra özel davranış, varsayılan yapılandırmada olduğu gibi 30 saniye içinde bir yeniden bağlanma denemesi daha denemek yerine üçüncü yeniden bağlanma girişimi hatasından sonra durarak varsayılan davranıştan yeniden ayrılır.

Otomatik yeniden bağlanma girişimlerinin zamanlaması ve sayısı üzerinde daha fazla denetime sahip olmak istiyorsanız, withAutomaticReconnect adlı nextRetryDelayInMillisecondstek bir yöntemi olan arabirimi uygulayan IRetryPolicy bir nesneyi kabul eder.

nextRetryDelayInMilliseconds türünde RetryContexttek bir bağımsız değişken alır. üç RetryContext özelliğe sahiptir: previousRetryCountelapsedMilliseconds ve retryReason sırasıyla , numbera number ve şeklindedirError. İlk yeniden bağlanma girişiminden önce hem hem elapsedMilliseconds de previousRetryCount sıfır olur ve retryReason bağlantının kaybolmasına neden olan Hata olur. Her başarısız yeniden deneme girişiminden sonra bir previousRetryCount artırılır, elapsedMilliseconds şimdiye kadar yeniden bağlanmaya harcanan süreyi milisaniye cinsinden yansıtacak şekilde güncelleştirilir ve retryReason son yeniden bağlanma girişiminin başarısız olmasına neden olan Hata olur.

nextRetryDelayInMilliseconds bir sonraki yeniden bağlanma girişiminden önce beklenmesi gereken milisaniye sayısını veya null yeniden bağlanmayı durdurması HubConnection gerektiğini gösteren bir sayı döndürmelidir.

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chathub")
    .withAutomaticReconnect({
        nextRetryDelayInMilliseconds: retryContext => {
            if (retryContext.elapsedMilliseconds < 60000) {
                // If we've been reconnecting for less than 60 seconds so far,
                // wait between 0 and 10 seconds before the next reconnect attempt.
                return Math.random() * 10000;
            } else {
                // If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
                return null;
            }
        }
    })
    .build();

Alternatif olarak, el ile yeniden bağlanma bölümünde gösterildiği gibi istemcinizi el ile yeniden bağlayacak kod yazabilirsiniz.

El ile yeniden bağlanma

Aşağıdaki kod tipik bir el ile yeniden bağlanma yaklaşımını gösterir:

  1. Bağlantıyı başlatmak için bir işlev (bu durumda start işlev) oluşturulur.
  2. Bağlantının start olay işleyicisinde işlevini çağırın onclose .
async function start() {
    try {
        await connection.start();
        console.log("SignalR Connected.");
    } catch (err) {
        console.log(err);
        setTimeout(start, 5000);
    }
};

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

Üretim uygulamaları genellikle üstel bir geri çekilme kullanır veya belirtilen sayıda yeniden dener.

Tarayıcı uyku sekmesi

Bazı tarayıcılarda, etkin olmayan sekmeler için bilgisayar kaynağı kullanımını azaltmak için sekme dondurma veya uyku özelliği vardır. Bu, bağlantıların kapanmasına neden SignalR olabilir ve istenmeyen bir kullanıcı deneyimine neden olabilir. Tarayıcılar, aşağıdakiler gibi bir sekmenin uyku moduna alınması gerekip gerekmediğini bulmak için buluşsal yöntemler kullanır:

  • Ses çalma
  • Web kilidi tutma
  • Kilit tutma IndexedDB
  • USB cihazına bağlı olma
  • Video veya ses yakalama
  • Yansıtılıyor
  • Pencere veya ekran yakalama

Dekont

Bu buluşsal yöntemler zaman içinde değişebilir veya tarayıcılar arasında farklılık gösterebilir. Destek matrisinizi denetleyin ve senaryolarınız için en uygun yöntemin hangisi olduğunu öğrenin.

Bir uygulamayı uyku moduna almaktan kaçınmak için, uygulamanın tarayıcının kullandığı buluşsal yöntemlerden birini tetiklemesi gerekir.

Aşağıdaki kod örneğinde, bir sekmeyi uyanık tutmak ve beklenmeyen bir bağlantının kapatılmasını önlemek için Web Kilidi'nin nasıl kullanılacağı gösterilmektedir.

var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
    const promise = new Promise((res) => {
        lockResolver = res;
    });

    navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
        return promise;
    });
}

Yukarıdaki kod örneği için:

  • Web Kilitleri deneyseldir. Koşullu denetim, tarayıcının Web Kilitleri'ni desteklediğini onaylar.
  • Promise çözümleyicisi (lockResolver), sekmenin uyku moduna alınması kabul edilebilir olduğunda kilidin serbest bırakılabilmesi için depolanır.
  • Bağlantı kapatılırken kilit çağrılarak lockResolver()serbest bırakılır. Kilit serbest bırakıldığında sekmenin uyku moduna girmesine izin verilir.

Ek kaynaklar