diff --git a/.gitignore b/.gitignore
index 45d2095cdb31cf0937596e088eea358648b4bccd..d499d77000223514ac4d47d5200a27b35f00b034 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ server/worldstorage/README.md
 
 # all generated directories
 wwwroot/
+!wwwroot/ws.html
 Attributes/
 Authentication/
 Converters/
diff --git a/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/ETSI-ARF/ControllersImpl/WebSocketController.cs b/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/ETSI-ARF/ControllersImpl/WebSocketController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e80b54d679b0ac6e03429de8246451ca5e6ab9d
--- /dev/null
+++ b/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/ETSI-ARF/ControllersImpl/WebSocketController.cs
@@ -0,0 +1,125 @@
+//
+// ARF - Augmented Reality Framework (ETSI ISG ARF)
+//
+// Copyright 2024 ETSI
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Last change: June 2024
+//
+
+using System;
+using System.Text;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Net.WebSockets;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Http;
+using Swashbuckle.AspNetCore.Annotations;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+#pragma warning disable CS1591 // Fehlendes XML-Kommentar für öffentlich sichtbaren Typ oder Element
+namespace ETSI.ARF.OpenAPI.WorldStorage.Services
+{
+    //
+    // ETSI-ARF World Analysis WebSocket implementation
+    // see also: https://learn.microsoft.com/de-de/aspnet/core/fundamentals/websockets?view=aspnetcore-5.0
+    //
+    public class WebSocketController : ControllerBase
+    {
+        [HttpGet("/ws")]
+        public async Task Get()
+        {
+            if (HttpContext.WebSockets.IsWebSocketRequest)
+            {
+                using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
+
+                if (webSocket.State == WebSocketState.Open)
+                {
+                    // Response an OK message
+                    await SendText(webSocket, "Hello, here is the ARF World Analysis services!");
+                }
+                await Echo(HttpContext, webSocket);
+            }
+            else
+            {
+                await HttpContext.Response.WriteAsync("ETSI-ARF World Analysis: Not a valid WebSocket request.");
+                HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
+            }
+        }
+
+        //
+        // Send a line of text
+        //
+        private async Task SendText(WebSocket webSocket, string text)
+        {
+            // Response an OK message
+            var message = text;
+            var bytes = Encoding.UTF8.GetBytes(message);
+            var arraySegment = new ArraySegment<byte>(bytes, 0, bytes.Length);
+            await webSocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
+        }
+
+        //
+        // Send the time all seconds
+        //
+        private async Task SendTime(WebSocket webSocket)
+        {
+            while (true)
+            {
+                var message = "Hello, my time is: " + DateTime.Now.ToLocalTime();
+                var bytes = Encoding.UTF8.GetBytes(message);
+                var arraySegment = new ArraySegment<byte>(bytes, 0, bytes.Length);
+
+                if (webSocket.State == WebSocketState.Open)
+                {
+                    await webSocket.SendAsync(arraySegment, WebSocketMessageType.Text, true, CancellationToken.None);
+                }
+                else if (webSocket.State == WebSocketState.Closed || webSocket.State == WebSocketState.Aborted)
+                {
+                    break;
+                }
+                Thread.Sleep(1000);
+            }
+        }
+
+        //
+        // Echo incoming messages
+        //
+        private async Task Echo(HttpContext context, WebSocket webSocket)
+        {
+            var buffer = new byte[1024 * 4];
+
+            // get the first data block
+            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
+            while (!result.CloseStatus.HasValue)
+            {
+                // test
+                await SendText(webSocket, "Thanks, I got this message:");
+
+                // echo the message back to the client
+                await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
+
+                // get the next block
+                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
+            }
+            await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
+        }
+    }
+}
+#pragma warning restore CS1591 // Fehlendes XML-Kommentar für öffentlich sichtbaren Typ oder Element
+
+
diff --git a/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/Startup.cs b/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/Startup.cs
index d9d13074bbe7b0a5ba668b2275b377bff9d421d3..48be55250c2022d50514a393758b36234e0102d7 100644
--- a/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/Startup.cs
+++ b/server/worldanalysis/src/ETSI.ARF.OpenAPI.WorldAnalysis/Startup.cs
@@ -161,6 +161,15 @@ namespace ETSI.ARF.OpenAPI.WorldAnalysis
                 app.UseHsts();
             }
 
+            // ETSI-ARF Websocket implementation
+            var webSocketOptions = new WebSocketOptions()
+            {
+                KeepAliveInterval = TimeSpan.FromSeconds(120),
+            };
+            //webSocketOptions.AllowedOrigins.Add("https://etsi.hhi.fraunhofer.de");
+            //webSocketOptions.AllowedOrigins.Add("https://www.client.com");
+            app.UseWebSockets();
+
             app.UseHttpsRedirection();
             app.UseDefaultFiles();
             app.UseStaticFiles();