ASP.NET Core SignalR, uygulamalara gerçek zamanlı web işlevselliği eklemeyi basitleştiren açık kaynaklı bir kütüphanedir. Gerçek zamanlı web işlevselliği, sunucu tarafı kodun içeriği istemcilere anında göndermesini sağlar.
SignalR için iyi adaylar:
SignalRCore sgcWebSockets bileşeni, bir SignalRCore sunucusuna bağlanmak için taşıma olarak WebSocket kullanır; bu taşıma desteklenmiyorsa, bir hata oluşur.
SignalRCore, istemciler ve sunucular arasında iletişim kurmak için hub'lar kullanır. SignalRCore 2 hub protokolü sağlar: JSON tabanlı metin protokolü ve MessagePack tabanlı ikili protokol. sgcWebSockets bileşeni, SignalRCore sunucularıyla iletişim kurmak için yalnızca JSON metin protokolünü uygular.
İstemcinin hangi Hub'ı kullanacağını yapılandırmak için, istemci sunucuya bağlanmadan önce SignalRCore/Hub özelliğinde Hub'ın adını ayarlamanız yeterlidir.
Bir istemci sunucuya yeni bir bağlantı açtığında, format protokolünü ve sürümünü içeren bir istek mesajı gönderir. sgcWebSockets her zaman format protokolünü JSON olarak gönderir. Sunucu, protokol sunucu tarafından desteklenmiyorsa bir hatayla yanıt verir; bu hata OnSignalRCoreError olayı kullanılarak işlenebilir ve bağlantı başarılı olursa OnSignalRCoreConnect olayı çağrılır.
Bir istemci bir SignalRCore sunucusuna bağlandığında, oturumlar arasında istemciyi tanımlayan bir ConnectionId gönderebilir, böylece bir bağlantı kesilirse istemci aynı önceki bağlantı id'sini geçirerek sunucuya yeniden bağlanabilir. Yeni bir bağlantı id'si almak için, sunucuya normal şekilde bağlanın ve OnBeforeConnectEvent kullanarak ConnectionId'yi öğrenebilirsiniz. Sunucuya yeniden bağlanmak ve önceki bir bağlantı id'sini geçirmek isterseniz, ReConnect yöntemini kullanın ve ConnectionId'yi parametre olarak geçirin.
SignalR Protokolü, herhangi bir Mesaj tabanlı taşıma üzerinden iki yönlü RPC için bir protokoldür. Bağlantıdaki her iki taraf da diğer tarafta prosedürleri çağırabilir ve prosedürler sıfır veya daha fazla sonuç veya bir hata döndürebilir. Örnek: istemci sunucudan bir yöntem isteyebilir ve sunucu istemciden bir yöntem isteyebilir. Sunucu ve istemciler arasında aşağıdaki mesajlar değiş tokuş edilir:
HandshakeRequest: istemci, mesaj formatı üzerinde anlaşmak için sunucuya gönderir.
HandshakeResponse: sunucu, önceki HandshakeRequest mesajının onayını istemciye yanıtlar. Handshake başarısız olursa bir hata içerir.
Close: bir bağlantı kapatıldığında istemci veya sunucu tarafından çağrılır. Bağlantı bir hata nedeniyle kapatıldıysa bir hata içerir.
Invocation: istemci veya sunucu, bir yöntemi argümanlarla veya argümansız çağırmak için başka bir eşe bir mesaj gönderir.
StreamInvocation: istemci veya sunucu, argümanlı veya argümansız bir akış yöntemini çağırmak için başka bir eşe bir mesaj gönderir. Yanıt farklı öğelere bölünür.
StreamItem: önceki bir StreamInvocation'dan gelen bir yanıttır.
Completion: önceki bir invocation veya StreamInvocation'ın tamamlandığı anlamına gelir. İşlem başarılı olduysa bir sonuç veya bir hata varsa bir hata içerebilir.
CancelInvocation: önceki bir StreamInvocation isteğini iptal edin.
Ping: bağlantının hâlâ canlı olup olmadığını kontrol etmek için kullanılan bir mesajdır.
SignalRCore, aşağıdaki kodlamaları kullanmanıza olanak tanır:
Şu anda, harici bir messagepack kütüphanesi kullanılarak gönderilen mesajlar kodlanarak MessagePack kullanılabilse de yalnızca JSON desteklenir. Daha fazla bilgi için aşağıdaki MessagePack bölümüne bakın.
Encoding Protokolünün yapılandırması SignalRCore.Protocol özelliğinde tanımlanır. Varsayılan olarak değer srcpJSON'dur.
Her bağlantıyla bir kullanıcı ilişkilendirmek ve hangi kullanıcıların kaynaklara erişebileceğini filtrelemek için kimlik doğrulama etkinleştirilebilir. Kimlik doğrulama, Bearer Token'lar kullanılarak uygulanır: istemci bir erişim token'ı sağlar ve sunucu bu token'ı doğrular ve kullanıcıyı tanımlamak için onu kullanır.
Standart Web API'lerinde, bearer token'lar bir HTTP Başlığında gönderilir, ancak websocket kullanılırken token bir sorgu dizesi parametresi olarak iletilir.
Aşağıdaki yöntemler desteklenir:
srcaRequestToken
Authentication etkinleştirilmişse, akış şu şekildedir:
1. Önce sunucudan geçerli bir token almaya çalışır. Authentication.RequestToken.URL'ye karşı bir HTTP bağlantısı açar ve User ve Password verilerini kullanarak bir POST yapar.
2. Önceki başarılıysa, bir token döndürülür. Değilse, bir hata döndürülür.
3. Token döndürülürse, yeni bir bağlantı anlaşması yapmak için yeni bir HTTP bağlantısı açar. Burada, token bir HTTP Başlığı olarak iletilir.
4. Öncekiler başarılı olursa, bir websocket bağlantısı açar ve token'ı sorgu dizesi parametresi olarak geçirir.
Authentication.Enabled: aktifse, bir websocket bağlantısı kurulmadan önce yetkilendirme kullanılacaktır.
Authentication.Username: kimlik doğrulamak için sunucuya sağlanan kullanıcı adı.
Authentication.Password: kimlik doğrulamak için sunucuya sağlanan gizli kelime.
Authentication.RequestToken.PostFieldUsername: kullanıcı adını iletmek için alanın adı (yapılandırmaya bağlıdır, hangi adın kullanıldığını görmek için http javascript sayfasını denetleyin).
Authentication.RequestToken.PostFieldPassword: parolayı iletecek alanın adı (yapılandırmaya bağlıdır, hangi adın kullanıldığını görmek için http javascript sayfasını kontrol edin).
Authentication.RequestToken.URL: token'ın istendiği url.
Authentication.RequestToken.QueryFieldToken: websocket bağlantısında kullanılan sorgu dizesi parametresinin adı.
srcaSetToken
Burada, token'ı doğrudan SignalRCore sunucusuna geçirirsiniz (çünkü token başka bir sunucudan alınmıştır).
Authentication.Enabled: etkinse, bir websocket bağlantısı kurulmadan önce yetkilendirme kullanılır.
Authentication.SetToken.Token: elde edilen token değeri.
Erişim token'ı, bir sorgu parametresi olarak gönderilebilir (varsayılan seçenek budur) veya bir Bearer Token olarak HTTP Başlığı şeklinde gönderilebilir. Bu davranışı yapılandırmak için Authentication.TokenParam özelliğini kullanın.
srcaBasic
Bu seçenek Basic Authentication kullanır, bu kimlik doğrulama yöntemi SignalRCore bileşeninin ve TsgcWebSocketClient öğesinin yapılandırılmasını gerektirir.
Örnek: sunucu temel kimlik doğrulama gerektiriyorsa ve kullanıcı adı "user", parola "secret" ise, bileşenleri aşağıda gösterildiği gibi yapılandırın.
// websocket client
WSClient := TsgcWebSocketClient.Create(nil);
WSClient.Authentication.Enabled := True;
WSClient.Authentication.Basic.Enabled := True;
WSClient.Authentication.URL.Enabled := False;
WSClient.Authentication.Session.Enabled := False;
WSClient.Authentication.Token.Enabled := False;
WSClient.Authentication.User := 'user';
WSClient.Authentication.Password := 'secret';
// signalrcore
Signal := TsgcWSAPI_SignalRCore.Create(nil);
Signal.SignalRCore.Authentication.Enabled := True;
Signal.SignalRCore.Authentication.Authentication := srcaBasic;
Signal.SignalRCore.Authentication.Username := 'user';
Signal.SignalRCore.Authentication.Password := 'secret';
Signal.Client := WSClient;
Sunucu ve istemciler arasında üç tür etkileşim vardır:
Caller, Callee'ye bir mesaj gönderir ve çağırmanın (invocation) tamamlandığını gösteren bir mesaj ve isteğe bağlı olarak çağırmanın bir sonucunu bekler
Örnek: istemci SendMessage yöntemini çağırır ve parametre olarak kullanıcı adını ve metin mesajını geçirir. Sunucudan bir sonuç mesajı almak için
bir Invocation Id gönderir.
SignalRCore.Invoke('SendMessage', ['John', 'Hello All.'], 'id-000001');
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
if Completion.Error <> '' then
ShowMessage('Something goes wrong.')
else
ShowMessage('Invocation Successful!');
end;
Caller, Callee'ye bir mesaj gönderir ve bu çağrı için başka bir mesaj beklemez. Çağrılar bir Invocation ID değeri olmadan gönderilebilir. Bu, çağrının "non-blocking" olduğunu gösterir.
Örnek: istemci SendMessage yöntemini çağırır ve parametre olarak kullanıcı adını ve metin mesajını geçer. İstemci, çağrının sonucu hakkında sunucudan herhangi bir yanıt beklemez.
SignalRCore.Invoke('SendMessage', ['John', 'Hello All.']);
Caller, Callee'ye bir mesaj gönderir ve Callee tarafından döndürülen bir veya daha fazla sonucu ardından çağrı sonunu gösteren bir mesajla bekler.
Örnek: istemci Counter yöntemini çağırır ve 500 milisaniye aralıkla 10 sayı ister.
SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
DoLog('#stream item: ' + StreamItem.Item);
end;
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
if Completion.Error '' then
ShowMessage('Something goes wrong.')
else
ShowMessage('Invocation Successful!');
end;
Tek bir çağırma (invocation) gerçekleştirmek için, Caller şu temel akışı izler:
procedure Invoke(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String = '');
procedure InvokeStream(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String);
Çağrıyı temsil etmek için benzersiz bir Invocation ID değeri (rastgele dize, Caller tarafından seçilir) ayırın. Çağrılan Target'ı, Arguments'ı ve InvocationId'yi içeren Invoke veya InvokeStream yöntemini çağırın (InvocationId göndermezseniz, tamamlama sonucunu alamazsınız).
Invocation engelleme yapmayan olarak işaretlenmişse (aşağıdaki "Engelleme Yapmayan Invocation'lar" bölümüne bakınız), burada durun ve hemen uygulamaya geri dönün. Eşleşen bir Invocation ID'ye sahip StreamItem veya Completion mesajını işleyin.
SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
if StreamItem.InvocationId = 'id-000002' then
DoLog('#stream item: ' + StreamItem.Item);
end;
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
if StreamItem.InvocationId = 'id-000002' then
begin
if Completion.Error '' then
ShowMessage('Something goes wrong.')
else
ShowMessage('Invocation Successful!');
end;
end;
Tek bir çağrı yapıp tamamlanmasını bekleyebilirsiniz.
function InvokeAndWait(const aTarget: String; aArguments: Array of Const; aInvocationId: String; out Completion: TSignalRCore_Completion;
const aTimeout: Integer = 10000): Boolean;
function InvokeStreamAndWait(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String;
out Completion: TSignalRCore_Completion; const aTimeout: Integer = 10000): Boolean;
Çağrıyı temsil etmek için benzersiz bir Invocation ID değeri (keyfi dize, Caller tarafından seçilir) ayırın. Çağrılan Target'ı, Arguments'ı ve InvocationId'yi içeren InvokeAndWait veya InvokeStreamAndWait yöntemini çağırın. Program, tamamlanma olayı çağrılana veya zaman aşımı aşılana kadar bekleyecektir.
var
oCompletion: TSignalRCore_Completion;
begin
if SignalRCore.InvokeStreamAndWait('Counter', [10, 500], 'id-000002', oCompletion) then
DoLog('#invoke stream ok: ' + oCompletion.Result)
else
DoLog('#invocke stream error: ' + oCompletion.Error);
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
if StreamItem.InvocationId = 'id-000002' then
DoLog('#stream item: ' + StreamItem.Item);
end;
İstemci, Sunucu bir Completion mesajı göndermeden önce StreamItem mesajlarını almayı durdurmak isterse, akışı başlatan StreamInvocation mesajı için kullanılan aynı InvocationId ile bir CancelInvocation mesajı gönderebilir.
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: SignalRCore_StreamItem; var Cancel: Boolean);
begin
if StreamItem.InvocationId = 'id-000002' then
Cancel := True;
end;
Bir Invocation, yalnızca Completion mesajı alındığında tamamlanmış olarak kabul edilir. İstemci sunucudan bir Invocation alırsa, OnSignalRCoreInvocation olayı çağrılır.
procedure OnSignalRCoreInvocation(Sender: TObject; Invocation: TSignalRCore_Invocation);
begin
if Invocation.Target = 'SendMessage' then
... your code here ...
end;
// Once invocation is completed, call Completion method to inform server invocation is finished.
// If result is successful, then call CompletionResult method:
SignalRCore.CompletionResult('id-000002', 'ok');
// If not, then call CompletionError method:
SignalRCore.CompletionError('id-000002', 'Error processing invocation.');
Bir bağlantı kapatıldığında istemci tarafından gönderilir. Bağlantı bir hata nedeniyle kapatıldıysa bir hata nedeni içerir.
SignalRCore.Close('Unexpected message').
// If the server close connection by any reason, OnSignalRCoreClose event will be called.
procedure OnSignalRCoreClose(Sender: TObject; Close: TSignalRCore_Close);
begin
DoLog('#closed: ' + Close.Error);
end;
SignalR Hub protokolü, altta yatan taşıma bağlantısının etkin kaldığından emin olmak için kullanılan "Keep Alive" mesajlarını destekler. Bu mesajlar şunları sağlamaya yardımcı olur:
Proxy'ler boşta kalma sürelerinde (az mesaj gönderildiğinde) altta yatan bağlantıyı kapatmaz. Altta yatan bağlantı düzgün bir şekilde sonlandırılmadan kesilirse, uygulama mümkün olduğunca hızlı bir şekilde bilgilendirilir.
Keep alive davranışı, Ping yöntemi çağrılarak veya WebSocket istemcisinde HeartBeat etkinleştirilerek elde edilir. Sunucu istemciye bir ping gönderirse, istemci otomatik olarak bir yanıt gönderir ve OnSignalRCoreKeepAlive olayı çağrılır.
procedure OnSignalRCoreKeepAlive(Sender: TObject);
begin
DoLog('#keepalive');
end;
SignalR Protokolünün MsgPack Kodlamasında, her Mesaj, verilen hub protokol mesajının özelliklerine karşılık gelen öğeleri içeren tek bir MsgPack dizisi olarak temsil edilir. Dizi öğeleri ilkel değerler, diziler (örneğin yöntem argümanları) veya nesneler (örneğin argüman değeri) olabilir. Dizideki ilk öğe mesaj türüdür.
Gönderilen mesajların nasıl kodlanacağını görmek için MessagePack belgelerine bakınız.
Yeni bir mesaj her alındığında, bu OnSignalRCoreMessagePack olayında dağıtılır. Mesaja Data Stream parametresi okunarak erişilebilir. JSON parametresi varsayılan olarak boştur, MessagePack mesajını JSON'a dönüştürürseniz, bileşen JSON mesajını kodlama JSON kullanıyormuş gibi işler (böylece OnSignalRCoreCompletion, OnSignalRCoreInvocation... olayları dağıtılır).