ASP.NET SignalR Hubs API Kılavuzu - Sunucu (SignalR 1.x)

Tarafından Patrick Fletcher, Tom Dykstra

Uyarı

Bu belgeler SignalR'nin en son sürümüne yönelik değildir. ASP.NET Core SignalR'ye göz atın.

Bu belge, SignalR sürüm 1.1 için ASP.NET SignalR Hubs API'sinin sunucu tarafını programlamaya giriş niteliğindedir ve yaygın seçenekleri gösteren kod örnekleri içerir.

SignalR Hubs API'leri, bir sunucudan bağlı istemcilere ve istemcilerden sunucuya uzaktan yordam çağrıları (RPC) yapmanıza olanak tanır. Sunucu kodunda, istemciler tarafından çağrılabilecek yöntemleri tanımlar ve istemcide çalışan yöntemleri çağırırsınız. İstemci kodunda, sunucudan çağrılabilen yöntemler tanımlarsınız ve sunucuda çalışan yöntemleri çağırırsınız. SignalR, istemciden sunucuya tüm tesisatı sizin için halleder.

SignalR ayrıca Kalıcı Bağlantılar adlı alt düzey bir API sunar. SignalR, Hubs ve Kalıcı Bağlantılar'a giriş için veya eksiksiz bir SignalR uygulamasının nasıl derlendiğini gösteren bir öğretici için bkz. SignalR - Başlarken.

Genel Bakış

Bu belgede aşağıdaki bölümler yer alır:

İstemcileri programlama hakkında belgeler için aşağıdaki kaynaklara bakın:

API Başvurusu konularının bağlantıları API'nin .NET 4.5 sürümünedir. .NET 4 kullanıyorsanız API konularının .NET 4 sürümüne bakın.

SignalR yolunu kaydetme ve SignalR seçeneklerini yapılandırma

İstemcilerin Hub'ınıza bağlanmak için kullanacağı yolu tanımlamak için uygulama başlatıldığında MapHubs yöntemini çağırın. MapHubssınıfı için System.Web.Routing.RouteCollection bir uzantı yöntemidir. Aşağıdaki örnekte , Global.asax dosyasında SignalR Hubs yolunun nasıl tanımlanacağı gösterilmektedir.

using System.Web.Routing;
public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapHubs();
    }
}

ASP.NET MVC uygulamasına SignalR işlevselliği ekliyorsanız SignalR yolunun diğer yollardan önce eklendiğinden emin olun. Daha fazla bilgi için bkz . Öğretici: SignalR ve MVC 4 ile Çalışmaya Başlama.

/signalr URL'si

Varsayılan olarak, istemcilerin Hub'ınıza bağlanmak için kullanacağı yol URL'si "/signalr"dır. (Bu URL'yi otomatik olarak oluşturulan JavaScript dosyası için olan "/signalr/hubs" URL'si ile karıştırmayın. Oluşturulan ara sunucu hakkında daha fazla bilgi için bkz . SignalR Hubs API Kılavuzu - JavaScript İstemcisi - Oluşturulan ara sunucu ve sizin için yaptıkları.)

Bu temel URL'yi SignalR için kullanılamaz hale getiren olağanüstü durumlar olabilir; örneğin, projenizde signalr adlı bir klasörünüz var ve adı değiştirmek istemiyorsunuz. Bu durumda, aşağıdaki örneklerde gösterildiği gibi temel URL'yi değiştirebilirsiniz (örnek koddaki "/signalr"ı istediğiniz URL ile değiştirin).

URL'yi belirten sunucu kodu

RouteTable.Routes.MapHubs("/signalr", new HubConfiguration());

URL'yi belirten JavaScript istemci kodu (oluşturulan proxy ile)

$.connection.hub.url = "/signalr"
$.connection.hub.start().done(init);

URL'yi belirten JavaScript istemci kodu (oluşturulan ara sunucu olmadan)

var connection = $.hubConnection("/signalr", { useDefaultPath: false });

URL'yi belirten .NET istemci kodu

var hubConnection = new HubConnection("http://contoso.com/signalr", useDefaultUrl: false);

SignalR Seçeneklerini Yapılandırma

yönteminin MapHubs aşırı yüklemeleri özel bir URL, özel bağımlılık çözümleyicisi ve aşağıdaki seçenekleri belirtmenize olanak tanır:

  • Tarayıcı istemcilerinden etki alanları arası çağrıları etkinleştirin.

    Genellikle tarayıcı sayfasından http://contoso.combir sayfa yüklerse SignalR bağlantısı adresinde aynı etki alanındadır http://contoso.com/signalr. sayfasından http://contoso.com ile bağlantı http://fabrikam.com/signalrkurulduysa, bu etki alanları arası bir bağlantıdır. Güvenlik nedeniyle, etki alanları arası bağlantılar varsayılan olarak devre dışı bırakılır. Daha fazla bilgi için bkz . ASP.NET SignalR Hubs API Kılavuzu - JavaScript İstemcisi - Etki alanları arası bağlantı kurma.

  • Ayrıntılı hata iletilerini etkinleştirin.

    Hatalar oluştuğunda SignalR'nin varsayılan davranışı, istemcilere ne olduğuyla ilgili ayrıntılar olmadan bir bildirim iletisi göndermektir. Kötü amaçlı kullanıcılar bu bilgileri uygulamanıza yönelik saldırılarda kullanabileceğinden, istemcilere ayrıntılı hata bilgileri göndermek üretimde önerilmez. Sorun giderme için, daha bilgilendirici hata raporlamayı geçici olarak etkinleştirmek için bu seçeneği kullanabilirsiniz.

  • Otomatik olarak oluşturulan JavaScript proxy dosyalarını devre dışı bırakın.

    Varsayılan olarak, "/signalr/hubs" URL'sine yanıt olarak Hub sınıflarınızın proxy'lerini içeren bir JavaScript dosyası oluşturulur. JavaScript proxy'lerini kullanmak istemiyorsanız veya bu dosyayı el ile oluşturmak ve istemcilerinizdeki fiziksel bir dosyaya başvurmak istiyorsanız, ara sunucu oluşturmayı devre dışı bırakmak için bu seçeneği kullanabilirsiniz. Daha fazla bilgi için bkz . SignalR Hubs API Kılavuzu - JavaScript İstemcisi - SignalR tarafından oluşturulan ara sunucu için fiziksel dosya oluşturma.

Aşağıdaki örnekte SignalR bağlantı URL'sinin ve yöntemine yapılan çağrıda bu seçeneklerin nasıl belirtilmesi gösterilmektedir MapHubs . Özel bir URL belirtmek için örnekteki "/signalr" yerine kullanmak istediğiniz URL'yi yazın.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableCrossDomain = true;
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
RouteTable.Routes.MapHubs("/signalr", hubConfiguration);

Hub sınıflarını oluşturma ve kullanma

Hub oluşturmak için Microsoft.Aspnet.Signalr.Hub'dan türetilen bir sınıf oluşturun. Aşağıdaki örnekte bir sohbet uygulaması için basit bir Hub sınıfı gösterilmektedir.

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}

Bu örnekte, bağlı bir istemci yöntemini çağırabilir NewContosoChatMessage ve çağırdığında, alınan veriler tüm bağlı istemcilere yayınlanır.

Hub nesne ömrü

Hub sınıfının örneğini oluşturmaz veya sunucudaki kendi kodunuzdan yöntemlerini çağırmazsınız; SignalR Hubs işlem hattı tarafından sizin için yapılan tüm işlemleri gerçekleştirin. SignalR, bir istemcinin bağlanması, bağlantısının kesilmesi veya sunucuya yöntem çağrısı yapması gibi bir Hub işlemini işlemesi gerektiğinde Hub sınıfınızın yeni bir örneğini oluşturur.

Hub sınıfının örnekleri geçici olduğundan, bir yöntem çağrısından diğerine durumu korumak için bunları kullanamazsınız. Sunucu bir istemciden her yöntem çağrısı aldığında, Hub sınıfınızın yeni bir örneği iletiyi işler. Birden çok bağlantı ve yöntem çağrısı aracılığıyla durumu korumak için veritabanı veya Hub sınıfındaki statik değişken gibi başka bir yöntemi ya da öğesinden Hubtüretilmeyen farklı bir sınıfı kullanın. Hub sınıfında statik değişken gibi bir yöntem kullanarak verileri bellekte kalıcı hale alırsanız, uygulama etki alanı geri dönüşüme geçtiğinde veriler kaybolur.

hub sınıfı dışında çalışan kendi kodunuzdan istemcilere ileti göndermek istiyorsanız, hub sınıfı örneğini oluşturarak bunu yapamazsınız, ancak Hub sınıfınızın SignalR bağlam nesnesine başvuru alarak bunu yapabilirsiniz. Daha fazla bilgi için, bu konunun devamında İstemci yöntemlerini çağırma ve Hub sınıfı dışından grupları yönetme konusuna bakın.

JavaScript istemcilerinde Hub adlarının camel-casing

Varsayılan olarak, JavaScript istemcileri sınıf adının camel cased sürümünü kullanarak Hubs'a başvurur. SignalR, JavaScript kodunun JavaScript kurallarına uygun olabilmesi için bu değişikliği otomatik olarak yapar. Önceki örnek JavaScript kodunda olarak contosoChatHub adlandırılır.

Sunucu

public class ContosoChatHub : Hub

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

var contosoChatHubProxy = $.connection.contosoChatHub;

İstemcilerin kullanması için farklı bir ad belirtmek istiyorsanız özniteliğini HubName ekleyin. Bir HubName öznitelik kullandığınızda, JavaScript istemcilerinde deve durumunda ad değişikliği olmaz.

Sunucu

[HubName("PascalCaseContosoChatHub")]
public class ContosoChatHub : Hub

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

var contosoChatHubProxy = $.connection.PascalCaseContosoChatHub;

Birden Çok Hub

Bir uygulamada birden çok Hub sınıfı tanımlayabilirsiniz. Bunu yaptığınızda bağlantı paylaşılır ancak gruplar ayrı olur:

  • Tüm istemciler hizmetinizle bir SignalR bağlantısı kurmak için aynı URL'yi kullanır ("/signalr" veya belirttiyseniz özel URL'niz) ve bu bağlantı hizmet tarafından tanımlanan tüm Hub'lar için kullanılır.

    Tek bir sınıftaki tüm Hub işlevlerini tanımlamaya kıyasla birden çok Hub için performans farkı yoktur.

  • Tüm Hub'lar aynı HTTP isteği bilgilerini alır.

    Tüm Hub'lar aynı bağlantıyı paylaştığından, sunucunun aldığı tek HTTP isteği bilgileri SignalR bağlantısını oluşturan özgün HTTP isteğinde gelen bilgilerdir. Bir sorgu dizesi belirterek istemciden sunucuya bilgi geçirmek için bağlantı isteğini kullanırsanız, farklı Hub'lara farklı sorgu dizeleri sağlayamazsınız. Tüm Hub'lar aynı bilgileri alır.

  • Oluşturulan JavaScript proxy'leri dosyası, tek bir dosyada tüm Hub'lar için proxy'ler içerir.

    JavaScript proxy'leri hakkında bilgi için bkz. SignalR Hubs API Kılavuzu - JavaScript İstemcisi - Oluşturulan ara sunucu ve sizin için yaptıkları.

  • Gruplar Hub'lar içinde tanımlanır.

    SignalR'da bağlı istemcilerin alt kümelerine yayın yapmak için adlandırılmış gruplar tanımlayabilirsiniz. Gruplar her Hub için ayrı ayrı tutulur. Örneğin, "Yöneticiler" adlı bir grup sınıfınız ContosoChatHub için bir istemci kümesi içerir ve aynı grup adı sınıfınız StockTickerHub için farklı bir istemci kümesine başvurur.

İstemcilerin çağırabileceği Hub sınıfında yöntemler tanımlama

Hub'da istemciden çağrılmasını istediğiniz bir yöntemi kullanıma açmak için, aşağıdaki örneklerde gösterildiği gibi genel bir yöntem bildirin.

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}
public class StockTickerHub : Hub
{
    public IEnumerable<Stock> GetAllStocks()
    {
        return _stockTicker.GetAllStocks();
    }
}

Herhangi bir C# yönteminde olduğu gibi, karmaşık türler ve diziler de dahil olmak üzere bir dönüş türü ve parametre belirtebilirsiniz. Parametrelerde aldığınız veya çağırana geri döndürdüğünüz tüm veriler istemci ile sunucu arasında JSON kullanılarak iletilir ve SignalR karmaşık nesnelerin ve nesne dizilerinin bağlamasını otomatik olarak işler.

JavaScript istemcilerinde yöntem adlarının deve kasası

Varsayılan olarak JavaScript istemcileri, yöntem adının camel cased sürümünü kullanarak Hub yöntemlerine başvurur. SignalR, JavaScript kodunun JavaScript kurallarına uygun olabilmesi için bu değişikliği otomatik olarak yapar.

Sunucu

public void NewContosoChatMessage(string userName, string message)

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

contosoChatHubProxy.server.newContosoChatMessage($(userName, message);

İstemcilerin kullanması için farklı bir ad belirtmek istiyorsanız özniteliğini HubMethodName ekleyin.

Sunucu

[HubMethodName("PascalCaseNewContosoChatMessage")]
public void NewContosoChatMessage(string userName, string message)

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

contosoChatHubProxy.server.PascalCaseNewContosoChatMessage(userName, message);

Zaman uyumsuz olarak ne zaman yürütülür?

Yöntem uzun süre çalışacaksa veya veritabanı araması veya web hizmeti çağrısı gibi beklemeyi kapsayan bir iş yapması gerekiyorsa, Bir Görev (dönüş yerine void ) veya Görev<T> nesnesi döndürerek (dönüş türü yerine T ) Hub yöntemini zaman uyumsuz hale getirin. yönteminden bir Task nesne döndürdiğinizde SignalR, öğesinin Task tamamlanmasını bekler ve ardından sarmalanmamış sonucu istemciye geri gönderir, bu nedenle istemcide yöntem çağrısını kodlarken bir fark yoktur.

Hub yönteminin zaman uyumsuz hale getirilmesi, WebSocket aktarımını kullandığında bağlantının engellenmesini önler. Hub yöntemi zaman uyumlu olarak yürütürse ve aktarım WebSocket olduğunda, Hub yöntemi tamamlanana kadar hub'da aynı istemciden sonraki yöntem çağrıları engellenir.

Aşağıdaki örnekte, zaman uyumlu veya zaman uyumsuz olarak çalıştırılacak şekilde kodlanmış olan yöntemin aynısını ve ardından iki sürümü çağırmak için çalışan JavaScript istemci kodunu gösterir.

Zaman Uyumlu

public IEnumerable<Stock> GetAllStocks()
{
    // Returns data from memory.
    return _stockTicker.GetAllStocks();
}

Zaman Uyumsuz - ASP.NET 4.5

public async Task<IEnumerable<Stock>> GetAllStocks()
{
    // Returns data from a web service.
    var uri = Util.getServiceUri("Stocks");
    using (HttpClient httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync(uri);
        return (await response.Content.ReadAsAsync<IEnumerable<Stock>>());
    }
}

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

stockTickerHubProxy.server.getAllStocks().done(function (stocks) {
    $.each(stocks, function () {
        alert(this.Symbol + ' ' + this.Price);
    });
});

ASP.NET 4.5'te zaman uyumsuz yöntemleri kullanma hakkında daha fazla bilgi için bkz. ASP.NET MVC 4'te Zaman Uyumsuz Yöntemler Kullanma.

Aşırı Yüklemeleri Tanımlama

Bir yöntem için aşırı yüklemeler tanımlamak istiyorsanız, her aşırı yüklemedeki parametre sayısı farklı olmalıdır. Farklı parametre türleri belirterek aşırı yüklemeyi ayırt ederseniz Hub sınıfınız derlenir ancak istemciler aşırı yüklemelerden birini çağırmaya çalıştığında SignalR hizmeti çalışma zamanında bir özel durum oluşturur.

Hub sınıfından istemci yöntemlerini çağırma

İstemci yöntemlerini sunucudan çağırmak için Hub sınıfınızdaki bir yöntemde özelliğini kullanın Clients . Aşağıdaki örnekte, tüm bağlı istemcileri çağıran addNewMessageToPage sunucu kodu ve JavaScript istemcisinde yöntemini tanımlayan istemci kodu gösterilmektedir.

Sunucu

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

contosoChatHubProxy.client.addNewMessageToPage = function (name, message) {
    // Add the message to the page. 
    $('#discussion').append('<li><strong>' + htmlEncode(name)
        + '</strong>: ' + htmlEncode(message) + '<li>');
};

İstemci yönteminden dönüş değeri alamazsınız; gibi int x = Clients.All.add(1,1) söz dizimi çalışmıyor.

Parametreler için karmaşık türler ve diziler belirtebilirsiniz. Aşağıdaki örnek, bir yöntem parametresinde istemciye karmaşık bir tür geçirir.

Karmaşık bir nesne kullanarak istemci yöntemini çağıran sunucu kodu

public void SendMessage(string name, string message)
{
    Clients.All.addContosoChatMessageToPage(new ContosoChatMessage() { UserName = name, Message = message });
}

Karmaşık nesneyi tanımlayan sunucu kodu

public class ContosoChatMessage
{
    public string UserName { get; set; }
    public string Message { get; set; }
}

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

var contosoChatHubProxy = $.connection.contosoChatHub;
contosoChatHubProxy.client.addMessageToPage = function (message) {
    console.log(message.UserName + ' ' + message.Message);
});

RPC'yi alacak istemcileri seçme

İstemciler özelliği, RPC'yi alacak istemcileri belirtmek için çeşitli seçenekler sağlayan bir HubConnectionContext nesnesi döndürür:

  • Tüm bağlı istemciler.

    Clients.All.addContosoChatMessageToPage(name, message);
    
  • Yalnızca çağıran istemci.

    Clients.Caller.addContosoChatMessageToPage(name, message);
    
  • Çağıran istemci dışındaki tüm istemciler.

    Clients.Others.addContosoChatMessageToPage(name, message);
    
  • Bağlantı kimliğiyle tanımlanan belirli bir istemci.

    Clients.Client(Context.ConnectionId).addContosoChatMessageToPage(name, message);
    

    Bu örnek çağıran istemciyi çağırır addContosoChatMessageToPage ve kullanımıyla Clients.Calleraynı etkiye sahiptir.

  • Bağlantı kimliğiyle tanımlanan belirtilen istemciler dışındaki tüm bağlı istemciler.

    Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Belirtilen gruptaki tüm bağlı istemciler.

    Clients.Group(groupName).addContosoChatMessageToPage(name, message);
    
  • Bağlantı kimliğiyle tanımlanan belirtilen istemciler dışında belirtilen gruptaki tüm bağlı istemciler.

    Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Belirtilen gruptaki çağıran istemci dışındaki tüm bağlı istemciler.

    Clients.OthersInGroup(groupName).addContosoChatMessageToPage(name, message);
    

Yöntem adları için derleme zamanı doğrulaması yok

Belirttiğiniz yöntem adı dinamik bir nesne olarak yorumlanır ve bu da bunun için IntelliSense veya derleme zamanı doğrulaması olmadığı anlamına gelir. İfade çalışma zamanında değerlendirilir. Yöntem çağrısı yürütürken SignalR yöntem adını ve parametre değerlerini istemciye gönderir ve istemcinin adla eşleşen bir yöntemi varsa, bu yöntem çağrılır ve parametre değerleri bu yönteme geçirilir. İstemcide eşleşen bir yöntem bulunamazsa hata oluşmaz. Bir istemci yöntemini çağırdığınızda SignalR'nin arka planda istemciye ilettiği verilerin biçimi hakkında bilgi için bkz . SignalR'ye Giriş.

Büyük/küçük harfe duyarlı olmayan yöntem adı eşleştirme

Yöntem adı eşleştirme büyük/küçük harfe duyarlı değildir. Örneğin, Clients.All.addContosoChatMessageToPage sunucuda , addcontosochatmessagetopageveya addContosoChatMessageToPage istemcisinde yürütülürAddContosoChatMessageToPage.

Zaman uyumsuz yürütme

Çağırdığınız yöntem zaman uyumsuz olarak yürütülür. Sonraki kod satırlarının yöntemin tamamlanmasını beklemesi gerektiğini belirtmediğiniz sürece, bir istemciye yöntem çağrısından sonra gelen tüm kodlar SignalR'nin istemcilere veri iletmeyi bitirmesini beklemeden hemen yürütülür. Aşağıdaki kod örnekleri, biri .NET 4.5'te çalışan kodu, diğeri de .NET 4'te çalışan kodu kullanan iki istemci yönteminin sırayla nasıl yürütüleceğini gösterir.

.NET 4.5 örneği

async public Task NewContosoChatMessage(string name, string message)
{
    await Clients.Others.addContosoChatMessageToPage(data);
    Clients.Caller.notifyMessageSent();
}

.NET 4 örneği

public void NewContosoChatMessage(string name, string message)
{
    (Clients.Others.addContosoChatMessageToPage(data) as Task).ContinueWith(antecedent =>
        Clients.Caller.notifyMessageSent());
}

bir sonraki kod satırı yürütülmeden önce istemci yönteminin bitmesini beklemek için veya ContinueWith kullanırsanızawait, bu istemcilerin bir sonraki kod satırı yürütülmeden önce iletiyi alacağı anlamına gelmez. İstemci yöntemi çağrısının "Tamamlanması", SignalR'nin iletiyi göndermek için gereken her şeyi yaptığı anlamına gelir. İstemcilerin iletiyi aldığını doğrulamanız gerekiyorsa, bu mekanizmayı kendiniz programlamanız gerekir. Örneğin, Hub'da bir MessageReceived yöntem kodlayabilir ve istemcideki yönteminde addContosoChatMessageToPage , istemcide yapmanız gereken her işi yaptıktan sonra çağırabilirsiniz MessageReceived . Hub'da MessageReceived gerçek istemci alımına ve özgün yöntem çağrısının işlenmesine bağlı olan her işi yapabilirsiniz.

Yöntem adı olarak dize değişkeni kullanma

Yöntem adı olarak bir dize değişkeni kullanarak bir istemci yöntemini çağırmak istiyorsanız, öğesine (veya , vb.) IClientProxy yayınlayın Clients.All ve invoke(methodName, args...)çağırın. Clients.CallerClients.Others

public void NewContosoChatMessage(string name, string message)
{
    string methodToCall = "addContosoChatMessageToPage";
    IClientProxy proxy = Clients.All;
    proxy.Invoke(methodToCall, name, message);
}

Hub sınıfından grup üyeliğini yönetme

SignalR'deki gruplar, iletileri bağlı istemcilerin belirtilen alt kümelerine yayınlamak için bir yöntem sağlar. Bir grubun herhangi bir sayıda istemcisi olabilir ve bir istemci de herhangi bir sayıda grubun üyesi olabilir.

Grup üyeliğini yönetmek için Hub sınıfının özelliği tarafından Groups sağlanan Add ve Remove yöntemlerini kullanın. Aşağıdaki örnek, istemci kodu tarafından çağrılan Hub yöntemlerinde kullanılan ve Groups.Remove yöntemlerini ve ardından bunları çağıran JavaScript istemci kodunu gösterirGroups.Add.

Sunucu

public class ContosoChatHub : Hub
{
    public Task JoinGroup(string groupName)
    {
        return Groups.Add(Context.ConnectionId, groupName);
    }

    public Task LeaveGroup(string groupName)
    {
        return Groups.Remove(Context.ConnectionId, groupName);
    }
}

Oluşturulan ara sunucuyu kullanan JavaScript istemcisi

contosoChatHubProxy.server.joinGroup(groupName);
contosoChatHubProxy.server.leaveGroup(groupName);

Açıkça grup oluşturmanız gerekmez. Aslında bir grup, çağrısında adını ilk kez belirttiğinizde Groups.Addotomatik olarak oluşturulur ve içindeki üyelikten son bağlantıyı kaldırdığınızda silinir.

Grup üyeliği listesi veya grup listesi almak için API yoktur. SignalR, istemcilere ve gruplara pub/sub modelini temel alan iletiler gönderir ve sunucu grup veya grup üyeliklerinin listesini tutmaz. Bu, web grubuna her düğüm eklediğinizde SignalR'nin koruduğu herhangi bir durumun yeni düğüme yayılması gerektiğinden ölçeklenebilirliği en üst düzeye çıkarmaya yardımcı olur.

Add ve Remove yöntemlerinin zaman uyumsuz yürütülmesi

Groups.Add ve Groups.Remove yöntemleri zaman uyumsuz olarak yürütülür. Bir gruba istemci eklemek ve grubu kullanarak istemciye hemen bir ileti göndermek istiyorsanız, önce yöntemin tamamlandığından Groups.Add emin olmanız gerekir. Aşağıdaki kod örnekleri, bunun nasıl yapılacağını gösterir. Bunlardan biri .NET 4.5'te çalışan bir kod, diğeri de .NET 4'te çalışan kod kullanılarak yapılır

.NET 4.5 örneği

async public Task JoinGroup(string groupName)
{
    await Groups.Add(Context.ConnectionId, groupName);
    Clients.Group(groupname).addContosoChatMessageToPage(Context.ConnectionId + " added to group");
}

.NET 4 örneği

public void JoinGroup(string groupName)
{
    (Groups.Add(Context.ConnectionId, groupName) as Task).ContinueWith(antecedent =>
        Clients.Group(groupName).addContosoChatMessageToPage(Context.ConnectionId + " added to group"));
}

Grup üyeliği kalıcılığı

SignalR, kullanıcıları değil bağlantıları izler. Bu nedenle, bir kullanıcının her bağlantı kurduğunda aynı grupta olmasını istiyorsanız, kullanıcı her yeni bağlantı kurduğunda aramanız Groups.Add gerekir.

Geçici bir bağlantı kaybından sonra SignalR bazen bağlantıyı otomatik olarak geri yükleyebilir. Bu durumda SignalR aynı bağlantıyı geri yükler, yeni bir bağlantı kurmaz ve bu nedenle istemcinin grup üyeliği otomatik olarak geri yüklenir. Grup üyelikleri de dahil olmak üzere her istemcinin bağlantı durumu istemciye yuvarlandığından, geçici kesme sunucu yeniden başlatma veya hata sonucu olduğunda bile bu mümkündür. Bir sunucu kapanırsa ve bağlantı zaman aşımına uğramadan önce yeni bir sunucuyla değiştirilirse, istemci yeni sunucuya otomatik olarak yeniden bağlanabilir ve üyesi olduğu gruplara yeniden kaydolabilir.

Bağlantı kaybedildikten sonra veya bağlantı zaman aşımına uğradıktan sonra bağlantı otomatik olarak geri yüklenemediyse veya istemcinin bağlantısı kesildiğinde (örneğin, bir tarayıcı yeni bir sayfaya gittiğinde), grup üyelikleri kaybolur. Kullanıcının bir sonraki bağlantısı yeni bir bağlantı olacaktır. Aynı kullanıcı yeni bir bağlantı kurduğunda grup üyeliklerini korumak için uygulamanızın kullanıcılar ve gruplar arasındaki ilişkileri izlemesi ve bir kullanıcı her yeni bağlantı kurduğunda grup üyeliklerini geri yüklemesi gerekir.

Bağlantılar ve yeniden bağlantılar hakkında daha fazla bilgi için, bu konunun devamında Hub sınıfında bağlantı ömrü olaylarını işleme bölümüne bakın.

Tek kullanıcılı gruplar

SignalR kullanan uygulamaların genellikle hangi kullanıcının ileti gönderdiğini ve hangi kullanıcıların ileti alması gerektiğini bilmek için kullanıcılar ve bağlantılar arasındaki ilişkileri izlemesi gerekir. Gruplar, bunu yapmak için yaygın olarak kullanılan iki desenden birinde kullanılır.

  • Tek kullanıcılı gruplar.

    Kullanıcı adını grup adı olarak belirtebilir ve kullanıcı her bağlandığında veya yeniden bağlandığında geçerli bağlantı kimliğini gruba ekleyebilirsiniz. Gruba gönderdiğiniz kullanıcıya ileti göndermek için. Bu yöntemin bir dezavantajı, grubun size kullanıcının çevrimiçi mi yoksa çevrimdışı mı olduğunu öğrenmeniz için bir yol sağlamamasıdır.

  • Kullanıcı adları ve bağlantı kimlikleri arasındaki ilişkilendirmeleri izleyin.

    Her kullanıcı adı ile bir veya daha fazla bağlantı kimliği arasındaki ilişkiyi bir sözlükte veya veritabanında depolayabilir ve kullanıcı her bağlandığında veya bağlantıyı kestiğinde depolanan verileri güncelleştirebilirsiniz. Kullanıcıya ileti göndermek için bağlantı kimliklerini belirtirsiniz. Bu yöntemin bir dezavantajı daha fazla bellek almasıdır.

Hub sınıfında bağlantı ömrü olaylarını işleme

Bağlantı ömrü olaylarını işlemenin tipik nedenleri, kullanıcının bağlı olup olmadığını izlemek ve kullanıcı adları ile bağlantı kimlikleri arasındaki ilişkiyi izlemektir. İstemciler bağlandığında veya bağlantıyı kestiğinde kendi kodunuzu çalıştırmak için, aşağıdaki örnekte gösterildiği gibi Hub sınıfının , OnDisconnectedve OnReconnected sanal yöntemlerini geçersiz kılınOnConnected.

public class ContosoChatHub : Hub
{
    public override Task OnConnected()
    {
        // Add your own code here.
        // For example: in a chat application, record the association between
        // the current connection ID and user name, and mark the user as online.
        // After the code in this method completes, the client is informed that
        // the connection is established; for example, in a JavaScript client,
        // the start().done callback is executed.
        return base.OnConnected();
    }

    public override Task OnDisconnected()
    {
        // Add your own code here.
        // For example: in a chat application, mark the user as offline, 
        // delete the association between the current connection id and user name.
        return base.OnDisconnected();
    }

    public override Task OnReconnected()
    {
        // Add your own code here.
        // For example: in a chat application, you might have marked the
        // user as offline after a period of inactivity; in that case 
        // mark the user as online again.
        return base.OnReconnected();
    }
}

OnConnected, OnDisconnected ve OnReconnected çağrıldığında

Bir tarayıcı yeni bir sayfaya her gidildiğinde yeni bir bağlantı kurulması gerekir; bu da SignalR'nin yöntemi ve OnConnected ardından yöntemini yürüteceği OnDisconnected anlamına gelir. SignalR, yeni bir bağlantı kurulduğunda her zaman yeni bir bağlantı kimliği oluşturur.

Bağlantı OnReconnected zaman aşımına uğramadan önce bir kablonun geçici olarak bağlantısının kesilmesi ve yeniden bağlanması gibi SignalR'nin otomatik olarak kurtarabileceği geçici bir bağlantı kesintisi olduğunda yöntemi çağrılır. OnDisconnected yöntemi, istemcinin bağlantısı kesildiğinde çağrılır ve bir tarayıcı yeni bir sayfaya gittiği zaman gibi SignalR otomatik olarak yeniden bağlanamaz. Bu nedenle, belirli bir istemci için olası bir olay dizisi , OnReconnected, OnDisconnected; veya OnConnected, OnDisconnectedolurOnConnected. Belirli bir bağlantı için , OnDisconnectedOnReconnected dizisini OnConnectedgörmezsiniz.

Bir sunucunun OnDisconnected kapanması veya Uygulama Etki Alanının geri dönüştürülmesi gibi bazı senaryolarda yöntemi çağrılmıyor. Başka bir sunucu hatta geldiğinde veya Uygulama Etki Alanı geri dönüşümünü tamamladığında, bazı istemciler olayı yeniden bağlayıp çalıştırabilir OnReconnected .

Daha fazla bilgi için bkz. SignalR'de Bağlantı Ömrü Olaylarını Anlama ve İşleme.

Arayan durumu doldurulamadı

Bağlantı ömrü olay işleyicisi yöntemleri sunucudan çağrılır; başka bir deyişle istemcideki nesneye state yerleştirdiğiniz herhangi bir durum sunucudaki özelliğinde Caller doldurulmayacak. Nesnesi ve Caller özelliği hakkında state daha fazla bilgi için, bu konunun devamında İstemciler ile Hub sınıfı arasında durum geçirme bölümüne bakın.

Context özelliğinden istemci hakkında bilgi alma

İstemci hakkında bilgi almak için Hub sınıfının özelliğini kullanın Context . özelliği, Context aşağıdaki bilgilere erişim sağlayan bir HubCallerContext nesnesi döndürür:

  • Çağıran istemcinin bağlantı kimliği.

    string connectionID = Context.ConnectionId;
    

    Bağlantı kimliği SignalR tarafından atanan bir GUID'dir (değeri kendi kodunuzda belirtemezsiniz). Her bağlantı için bir bağlantı kimliği vardır ve uygulamanızda birden çok Hub varsa tüm Hub'lar tarafından aynı bağlantı kimliği kullanılır.

  • HTTP üst bilgi verileri.

    System.Collections.Specialized.NameValueCollection headers = Context.Request.Headers;
    

    HTTP üst bilgilerini adresinden Context.Headersde alabilirsiniz. Aynı şeye birden çok başvurunun nedeni, önce oluşturulmuş olması Context.Headers , özelliğin Context.Request daha sonra eklenmesi ve Context.Headers geriye dönük uyumluluk için korunmasıdır.

  • Sorgu dizesi verileri.

    System.Collections.Specialized.NameValueCollection queryString = Context.Request.QueryString;
    string parameterValue = queryString["parametername"]
    

    Sorgu dizesi verilerini 'den Context.QueryStringde alabilirsiniz.

    Bu özellikte elde ettiğiniz sorgu dizesi, SignalR bağlantısını oluşturan HTTP isteğiyle kullanılan dizedir. bağlantıyı yapılandırarak istemciye sorgu dizesi parametreleri ekleyebilirsiniz. Bu, istemci hakkındaki verileri istemciden sunucuya geçirmenin kullanışlı bir yoludur. Aşağıdaki örnekte, oluşturulan ara sunucuyu kullandığınızda JavaScript istemcisine sorgu dizesi eklemenin bir yolu gösterilmektedir.

    $.connection.hub.qs = { "version" : "1.0" };
    

    Sorgu dizesi parametrelerini ayarlama hakkında daha fazla bilgi için bkz. JavaScript ve .NET istemcileri için API kılavuzları.

    Bağlantı için kullanılan aktarım yöntemini sorgu dizesi verilerinde ve SignalR tarafından dahili olarak kullanılan bazı diğer değerlerde bulabilirsiniz:

    string transportMethod = queryString["transport"];
    

    değeri transportMethod "webSockets", "serverSentEvents", "foreverFrame" veya "longPolling" olur. Olay işleyicisi yönteminde OnConnected bu değeri denetlerseniz, bazı senaryolarda başlangıçta bağlantı için belirlenen son aktarım yöntemi olmayan bir aktarım değeri alabilirsiniz. Bu durumda yöntem bir özel durum oluşturur ve son aktarım yöntemi oluşturulduğunda daha sonra yeniden çağrılır.

  • Kurabiye.

    System.Collections.Generic.IDictionary<string, Cookie> cookies = Context.Request.Cookies;
    

    Tanımlama bilgilerini adresinden Context.RequestCookiesde alabilirsiniz.

  • Kullanıcı bilgileri.

    System.Security.Principal.IPrincipal user = Context.User;
    
  • İsteğin HttpContext nesnesi:

    System.Web.HttpContextBase httpContext = Context.Request.GetHttpContext();
    

    SignalR bağlantısı için nesnesini almak HttpContext.CurrentHttpContext yerine bu yöntemi kullanın.

İstemciler ile Hub sınıfı arasında durum geçirme

İstemci proxy'si, her yöntem çağrısıyla sunucuya iletilmesini istediğiniz verileri depolayabileceğiniz bir state nesne sağlar. Sunucuda, istemciler tarafından çağrılan Hub yöntemlerindeki özelliğinde bu verilere Clients.Caller erişebilirsiniz. Clients.Caller özelliği, OnDisconnectedve OnReconnectedbağlantı ömrü olay işleyici yöntemleri OnConnectediçin doldurulmuyor.

nesnesinde ve Clients.Caller özelliğinde state veri oluşturma veya güncelleştirme her iki yönde de çalışır. Sunucudaki değerleri güncelleştirebilirsiniz ve bunlar istemciye geri geçirilir.

Aşağıdaki örnekte, her yöntem çağrısıyla sunucuya iletim durumunu depolayan JavaScript istemci kodu gösterilmektedir.

contosoChatHubProxy.state.userName = "Fadi Fakhouri";
contosoChatHubProxy.state.computerName = "fadivm1";

Aşağıdaki örnekte bir .NET istemcisindeki eşdeğer kod gösterilmektedir.

contosoChatHubProxy["userName"] = "Fadi Fakhouri";
chatHubProxy["computerName"] = "fadivm1";

Hub sınıfınızda bu verilere özelliğinden Clients.Caller erişebilirsiniz. Aşağıdaki örnekte, önceki örnekte başvuruda bulunılan durumu alan kod gösterilmektedir.

public void NewContosoChatMessage(string data)
{
    string userName = Clients.Caller.userName;
    string computerName = Clients.Caller.computerName;
    Clients.Others.addContosoChatMessageToPage(message, userName, computerName);
}

Not

Veya Clients.Caller özelliğine yerleştirdiğiniz state her şey her yöntem çağrısıyla yuvarlandığından, durumu kalıcı hale getiren bu mekanizma büyük miktarda veri için tasarlanmamıştır. Kullanıcı adları veya sayaçlar gibi daha küçük öğeler için kullanışlıdır.

Hub sınıfında hataları işleme

Hub sınıf yöntemlerinizde oluşan hataları işlemek için aşağıdaki yöntemlerden birini veya her ikisini kullanın:

  • Yöntem kodunuzu try-catch bloklarında sarmalayın ve özel durum nesnesini günlüğe yazın. Hata ayıklama amacıyla özel durumu istemciye gönderebilirsiniz, ancak güvenlik nedenleriyle üretimdeki istemcilere ayrıntılı bilgi gönderilmesi önerilmez.

  • OnIncomingError yöntemini işleyen bir Hubs işlem hattı modülü oluşturun. Aşağıdaki örnek hataları günlüğe kaydeden bir işlem hattı modülünü ve ardından Modülü Hubs işlem hattına yerleştiren Global.asax kodunu gösterir.

    public class ErrorHandlingPipelineModule : HubPipelineModule
    {
        protected override void OnIncomingError(Exception ex, IHubIncomingInvokerContext context)
        {
            Debug.WriteLine("=> Exception " + ex.Message);
            if (ex.InnerException != null)
            {
                Debug.WriteLine("=> Inner Exception " + ex.InnerException.Message);
            }
            base.OnIncomingError(ex, context);
        }
    }
    
    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); 
        RouteTable.Routes.MapHubs();
    }
    

Hub işlem hattı modülleri hakkında daha fazla bilgi için bu konunun devamında Yer alan Hubs işlem hattını özelleştirme bölümüne bakın.

İzlemeyi etkinleştirme

Sunucu tarafı izlemeyi etkinleştirmek için, bu örnekte gösterildiği gibi Web.config dosyanıza bir system.diagnostics öğesi ekleyin:

<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit https://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="SignalRSamples" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;" />
    <add name="SignalRSamplesWithMARS" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;MultipleActiveResultSets=true;" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
  <system.diagnostics>
    <sources>
      <source name="SignalR.SqlMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
     <source name="SignalR.ServiceBusMessageBus">
        <listeners>
            <add name="SignalR-Bus" />
        </listeners>
     </source>
     <source name="SignalR.ScaleoutMessageBus">
        <listeners>
            <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.Transports.WebSocketTransport">
        <listeners>
          <add name="SignalR-Transports" />
        </listeners>
      </source>
      <source name="SignalR.Transports.ServerSentEventsTransport">
          <listeners>
              <add name="SignalR-Transports" />
          </listeners>
      </source>
      <source name="SignalR.Transports.ForeverFrameTransport">
          <listeners>
              <add name="SignalR-Transports" />
          </listeners>
      </source>
      <source name="SignalR.Transports.LongPollingTransport">
        <listeners>
            <add name="SignalR-Transports" />
        </listeners>
      </source>
      <source name="SignalR.Transports.TransportHeartBeat">
        <listeners>
            <add name="SignalR-Transports" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="SignalRSwitch" value="Verbose" />
    </switches>
    <sharedListeners>
      <add name="SignalR-Transports" 
           type="System.Diagnostics.TextWriterTraceListener" 
           initializeData="transports.log.txt" />
        <add name="SignalR-Bus"
           type="System.Diagnostics.TextWriterTraceListener"
           initializeData="bus.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>

Uygulamayı Visual Studio'da çalıştırdığınızda, çıkış penceresinde günlükleri görüntüleyebilirsiniz.

İstemci yöntemlerini çağırma ve Hub sınıfının dışından grupları yönetme

Hub sınıfınızdan farklı bir sınıftan istemci yöntemlerini çağırmak için Hub için SignalR bağlam nesnesine bir başvuru alın ve istemcide yöntemleri çağırmak veya grupları yönetmek için bunu kullanın.

Aşağıdaki örnek StockTicker sınıf bağlam nesnesini alır, sınıfın bir örneğinde depolar, sınıf örneğini statik bir özellikte depolar ve adlı StockTickerHubhub'a bağlı istemcilerde yöntemini çağırmak updateStockPrice için tekli sınıf örneğindeki bağlamı kullanır.

// For the complete example, go to 
// http://www.asp.net/signalr/overview/signalr-1x/getting-started/tutorial-server-broadcast-with-aspnet-signalr
// This sample only shows code related to getting and using the SignalR context.
public class StockTicker
{
    // Singleton instance
    private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(
        () => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>()));

    private IHubContext _context;

    private StockTicker(IHubContext context)
    {
        _context = context;
    }

    // This method is invoked by a Timer object.
    private void UpdateStockPrices(object state)
    {
        foreach (var stock in _stocks.Values)
        {
            if (TryUpdateStockPrice(stock))
            {
                _context.Clients.All.updateStockPrice(stock);
            }
        }
    }

Bağlamı uzun ömürlü bir nesnede birden çok kez kullanmanız gerekiyorsa, başvuruyu bir kez alın ve her seferinde yeniden almak yerine kaydedin. Bağlamı bir kez almak, SignalR'nin istemcilere hub yöntemlerinizin istemci yöntemi çağrıları yaptığı sırayla ileti göndermesini sağlar. Hub için SignalR bağlamını kullanmayı gösteren bir öğretici için bkz. ASP.NET SignalR ile Sunucu Yayını.

İstemci yöntemlerini çağırma

Hangi istemcilerin RPC alacağını belirtebilirsiniz, ancak Hub sınıfından arama yaptığınızdan daha az seçeneğiniz vardır. Bunun nedeni, bağlamın bir istemciden gelen belirli bir çağrıyla ilişkilendirilmemesidir, bu nedenle , veya veya Clients.CallerClients.OthersInGroupgibi Clients.Othersgeçerli bağlantı kimliği hakkında bilgi gerektiren yöntemler kullanılamaz. Aşağıdaki seçenekler kullanılabilir:

  • Tüm bağlı istemciler.

    context.Clients.All.addContosoChatMessageToPage(name, message);
    
  • Bağlantı kimliğiyle tanımlanan belirli bir istemci.

    context.Clients.Client(connectionID).addContosoChatMessageToPage(name, message);
    
  • Bağlantı kimliğiyle tanımlanan belirtilen istemciler dışındaki tüm bağlı istemciler.

    context.Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Belirtilen gruptaki tüm bağlı istemciler.

    context.Clients.Group(groupName).addContosoChatMessageToPage(name, message);
    
  • Belirtilen istemciler dışında, bağlantı kimliğiyle tanımlanan belirtilen bir gruptaki tüm bağlı istemciler.

    Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    

Hub sınıfınızdaki yöntemlerden Hub olmayan sınıfınızı çağırıyorsanız, geçerli bağlantı kimliğini geçirebilir ve bunu Clients.Client, Clients.AllExceptveya , veya Clients.Group simülasyonu Clients.OthersInGroupClients.CallerClients.Othersyapmak için kullanabilirsiniz. Aşağıdaki örnekte, MoveShapeHub sınıfı bağlantı kimliğini sınıfına Broadcaster geçirir, böylece sınıfın Broadcaster simülasyonunu Clients.Othersyapabilir.

// For the complete example, see
// http://www.asp.net/signalr/overview/getting-started/tutorial-high-frequency-realtime-with-signalr
// This sample only shows code that passes connection ID to the non-Hub class,
// in order to simulate Clients.Others.
public class MoveShapeHub : Hub
{
    // Code not shown puts a singleton instance of Broadcaster in this variable.
    private Broadcaster _broadcaster;

    public void UpdateModel(ShapeModel clientModel)
    {
        clientModel.LastUpdatedBy = Context.ConnectionId;
        // Update the shape model within our broadcaster
        _broadcaster.UpdateShape(clientModel);
    }
}

public class Broadcaster
{
    public Broadcaster()
    {
        _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
    }

    public void UpdateShape(ShapeModel clientModel)
    {
        _model = clientModel;
        _modelUpdated = true;
    }

    // Called by a Timer object.
    public void BroadcastShape(object state)
    {
        if (_modelUpdated)
        {
            _hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
            _modelUpdated = false;
        }
    }
}

Grup üyeliğini yönetme

Grupları yönetmek için, Hub sınıfıyla aynı seçeneklere sahipsiniz.

  • Gruba istemci ekleme

    context.Groups.Add(connectionID, groupName);
    
  • Gruptan istemci kaldırma

    context.Groups.Remove(connectionID, groupName);
    

Hubs işlem hattını özelleştirme

SignalR, Hub işlem hattına kendi kodunuzu eklemenizi sağlar. Aşağıdaki örnek, istemciden alınan her gelen yöntem çağrısını ve istemcide çağrılan giden yöntem çağrısını günlüğe kaydeden özel bir Hub işlem hattı modülünü gösterir:

public class LoggingPipelineModule : HubPipelineModule 
{ 
    protected override bool OnBeforeIncoming(IHubIncomingInvokerContext context) 
    { 
        Debug.WriteLine("=> Invoking " + context.MethodDescriptor.Name + " on hub " + context.MethodDescriptor.Hub.Name); 
        return base.OnBeforeIncoming(context); 
    }   
    protected override bool OnBeforeOutgoing(IHubOutgoingInvokerContext context) 
    { 
        Debug.WriteLine("<= Invoking " + context.Invocation.Method + " on client hub " + context.Invocation.Hub); 
        return base.OnBeforeOutgoing(context); 
    } 
}

Global.asax dosyasındaki aşağıdaki kod, hub işlem hattında çalıştırılacak modülü kaydeder:

protected void Application_Start(object sender, EventArgs e) 
{ 
    GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule()); 
    RouteTable.Routes.MapHubs();
}

Geçersiz kılabileceğiniz birçok farklı yöntem vardır. Tam liste için bkz . HubPipelineModule Yöntemleri.