SlideShare a Scribd company logo
Real-time capabilities in ASP.NET Core
web applications
Tomasz Pęczek
@tpeczek
Cross Frame Communication
(Long) Polling
Historical real-time techniques
WebSockets
Server-Sent Events
and beyond ...
Push Noti cations
Real-time technologies in HTML 5
Bidirectional
Message oriented
Text and binary
"It is the closest API to a raw network socket in the browser."
Ilya Grigorik
WebSockets
Custom protocol
Binary framing
With great power comes... complexity
IHttpWebSocketFeature
IsWebSocketRequest
AcceptAsync
WebSocket
SendAsync
ReceiveAsync
CloseAsync
ASP.NET Core WebSockets API surface
public class WebSocketConnectionsMiddleware
{
private IWebSocketConnectionsService _connectionsService;
public WebSocketConnectionsMiddleware(RequestDelegate next,
IWebSocketConnectionsService connectionsService)
{
_connectionsService = connectionsService
?? throw new ArgumentNullException(nameof(connectionsService));
}
public async Task Invoke(HttpContext context)
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
WebSocketConnection webSocketConnection = new WebSocketConnection(webSocket);
_connectionsService.AddConnection(webSocketConnection);
await webSocketConnection.ReceiveMessagesUntilCloseAsync();
if (webSocketConnection.CloseStatus.HasValue)
{
await webSocket.CloseAsync(webSocketConnection.CloseStatus.Value,
webSocketConnection.CloseStatusDescription, CancellationToken.None);
}
_connectionsService.RemoveConnection(webSocketConnection.Id);
}
else
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
}
}
}
WebSockets requests accepting middleware
public async Task ReceiveMessagesUntilCloseAsync()
{
byte[] receivePayloadBuffer = new byte[_receivePayloadBufferSize];
WebSocketReceiveResult webSocketReceiveResult =
await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer),
CancellationToken.None);
while (webSocketReceiveResult.MessageType != WebSocketMessageType.Close)
{
if (webSocketReceiveResult.MessageType == WebSocketMessageType.Binary)
{
byte[] webSocketMessage = await ReceiveMessagePayloadAsync(webSocketReceiveResult,
receivePayloadBuffer);
ReceiveBinary?.Invoke(this, webSocketMessage);
}
else
{
byte[] webSocketMessage = await ReceiveMessagePayloadAsync(webSocketReceiveResult,
receivePayloadBuffer);
ReceiveText?.Invoke(this, Encoding.UTF8.GetString(webSocketMessage));
}
webSocketReceiveResult =
await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer),
CancellationToken.None);
}
CloseStatus = webSocketReceiveResult.CloseStatus.Value;
CloseStatusDescription = webSocketReceiveResult.CloseStatusDescription;
}
Receiving loop in details
private static async Task<byte[]> ReceiveMessagePayloadAsync(
WebSocketReceiveResult webSocketReceiveResult, byte[] receivePayloadBuffer)
{
byte[] messagePayload = null;
if (webSocketReceiveResult.EndOfMessage)
{
messagePayload = new byte[webSocketReceiveResult.Count];
Array.Copy(receivePayloadBuffer, messagePayload, webSocketReceiveResult.Count);
}
else
{
using (MemoryStream messagePayloadStream = new MemoryStream())
{
messagePayloadStream.Write(receivePayloadBuffer, 0, webSocketReceiveResult.Count);
while (!webSocketReceiveResult.EndOfMessage)
{
webSocketReceiveResult =
await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer),
CancellationToken.None);
messagePayloadStream.Write(receivePayloadBuffer, 0, webSocketReceiveResult.Count);
}
messagePayload = messagePayloadStream.ToArray();
}
}
return messagePayload;
}
Receiving loop in details
public async Task ReceiveMessagesUntilCloseAsync()
{
try
{
byte[] receivePayloadBuffer = new byte[_receivePayloadBufferSize];
WebSocketReceiveResult webSocketReceiveResult =
await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer),
CancellationToken.None);
while (webSocketReceiveResult.MessageType != WebSocketMessageType.Close)
{
...
webSocketReceiveResult =
await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer),
CancellationToken.None);
}
CloseStatus = webSocketReceiveResult.CloseStatus.Value;
CloseStatusDescription = webSocketReceiveResult.CloseStatusDescription;
}
catch (WebSocketException wsex)
when (wsex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
{
// Maybe perform some logging
}
}
Receiving loop in details
private static Task SendAsync(WebSocket webSocket, byte[] message,
WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
ArraySegment<byte> messageSegment = new ArraySegment<byte>(message, 0, message.Length);
return _webSocket.SendAsync(messageSegment, messageType, endOfMessage, cancellationToken);
}
How about sending messages?
Subprotocols
Extensions
There is more!
Authentication & Authorization
Encryption
Cross-Site WebSocket Hijacking
Don't forget about the security
Unidirectional
Event oriented
Text only
"SSE is a high performance transport for server-to-client streaming of text-
based real-time data."
Ilya Grigorik
Server-Sent Events
GET /stream HTTP/1.1
...
Accept: text/event-stream
SSE is simple ...
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: text/event-stream
Transfer-Encoding: chunked
id: 1
event: LoremIpsum
data: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
id: 2
event: LoremIpsum
data: Etiam cursus leo sit amet dolor maximus, et malesuada sem volutpat.
data: Donec fringilla dui cursus ligula consectetur pulvinar.
data: Lorem ipsum ...
SSE is simple ...
Authentication & Authorization
Same-origin policy & CORS
In ight compression
Out of the box multiplexing (HTTP/2)
and more...
... it inherits all HTTP capabilities
public class ServerSentEventsMiddleware
{
private readonly RequestDelegate _next;
private readonly IServerSentEventsConnectionsService _connectionsService;
public ServerSentEventsMiddleware(RequestDelegate next,
IServerSentEventsConnectionsService connectionsService)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_connectionsService = connectionsService
?? throw new ArgumentNullException(nameof(connectionsService));
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers["Accept"] == "text/event-stream")
{
IHttpBufferingFeature bufferingFeature = context.Features.Get<IHttpBufferingFeature>();
if (bufferingFeature != null)
{
bufferingFeature.DisableResponseBuffering();
}
response.ContentType = "text/event-stream";
await response.Body.FlushAsync();
ServerSentEventsConnection serverSentEventsConnection = new ServerSentEventsConnection(
Guid.NewGuid(), context.User, context.Response);
_connectionsService.AddClient(client);
await context.RequestAborted.WaitAsync();
_connectionsService.RemoveClient(serverSentEventsConnection.Id);
}
else
{
await _next(context);
}
}
SSE middleware implementation
Use id with your messages
Client observes last seen id
Client transmits last seen id on reconnect
Automatic reconnect
"Incredibly simple real-time web for ASP.NET Core"
SignalR Hub Protocol
Transports (Duplex, Binary-safe, Text-safe)
WebSockets
Server-Sent Events + HTTP Post
Long Polling + HTTP Post
Quick mention of SignalR
In-browser push noti cations
Immediate delivery when client on-line
Delayed delivery when client o -line
HTTP Web Push & Push API
Web Push Flow
Web Push Flow
let pushServiceWorkerRegistration;
function registerPushServiceWorker() {
navigator.serviceWorker.register('/scripts/service-workers/push-service-worker.js',
{ scope: '/scripts/service-workers/push-service-worker/' })
.then(function (serviceWorkerRegistration) {
pushServiceWorkerRegistration = serviceWorkerRegistration;
...
console.log('Push Service Worker has been registered successfully');
}).catch(function (error) {
console.log('Push Service Worker registration has failed: ' + error);
});
};
Subscribing
function subscribeForPushNotifications() {
let applicationServerPublicKey = urlB64ToUint8Array('<Public Key in Base64 Format>');
pushServiceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerPublicKey
}).then(function (pushSubscription) {
fetch('push-notifications-api/subscriptions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(pushSubscription)
}).then(function (response) {
if (response.ok) {
console.log('Successfully subscribed for Push Notifications');
} else {
console.log('Failed to store Push Notifications subscription on server');
}
}).catch(function (error) {
console.log('Failed to store Push Notifications subscription on server: ' + error);
});
...
}).catch(function (error) {
if (Notification.permission === 'denied') {
...
} else {
console.log('Failed to subscribe for Push Notifications: ' + error);
}
});
};
Subscribing
self.addEventListener('push', function (event) {
event.waitUntil(self.registration.showNotification('Push Notification from ASP.NET Core', {
body: event.data.text(),
icon: '/images/push-notification-icon.png'
}));
});
Subscribing
HTTP Authentication with WebPush or VAPID scheme
JSON Web Token
<Base64 encoded JWT header JSON>.<Base64 encoded JWT body JSON>.<Base64 encoded signature>
I am who I am
private const string JWT_HEADER = "{"typ":"JWT","alg":"ES256"}";
I am who I am
private string GenerateJwtBodySegment(string audience, DateTime absoluteExpiration)
{
StringBuilder jwtBodyBuilder = new StringBuilder();
jwtBodyBuilder.Append("{"aud":"").Append(audience)
.Append("","exp":").Append(ToUnixTimeSeconds(absoluteExpiration)
.ToString(CultureInfo.InvariantCulture));
if (_subject != null)
{
jwtBodyBuilder.Append(","sub":"").Append(_subject).Append(""}");
}
else
{
jwtBodyBuilder.Append("}");
}
return UrlBase64Converter.ToUrlBase64String(
Encoding.UTF8.GetBytes(jwtBodyBuilder.ToString())
);
}
I am who I am
private static HttpRequestMessage SetAuthentication(HttpRequestMessage pushMessageDeliveryRequest,
string endpoint)
{
Uri endpointUri = new Uri(endpoint);
string audience = endpointUri.Scheme + @"://" + endpointUri.Host;
if (_authenticationScheme == VapidAuthenticationScheme.WebPush)
{
pushMessageDeliveryRequest.Headers.Authorization =
new AuthenticationHeaderValue("WebPush", GetToken(audience));
pushMessageDeliveryRequest.Headers.Add("Crypto-Key", "p256ecdsa=" + _publicKey);
}
else
{
pushMessageDeliveryRequest.Headers.Authorization =
new AuthenticationHeaderValue("vapid",
String.Format("t={0}, k={1}", GetToken(audience), _publicKey)
);
}
return pushMessageDeliveryRequest;
}
I am who I am
Utilizes Encrypted Content-Encoding
Client generates P-256 key pair and authentication secret
Server generates EDCH key pair
The public key from server EDCH is used as key id
The shared secret is used as key
For client eyes only
HttpRequestMessage pushMessageDeliveryRequest = new HttpRequestMessage(HttpMethod.Post,
subscription.Endpoint)
{
Headers =
{
{ "TTL", message.TimeToLive.ToString(CultureInfo.InvariantCulture) }
}
};
Additional attributes
private static HttpRequestMessage SetUrgency(HttpRequestMessage pushMessageDeliveryRequest,
PushMessage message)
{
switch (message.Urgency)
{
case PushMessageUrgency.Normal:
break;
case PushMessageUrgency.VeryLow:
case PushMessageUrgency.Low:
case PushMessageUrgency.High:
pushMessageDeliveryRequest.Headers
.Add("Urgency", _urgencyHeaderValues[message.Urgency]);
break;
default:
throw new NotSupportedException($"Not supported {nameof(PushMessageUrgency)}.");
}
return pushMessageDeliveryRequest;
}
Additional attributes
private static HttpRequestMessage SetTopic(HttpRequestMessage pushMessageDeliveryRequest,
PushMessage message)
{
if (!String.IsNullOrWhiteSpace(message.Topic))
{
pushMessageDeliveryRequest.Headers.Add("Topic", message.Topic);
}
return pushMessageDeliveryRequest;
}
Additional attributes
Consider primary use case ...
High performance server to client - Server-Sent Events is your friend
Durable but not critical noti cation - Web Push
WebSockets for the generic ones
When you are about to choose
... and trade o s
In case of considerable IE/Edge user base Server-Sent Events advantages
disappear
Client can disable Push Noti cations
WebSockets have potential implementation issues
When you are about to choose
You will need to scale
For WebSockets and Server-Sent Events load balancing is good choice
For Web Push consider dedicated services and sharding
Don't forget about the future
https://www.tpeczek.com/
https://github.com/tpeczek/Demo.AspNetCore.WebSockets
https://github.com/tpeczek/Lib.AspNetCore.WebSocketsCompression
https://github.com/tpeczek/Demo.AspNetCore.ServerSentEvents
https://github.com/tpeczek/Lib.AspNetCore.ServerSentEvents
https://github.com/tpeczek/Demo.AspNetCore.PushNoti cations
https://github.com/tpeczek/Lib.Net.Http.WebPush
Resources
Thank You!

More Related Content

What's hot

What are JSON Web Tokens and Why Should I Care?
What are JSON Web Tokens and Why Should I Care?What are JSON Web Tokens and Why Should I Care?
What are JSON Web Tokens and Why Should I Care?
Derek Edwards
 
Java and the blockchain - introducing web3j
Java and the blockchain - introducing web3jJava and the blockchain - introducing web3j
Java and the blockchain - introducing web3j
Conor Svensson
 
Node.js Blockchain Implementation
Node.js Blockchain ImplementationNode.js Blockchain Implementation
Node.js Blockchain Implementation
GlobalLogic Ukraine
 
2016 pycontw web api authentication
2016 pycontw web api authentication 2016 pycontw web api authentication
2016 pycontw web api authentication
Micron Technology
 
Web-Socket
Web-SocketWeb-Socket
Pushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax WPushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax W
rajivmordani
 
W3 conf hill-html5-security-realities
W3 conf hill-html5-security-realitiesW3 conf hill-html5-security-realities
W3 conf hill-html5-security-realities
Brad Hill
 
Micro Web Service - Slim and JWT
Micro Web Service - Slim and JWTMicro Web Service - Slim and JWT
Micro Web Service - Slim and JWT
Tuyen Vuong
 
JWT Authentication with AngularJS
JWT Authentication with AngularJSJWT Authentication with AngularJS
JWT Authentication with AngularJS
robertjd
 
Microservices with SenecaJS (part 2)
Microservices with SenecaJS (part 2)Microservices with SenecaJS (part 2)
Microservices with SenecaJS (part 2)
Designveloper
 
HTML5 Server Sent Events/JSF JAX 2011 Conference
HTML5 Server Sent Events/JSF  JAX 2011 ConferenceHTML5 Server Sent Events/JSF  JAX 2011 Conference
HTML5 Server Sent Events/JSF JAX 2011 Conference
Roger Kitain
 
Multi client Development with Spring
Multi client Development with SpringMulti client Development with Spring
Multi client Development with Spring
Joshua Long
 
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry BuzdinModern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
Java User Group Latvia
 
API Security : Patterns and Practices
API Security : Patterns and PracticesAPI Security : Patterns and Practices
API Security : Patterns and Practices
Prabath Siriwardena
 
I Can See Clearly Now - Observing & understanding your Spring applications at...
I Can See Clearly Now - Observing & understanding your Spring applications at...I Can See Clearly Now - Observing & understanding your Spring applications at...
I Can See Clearly Now - Observing & understanding your Spring applications at...
Joris Kuipers
 
Microservices With SenecaJS
Microservices With SenecaJSMicroservices With SenecaJS
Microservices With SenecaJS
Designveloper
 
Server side
Server sideServer side
Server side
philipsinter
 
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Fwdays
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
Joshua Long
 
Html5 websockets
Html5 websocketsHtml5 websockets
Html5 websockets
AbhishekMondal42
 

What's hot (20)

What are JSON Web Tokens and Why Should I Care?
What are JSON Web Tokens and Why Should I Care?What are JSON Web Tokens and Why Should I Care?
What are JSON Web Tokens and Why Should I Care?
 
Java and the blockchain - introducing web3j
Java and the blockchain - introducing web3jJava and the blockchain - introducing web3j
Java and the blockchain - introducing web3j
 
Node.js Blockchain Implementation
Node.js Blockchain ImplementationNode.js Blockchain Implementation
Node.js Blockchain Implementation
 
2016 pycontw web api authentication
2016 pycontw web api authentication 2016 pycontw web api authentication
2016 pycontw web api authentication
 
Web-Socket
Web-SocketWeb-Socket
Web-Socket
 
Pushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax WPushing Datatothe Browserwith Comet Ajax W
Pushing Datatothe Browserwith Comet Ajax W
 
W3 conf hill-html5-security-realities
W3 conf hill-html5-security-realitiesW3 conf hill-html5-security-realities
W3 conf hill-html5-security-realities
 
Micro Web Service - Slim and JWT
Micro Web Service - Slim and JWTMicro Web Service - Slim and JWT
Micro Web Service - Slim and JWT
 
JWT Authentication with AngularJS
JWT Authentication with AngularJSJWT Authentication with AngularJS
JWT Authentication with AngularJS
 
Microservices with SenecaJS (part 2)
Microservices with SenecaJS (part 2)Microservices with SenecaJS (part 2)
Microservices with SenecaJS (part 2)
 
HTML5 Server Sent Events/JSF JAX 2011 Conference
HTML5 Server Sent Events/JSF  JAX 2011 ConferenceHTML5 Server Sent Events/JSF  JAX 2011 Conference
HTML5 Server Sent Events/JSF JAX 2011 Conference
 
Multi client Development with Spring
Multi client Development with SpringMulti client Development with Spring
Multi client Development with Spring
 
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry BuzdinModern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
Modern Security with OAuth 2.0 and JWT and Spring by Dmitry Buzdin
 
API Security : Patterns and Practices
API Security : Patterns and PracticesAPI Security : Patterns and Practices
API Security : Patterns and Practices
 
I Can See Clearly Now - Observing & understanding your Spring applications at...
I Can See Clearly Now - Observing & understanding your Spring applications at...I Can See Clearly Now - Observing & understanding your Spring applications at...
I Can See Clearly Now - Observing & understanding your Spring applications at...
 
Microservices With SenecaJS
Microservices With SenecaJSMicroservices With SenecaJS
Microservices With SenecaJS
 
Server side
Server sideServer side
Server side
 
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
Alexey Kupriyanenko "The State of Modern JavaScript and Web in 2020 - Real us...
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
 
Html5 websockets
Html5 websocketsHtml5 websockets
Html5 websockets
 

Similar to 4Developers 2018: Real-time capabilities in ASP.NET Core web applications (Tomasz Pęczek)

WebSockets in JEE 7
WebSockets in JEE 7WebSockets in JEE 7
WebSockets in JEE 7
Shahzad Badar
 
Web Real-time Communications
Web Real-time CommunicationsWeb Real-time Communications
Web Real-time Communications
Alexei Skachykhin
 
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha
 
Building Websocket Applications with GlassFish and Grizzly
Building Websocket Applications with GlassFish and GrizzlyBuilding Websocket Applications with GlassFish and Grizzly
Building Websocket Applications with GlassFish and Grizzly
Justin Lee
 
Server-Sent Events in Action
Server-Sent Events in ActionServer-Sent Events in Action
Server-Sent Events in Action
Andrei Rusu
 
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java DevelopersWebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
Viktor Gamov
 
Message in a Bottle
Message in a BottleMessage in a Bottle
Message in a Bottle
Zohar Arad
 
The HTML5 WebSocket API
The HTML5 WebSocket APIThe HTML5 WebSocket API
The HTML5 WebSocket API
David Lindkvist
 
Scaling asp.net websites to millions of users
Scaling asp.net websites to millions of usersScaling asp.net websites to millions of users
Scaling asp.net websites to millions of users
oazabir
 
Websocket
WebsocketWebsocket
Websocket
艾鍗科技
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
FDConf
 
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
BizTalk360
 
Pushing the Boundaries of Sencha and HTML5′s WebRTC
Pushing the Boundaries of Sencha and HTML5′s WebRTCPushing the Boundaries of Sencha and HTML5′s WebRTC
Pushing the Boundaries of Sencha and HTML5′s WebRTC
Rich Waters
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
Yakov Fain
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serialization
GWTcon
 
Unit-5.pptx
Unit-5.pptxUnit-5.pptx
Unit-5.pptx
itzkuu01
 
Building interactivity with websockets
Building interactivity with websocketsBuilding interactivity with websockets
Building interactivity with websockets
Wim Godden
 
Node.js introduction
Node.js introductionNode.js introduction
Node.js introduction
Parth Joshi
 
The complete ASP.NET (IIS) Tutorial with code example in power point slide show
The complete ASP.NET (IIS) Tutorial with code example in power point slide showThe complete ASP.NET (IIS) Tutorial with code example in power point slide show
The complete ASP.NET (IIS) Tutorial with code example in power point slide show
Subhas Malik
 
WCF 4 Overview
WCF 4 OverviewWCF 4 Overview
WCF 4 Overview
Mariano Omar Rodriguez
 

Similar to 4Developers 2018: Real-time capabilities in ASP.NET Core web applications (Tomasz Pęczek) (20)

WebSockets in JEE 7
WebSockets in JEE 7WebSockets in JEE 7
WebSockets in JEE 7
 
Web Real-time Communications
Web Real-time CommunicationsWeb Real-time Communications
Web Real-time Communications
 
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
 
Building Websocket Applications with GlassFish and Grizzly
Building Websocket Applications with GlassFish and GrizzlyBuilding Websocket Applications with GlassFish and Grizzly
Building Websocket Applications with GlassFish and Grizzly
 
Server-Sent Events in Action
Server-Sent Events in ActionServer-Sent Events in Action
Server-Sent Events in Action
 
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java DevelopersWebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
WebSockets: The Current State of the Most Valuable HTML5 API for Java Developers
 
Message in a Bottle
Message in a BottleMessage in a Bottle
Message in a Bottle
 
The HTML5 WebSocket API
The HTML5 WebSocket APIThe HTML5 WebSocket API
The HTML5 WebSocket API
 
Scaling asp.net websites to millions of users
Scaling asp.net websites to millions of usersScaling asp.net websites to millions of users
Scaling asp.net websites to millions of users
 
Websocket
WebsocketWebsocket
Websocket
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
Use Windows Azure Service Bus, BizTalk Services, Mobile Services, and BizTalk...
 
Pushing the Boundaries of Sencha and HTML5′s WebRTC
Pushing the Boundaries of Sencha and HTML5′s WebRTCPushing the Boundaries of Sencha and HTML5′s WebRTC
Pushing the Boundaries of Sencha and HTML5′s WebRTC
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSockets
 
GWT Web Socket and data serialization
GWT Web Socket and data serializationGWT Web Socket and data serialization
GWT Web Socket and data serialization
 
Unit-5.pptx
Unit-5.pptxUnit-5.pptx
Unit-5.pptx
 
Building interactivity with websockets
Building interactivity with websocketsBuilding interactivity with websockets
Building interactivity with websockets
 
Node.js introduction
Node.js introductionNode.js introduction
Node.js introduction
 
The complete ASP.NET (IIS) Tutorial with code example in power point slide show
The complete ASP.NET (IIS) Tutorial with code example in power point slide showThe complete ASP.NET (IIS) Tutorial with code example in power point slide show
The complete ASP.NET (IIS) Tutorial with code example in power point slide show
 
WCF 4 Overview
WCF 4 OverviewWCF 4 Overview
WCF 4 Overview
 

Recently uploaded

Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Malak Abu Hammad
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
SitimaJohn
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
Zilliz
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
Federico Razzoli
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
Zilliz
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Hiroshi SHIBATA
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
Ivanti
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
Jason Packer
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
MichaelKnudsen27
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
Jakub Marek
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
Tomaz Bratanic
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
ssuserfac0301
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Jeffrey Haguewood
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc
 
OpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - AuthorizationOpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - Authorization
David Brossard
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
panagenda
 

Recently uploaded (20)

Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdfUnlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
Unlock the Future of Search with MongoDB Atlas_ Vector Search Unleashed.pdf
 
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptxOcean lotus Threat actors project by John Sitima 2024 (1).pptx
Ocean lotus Threat actors project by John Sitima 2024 (1).pptx
 
Fueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte WebinarFueling AI with Great Data with Airbyte Webinar
Fueling AI with Great Data with Airbyte Webinar
 
Webinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data WarehouseWebinar: Designing a schema for a Data Warehouse
Webinar: Designing a schema for a Data Warehouse
 
Building Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and MilvusBuilding Production Ready Search Pipelines with Spark and Milvus
Building Production Ready Search Pipelines with Spark and Milvus
 
Introduction of Cybersecurity with OSS at Code Europe 2024
Introduction of Cybersecurity with OSS  at Code Europe 2024Introduction of Cybersecurity with OSS  at Code Europe 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
 
Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024Columbus Data & Analytics Wednesdays - June 2024
Columbus Data & Analytics Wednesdays - June 2024
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 
Nordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptxNordic Marketo Engage User Group_June 13_ 2024.pptx
Nordic Marketo Engage User Group_June 13_ 2024.pptx
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)Main news related to the CCS TSI 2023 (2023/1695)
Main news related to the CCS TSI 2023 (2023/1695)
 
GraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracyGraphRAG for Life Science to increase LLM accuracy
GraphRAG for Life Science to increase LLM accuracy
 
Taking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdfTaking AI to the Next Level in Manufacturing.pdf
Taking AI to the Next Level in Manufacturing.pdf
 
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
Salesforce Integration for Bonterra Impact Management (fka Social Solutions A...
 
TrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy SurveyTrustArc Webinar - 2024 Global Privacy Survey
TrustArc Webinar - 2024 Global Privacy Survey
 
OpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - AuthorizationOpenID AuthZEN Interop Read Out - Authorization
OpenID AuthZEN Interop Read Out - Authorization
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAUHCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
HCL Notes und Domino Lizenzkostenreduzierung in der Welt von DLAU
 

4Developers 2018: Real-time capabilities in ASP.NET Core web applications (Tomasz Pęczek)

  • 1. Real-time capabilities in ASP.NET Core web applications Tomasz Pęczek @tpeczek
  • 2. Cross Frame Communication (Long) Polling Historical real-time techniques
  • 3. WebSockets Server-Sent Events and beyond ... Push Noti cations Real-time technologies in HTML 5
  • 4. Bidirectional Message oriented Text and binary "It is the closest API to a raw network socket in the browser." Ilya Grigorik WebSockets
  • 5. Custom protocol Binary framing With great power comes... complexity
  • 7. public class WebSocketConnectionsMiddleware { private IWebSocketConnectionsService _connectionsService; public WebSocketConnectionsMiddleware(RequestDelegate next, IWebSocketConnectionsService connectionsService) { _connectionsService = connectionsService ?? throw new ArgumentNullException(nameof(connectionsService)); } public async Task Invoke(HttpContext context) { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); WebSocketConnection webSocketConnection = new WebSocketConnection(webSocket); _connectionsService.AddConnection(webSocketConnection); await webSocketConnection.ReceiveMessagesUntilCloseAsync(); if (webSocketConnection.CloseStatus.HasValue) { await webSocket.CloseAsync(webSocketConnection.CloseStatus.Value, webSocketConnection.CloseStatusDescription, CancellationToken.None); } _connectionsService.RemoveConnection(webSocketConnection.Id); } else { context.Response.StatusCode = StatusCodes.Status400BadRequest; } } } WebSockets requests accepting middleware
  • 8. public async Task ReceiveMessagesUntilCloseAsync() { byte[] receivePayloadBuffer = new byte[_receivePayloadBufferSize]; WebSocketReceiveResult webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer), CancellationToken.None); while (webSocketReceiveResult.MessageType != WebSocketMessageType.Close) { if (webSocketReceiveResult.MessageType == WebSocketMessageType.Binary) { byte[] webSocketMessage = await ReceiveMessagePayloadAsync(webSocketReceiveResult, receivePayloadBuffer); ReceiveBinary?.Invoke(this, webSocketMessage); } else { byte[] webSocketMessage = await ReceiveMessagePayloadAsync(webSocketReceiveResult, receivePayloadBuffer); ReceiveText?.Invoke(this, Encoding.UTF8.GetString(webSocketMessage)); } webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer), CancellationToken.None); } CloseStatus = webSocketReceiveResult.CloseStatus.Value; CloseStatusDescription = webSocketReceiveResult.CloseStatusDescription; } Receiving loop in details
  • 9. private static async Task<byte[]> ReceiveMessagePayloadAsync( WebSocketReceiveResult webSocketReceiveResult, byte[] receivePayloadBuffer) { byte[] messagePayload = null; if (webSocketReceiveResult.EndOfMessage) { messagePayload = new byte[webSocketReceiveResult.Count]; Array.Copy(receivePayloadBuffer, messagePayload, webSocketReceiveResult.Count); } else { using (MemoryStream messagePayloadStream = new MemoryStream()) { messagePayloadStream.Write(receivePayloadBuffer, 0, webSocketReceiveResult.Count); while (!webSocketReceiveResult.EndOfMessage) { webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer), CancellationToken.None); messagePayloadStream.Write(receivePayloadBuffer, 0, webSocketReceiveResult.Count); } messagePayload = messagePayloadStream.ToArray(); } } return messagePayload; } Receiving loop in details
  • 10. public async Task ReceiveMessagesUntilCloseAsync() { try { byte[] receivePayloadBuffer = new byte[_receivePayloadBufferSize]; WebSocketReceiveResult webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer), CancellationToken.None); while (webSocketReceiveResult.MessageType != WebSocketMessageType.Close) { ... webSocketReceiveResult = await _webSocket.ReceiveAsync(new ArraySegment<byte>(receivePayloadBuffer), CancellationToken.None); } CloseStatus = webSocketReceiveResult.CloseStatus.Value; CloseStatusDescription = webSocketReceiveResult.CloseStatusDescription; } catch (WebSocketException wsex) when (wsex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely) { // Maybe perform some logging } } Receiving loop in details
  • 11. private static Task SendAsync(WebSocket webSocket, byte[] message, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { ArraySegment<byte> messageSegment = new ArraySegment<byte>(message, 0, message.Length); return _webSocket.SendAsync(messageSegment, messageType, endOfMessage, cancellationToken); } How about sending messages?
  • 13. Authentication & Authorization Encryption Cross-Site WebSocket Hijacking Don't forget about the security
  • 14. Unidirectional Event oriented Text only "SSE is a high performance transport for server-to-client streaming of text- based real-time data." Ilya Grigorik Server-Sent Events
  • 15. GET /stream HTTP/1.1 ... Accept: text/event-stream SSE is simple ...
  • 16. HTTP/1.1 200 OK Connection: keep-alive Content-Type: text/event-stream Transfer-Encoding: chunked id: 1 event: LoremIpsum data: Lorem ipsum dolor sit amet, consectetur adipiscing elit. id: 2 event: LoremIpsum data: Etiam cursus leo sit amet dolor maximus, et malesuada sem volutpat. data: Donec fringilla dui cursus ligula consectetur pulvinar. data: Lorem ipsum ... SSE is simple ...
  • 17. Authentication & Authorization Same-origin policy & CORS In ight compression Out of the box multiplexing (HTTP/2) and more... ... it inherits all HTTP capabilities
  • 18. public class ServerSentEventsMiddleware { private readonly RequestDelegate _next; private readonly IServerSentEventsConnectionsService _connectionsService; public ServerSentEventsMiddleware(RequestDelegate next, IServerSentEventsConnectionsService connectionsService) { _next = next ?? throw new ArgumentNullException(nameof(next)); _connectionsService = connectionsService ?? throw new ArgumentNullException(nameof(connectionsService)); } public async Task Invoke(HttpContext context) { if (context.Request.Headers["Accept"] == "text/event-stream") { IHttpBufferingFeature bufferingFeature = context.Features.Get<IHttpBufferingFeature>(); if (bufferingFeature != null) { bufferingFeature.DisableResponseBuffering(); } response.ContentType = "text/event-stream"; await response.Body.FlushAsync(); ServerSentEventsConnection serverSentEventsConnection = new ServerSentEventsConnection( Guid.NewGuid(), context.User, context.Response); _connectionsService.AddClient(client); await context.RequestAborted.WaitAsync(); _connectionsService.RemoveClient(serverSentEventsConnection.Id); } else { await _next(context); } } SSE middleware implementation
  • 19. Use id with your messages Client observes last seen id Client transmits last seen id on reconnect Automatic reconnect
  • 20. "Incredibly simple real-time web for ASP.NET Core" SignalR Hub Protocol Transports (Duplex, Binary-safe, Text-safe) WebSockets Server-Sent Events + HTTP Post Long Polling + HTTP Post Quick mention of SignalR
  • 21. In-browser push noti cations Immediate delivery when client on-line Delayed delivery when client o -line HTTP Web Push & Push API
  • 24. let pushServiceWorkerRegistration; function registerPushServiceWorker() { navigator.serviceWorker.register('/scripts/service-workers/push-service-worker.js', { scope: '/scripts/service-workers/push-service-worker/' }) .then(function (serviceWorkerRegistration) { pushServiceWorkerRegistration = serviceWorkerRegistration; ... console.log('Push Service Worker has been registered successfully'); }).catch(function (error) { console.log('Push Service Worker registration has failed: ' + error); }); }; Subscribing
  • 25. function subscribeForPushNotifications() { let applicationServerPublicKey = urlB64ToUint8Array('<Public Key in Base64 Format>'); pushServiceWorkerRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: applicationServerPublicKey }).then(function (pushSubscription) { fetch('push-notifications-api/subscriptions', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(pushSubscription) }).then(function (response) { if (response.ok) { console.log('Successfully subscribed for Push Notifications'); } else { console.log('Failed to store Push Notifications subscription on server'); } }).catch(function (error) { console.log('Failed to store Push Notifications subscription on server: ' + error); }); ... }).catch(function (error) { if (Notification.permission === 'denied') { ... } else { console.log('Failed to subscribe for Push Notifications: ' + error); } }); }; Subscribing
  • 26. self.addEventListener('push', function (event) { event.waitUntil(self.registration.showNotification('Push Notification from ASP.NET Core', { body: event.data.text(), icon: '/images/push-notification-icon.png' })); }); Subscribing
  • 27. HTTP Authentication with WebPush or VAPID scheme JSON Web Token <Base64 encoded JWT header JSON>.<Base64 encoded JWT body JSON>.<Base64 encoded signature> I am who I am
  • 28. private const string JWT_HEADER = "{"typ":"JWT","alg":"ES256"}"; I am who I am
  • 29. private string GenerateJwtBodySegment(string audience, DateTime absoluteExpiration) { StringBuilder jwtBodyBuilder = new StringBuilder(); jwtBodyBuilder.Append("{"aud":"").Append(audience) .Append("","exp":").Append(ToUnixTimeSeconds(absoluteExpiration) .ToString(CultureInfo.InvariantCulture)); if (_subject != null) { jwtBodyBuilder.Append(","sub":"").Append(_subject).Append(""}"); } else { jwtBodyBuilder.Append("}"); } return UrlBase64Converter.ToUrlBase64String( Encoding.UTF8.GetBytes(jwtBodyBuilder.ToString()) ); } I am who I am
  • 30. private static HttpRequestMessage SetAuthentication(HttpRequestMessage pushMessageDeliveryRequest, string endpoint) { Uri endpointUri = new Uri(endpoint); string audience = endpointUri.Scheme + @"://" + endpointUri.Host; if (_authenticationScheme == VapidAuthenticationScheme.WebPush) { pushMessageDeliveryRequest.Headers.Authorization = new AuthenticationHeaderValue("WebPush", GetToken(audience)); pushMessageDeliveryRequest.Headers.Add("Crypto-Key", "p256ecdsa=" + _publicKey); } else { pushMessageDeliveryRequest.Headers.Authorization = new AuthenticationHeaderValue("vapid", String.Format("t={0}, k={1}", GetToken(audience), _publicKey) ); } return pushMessageDeliveryRequest; } I am who I am
  • 31. Utilizes Encrypted Content-Encoding Client generates P-256 key pair and authentication secret Server generates EDCH key pair The public key from server EDCH is used as key id The shared secret is used as key For client eyes only
  • 32. HttpRequestMessage pushMessageDeliveryRequest = new HttpRequestMessage(HttpMethod.Post, subscription.Endpoint) { Headers = { { "TTL", message.TimeToLive.ToString(CultureInfo.InvariantCulture) } } }; Additional attributes
  • 33. private static HttpRequestMessage SetUrgency(HttpRequestMessage pushMessageDeliveryRequest, PushMessage message) { switch (message.Urgency) { case PushMessageUrgency.Normal: break; case PushMessageUrgency.VeryLow: case PushMessageUrgency.Low: case PushMessageUrgency.High: pushMessageDeliveryRequest.Headers .Add("Urgency", _urgencyHeaderValues[message.Urgency]); break; default: throw new NotSupportedException($"Not supported {nameof(PushMessageUrgency)}."); } return pushMessageDeliveryRequest; } Additional attributes
  • 34. private static HttpRequestMessage SetTopic(HttpRequestMessage pushMessageDeliveryRequest, PushMessage message) { if (!String.IsNullOrWhiteSpace(message.Topic)) { pushMessageDeliveryRequest.Headers.Add("Topic", message.Topic); } return pushMessageDeliveryRequest; } Additional attributes
  • 35. Consider primary use case ... High performance server to client - Server-Sent Events is your friend Durable but not critical noti cation - Web Push WebSockets for the generic ones When you are about to choose
  • 36. ... and trade o s In case of considerable IE/Edge user base Server-Sent Events advantages disappear Client can disable Push Noti cations WebSockets have potential implementation issues When you are about to choose
  • 37. You will need to scale For WebSockets and Server-Sent Events load balancing is good choice For Web Push consider dedicated services and sharding Don't forget about the future