ASP.NET Core desteği WebSockets

Tom Dykstra ve Andrew Stanton-nurte

Bu makalede, ASP.NET Core ' de WebSockets ile çalışmaya başlama açıklanmaktadır. WebSocket (RFC 6455), TCP bağlantıları üzerinden iki yönlü kalıcı iletişim kanalları sağlayan bir protokoldür. Bu, sohbet, pano ve oyun uygulamaları gibi hızlı, gerçek zamanlı iletişimden faydalanabilir uygulamalarda kullanılır.

Örnek kodu görüntüleyin veya indirin (nasıl indirilir). Nasıl çalıştırılır?

SignalR

ASP.NET Core SignalR , uygulamalara gerçek zamanlı Web işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. Mümkün olduğunda WebSockets kullanır.

Çoğu uygulama için SignalR Ham WebSockets üzerinde önerilir. SignalR WebSockets ' nin kullanılamadığı ortamlar için taşıma geri dönüşü sağlar. Ayrıca temel bir uzak yordam çağrısı uygulama modeli sağlar. Ve çoğu senaryoda SignalR Ham WebSockets kullanmaya kıyasla önemli bir performans olumsuz yanı yoktur.

Bazı uygulamalarda, .net 'Teki GRPC , WebSockets için bir alternatif sağlar.

Önkoşullar

  • ASP.NET Core destekleyen herhangi bir işletim sistemi:
    • Windows 7/Windows Server 2008 veya üzeri
    • Linux
    • macOS
  • uygulama ııs ile Windows üzerinde çalışıyorsa:
    • Windows 8/Windows Server 2012 veya üzeri
    • IIS 8/IIS 8 Express
    • WebSockets etkinleştirilmelidir. bkz. ııs/IIS Express desteği bölümü.
  • Uygulama HTTP.sysüzerinde çalışıyorsa:
    • Windows 8/Windows Server 2012 veya üzeri
  • Desteklenen tarayıcılar için bkz https://caniuse.com/#feat=websockets ..

Ara yazılımı yapılandırma

WebSockets ara yazılımını Configure sınıfının yöntemine ekleyin Startup :

app.UseWebSockets();

Not

Bir denetleyicide WebSocket isteklerini kabul etmek isterseniz, çağrısının daha app.UseWebSockets önce gerçekleşmesi gerekir app.UseEndpoints .

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval -Proxy 'lerin bağlantının açık kalmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval -Proxy 'lerin bağlantının açık kalmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.
  • AllowedOrigins -WebSocket istekleri için izin verilen kaynak üst bilgi değerleri listesi. Varsayılan olarak, tüm kaynaklardan izin verilir. Ayrıntılar için aşağıdaki "WebSocket kaynak kısıtlaması" başlığına bakın.
var webSocketOptions = new WebSocketOptions() 
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

WebSocket isteklerini kabul et

Daha sonra istek yaşam döngüsünün (daha sonra Configure yöntemde veya bir eylem yönteminde daha sonra) bir yerde, bir WebSocket isteği olup olmadığını denetleyin ve WebSocket isteğini kabul edin.

Aşağıdaki örnek daha sonra Configure yönteminde verilmiştir:

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
            {
                await Echo(context, webSocket);
            }
        }
        else
        {
            context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
        }
    }
    else
    {
        await next();
    }

});

Herhangi bir URL 'de bir WebSocket isteği gelebilir, ancak bu örnek kod yalnızca için istekleri kabul eder /ws .

Benzer bir yaklaşım, bir denetleyici yönteminde alınabilir:

public class WebSocketController : ControllerBase
{
    [HttpGet("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using WebSocket webSocket = await 
                               HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(HttpContext, webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
        }
    }

WebSocket kullanırken, bağlantı süresince ara yazılım işlem hattını çalışır durumda tutmanız gerekir . Ara yazılım ardışık düzeni bittikten sonra bir WebSocket iletisi göndermeye veya almaya çalışırsanız, aşağıdaki gibi bir özel durum alabilirsiniz:

System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.

WebSocket 'e veri yazmak için bir arka plan hizmeti kullanıyorsanız, ara yazılım ardışık düzenini çalışır durumda tutmanız gerekir. Bunu kullanarak yapın TaskCompletionSource<TResult> . TaskCompletionSource' İ arka plan hizmetinize geçirin ve WebSocket ile bitirdiğinizde bu hizmete çağrı yapın TrySetResult . Ardından await , Task Aşağıdaki örnekte gösterildiği gibi istek sırasında özelliği:

app.Use(async (context, next) =>
{
    using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
    {
        var socketFinishedTcs = new TaskCompletionSource<object>();

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

WebSocket kapalı özel durumu bir eylem yönteminden çok yakında döndürüldükten sonra da gerçekleşebilir. Bir eylem yönteminde yuva kabul edilirken, işlem yönteminden dönmeden önce yuva kullanan kodun tamamlanmasını bekleyin.

Task.Wait Task.Result Önemli iş parçacığı sorunlarına neden olabileceği için, yuvanın tamamlanmasını beklemek için hiçbir şekilde, veya benzer engelleme çağrılarını kullanmayın. Her zaman kullanın await .

Sıkıştırma

Uyarı

Şifrelenmiş bağlantılar üzerinde sıkıştırmayı etkinleştirmek, bir uygulamayı suç/Ihlal saldırılarına maruz hale getirir. Gizli bilgiler gönderiyorsanız, sıkıştırma veya çağırma sırasında kullanımı kullanmaktan kaçının WebSocketMessageFlags.DisableCompression WebSocket.SendAsync . Bu, WebSocket 'in her iki tarafında da geçerlidir. Tarayıcıda WebSockets API 'sinin, gönderme başına sıkıştırmayı devre dışı bırakma yapılandırmasına sahip olmadığına unutmayın.

WebSockets üzerinden ileti sıkıştırması isteniyorsa, kabul kodu aşağıdaki şekilde sıkıştırmaya izin verdiğini belirtmelidir:

using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext() { DangerousEnableCompression = true }))
{
}

WebSocketAcceptContext.ServerMaxWindowBits ve WebSocketAcceptContext.DisableServerContextTakeover , sıkıştırmanın nasıl çalıştığını denetleyen gelişmiş seçeneklerdir.

İlk bağlantı kurulurken istemci ve sunucu arasında sıkıştırma işlemi yapılır. Anlaşma hakkında daha fazla bilgi için bkz. WEBSOCKET RFC Için sıkıştırma uzantıları.

Not

Sıkıştırma anlaşması sunucu veya istemci tarafından kabul edilmemişse bağlantı yine de oluşturulur. Ancak bağlantı, iletileri gönderirken ve alırken sıkıştırma kullanmaz.

İleti alma ve gönderme

AcceptWebSocketAsyncYöntemi, TCP bağlantısını bir WebSocket bağlantısıyla yükseltir ve bir WebSocket nesnesi sağlar. WebSocketİleti göndermek ve almak için nesnesini kullanın.

WebSocket isteğini kabul eden daha önce gösterilen kod, WebSocket nesneyi bir Echo yönteme geçirir. Kod bir ileti alır ve hemen aynı iletiyi geri gönderir. İletiler, istemci bağlantıyı kapatana kadar bir döngüde gönderilir ve alınır:

private async Task Echo(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

Döngüye başlamadan önce WebSocket bağlantısı kabul edildiğinde, ara yazılım ardışık düzeni sona erer. Yuva kapatıldıktan sonra işlem hattı kaldırımları. Diğer bir deyişle, WebSocket kabul edildiğinde isteğin işlem hattında ileri doğru hareket ettirilmesi durduruluyor. Döngü bittiğinde ve yuva kapalıyken, istek ardışık düzeni yedekler.

İstemci bağlantısı kesilen işleme

İstemci bağlantı kaybı nedeniyle bağlantısı kesildiğinde sunucu otomatik olarak bilgilendirilmedi. Sunucu, yalnızca istemci gönderirse, internet bağlantısı kaybedilmişse gerçekleştirilemez bir bağlantı kesme iletisi alır. Bu durumda bazı işlemleri gerçekleştirmek istiyorsanız, belirli bir zaman penceresinde istemciden hiçbir şey alınmadığında bir zaman aşımı ayarlayın.

İstemci her zaman ileti göndermiyor ve bağlantı boşta kaldığı için zaman aşımına uğramasını istemiyorsanız, istemcinin her X saniyede bir ping iletisi göndermesi için bir Zamanlayıcı kullanmasını sağlamak için bir Zamanlayıcı kullanmasını sağlayabilirsiniz. Sunucusunda, bir ileti * öncekinden sonra 2 X saniye içinde gelmediyse, bağlantıyı sonlandırın ve istemcinin bağlantısının kesildiğini bildirin. Beklenen zaman aralığının iki kez, ping iletisini tutabilecek Ağ gecikmeleri için ek süre kalmasını bekleyin.

WebSocket kaynak kısıtlaması

CORS tarafından sunulan korumalar WebSockets için geçerlidir. Tarayıcılar şunları desteklemez:

  • CORS ön uçuş istekleri gerçekleştirin.
  • Access-ControlWebSocket istekleri yapılırken üst bilgilerde belirtilen kısıtlamalara saygı.

Ancak, tarayıcılar Origin WebSocket istekleri verirken üstbilgiyi gönderir. Yalnızca beklenen kaynaklardan gelen WebSockets izin verildiğinden emin olmak için uygulamalar bu üstbilgileri doğrulamak üzere yapılandırılmalıdır.

Sunucunuzu "" üzerinde barındırıyorsanız https://server.com ve istemcinizi "" üzerinde barındırıyorsanız https://client.com , https://client.com AllowedOrigins doğrulamak için WebSockets listesine "" ekleyin.

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Not

OriginÜst bilgi istemci tarafından denetlenir ve Referer üst bilgi gibi erişilebilir. Bu üst bilgileri kimlik doğrulama mekanizması olarak kullanmayın.

ııs/IIS Express desteği

Windows Server 2012 veya üzeri ve ııs/IIS Express 8 veya üzeri ile Windows 8 veya üzeri, WebSocket protokolü için destek içerir.

Not

IIS Express kullanılırken WebSockets her zaman etkindir.

IIS üzerinde WebSockets etkinleştirme

Windows Server 2012 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Yönet menüsündeki rol ve özellik ekleme sihirbazı ' nı veya Sunucu Yöneticisi bağlantısındaki bağlantıyı kullanın.
  2. Rol tabanlı veya özellik tabanlı yükleme' yi seçin. İleri’yi seçin.
  3. Uygun sunucuyu seçin (yerel sunucu varsayılan olarak seçilidir). İleri’yi seçin.
  4. Roller ağacında Web sunucusu (IIS) öğesini genişletin, Web sunucusu' nu genişletin ve ardından uygulama geliştirme' yi genişletin.
  5. WebSocket protokolünü seçin. İleri’yi seçin.
  6. Ek özellikler gerekmiyorsa, İleri' yi seçin.
  7. Yükle'yi seçin.
  8. Yükleme tamamlandığında sihirbazdan çıkmak için Kapat ' ı seçin.

Windows 8 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. denetim masası > programlar > programlar ve özellikler' e gidin > Windows özellikleri açın veya kapatın (ekranın sol tarafında).
  2. şu düğümleri açın: Internet Information Services > World Wide Web Services > uygulama geliştirme özellikleri.
  3. WebSocket protokolü özelliğini seçin. Tamam’ı seçin.

Node.js üzerinde socket.io kullanırken WebSocket 'i devre dışı bırak

Node.jsüzerinde Socket.io ' de WebSocket DESTEĞINI kullanıyorsanız, varsayılan IIS WebSocket modülünü webSocket web.config veya applicationHost.config öğesini kullanarak devre dışı bırakın. Bu adım gerçekleştirilmemişse, IIS WebSocket modülü Node.js ve uygulama yerine WebSocket iletişimini işlemeye çalışır.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Örnek uygulama

Bu makaleye eşlik eden örnek uygulama bir Echo uygulamasıdır. WebSocket bağlantısı yapan bir Web sayfasına sahiptir ve sunucu istemciye geri aldığı tüm iletileri daha sonra sonlandırır. örnek uygulama, IIS Express ile Visual Studio çalışacak şekilde yapılandırılmamış, bu nedenle uygulamayı ile bir komut kabuğunda çalıştırın dotnet run ve ' a bir tarayıcıda gidin http://localhost:5000 . Web sayfası bağlantı durumunu gösterir:

WebSockets bağlantısından önce Web sayfasının ilk durumu

gösterilen URL 'ye bir WebSocket isteği göndermek için Bağlan ' ı seçin. Bir sınama iletisi girin ve Gönder' i seçin. İşiniz bittiğinde yuvayı kapat' ı seçin. Iletişim günlüğü bölümünde her açık, gönder ve Kapat eylemi gerçekleşir.

WebSockets bağlantısı ve test iletileri gönderildikten ve alındıktan sonra Web sayfasının son durumu