using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
// Unintelligle code. It's nonsense code, need to break all classes into their own method.
// This is gobbled up to demonstrate Websockets can work with MVC pattern also running an HTTP server
// Thus, this is combination of both an HTTP server along with Websocket running on same program
// NOT recommended design.
//
// For full resource, see WebSocketCore .NET in github
namespace WebSocketCore
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebSocketCore", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebSocketCore v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
//webSocketOptions.AllowedOrigins.Add("https://www.client.com");
//webSocketOptions.AllowedOrigins.Add("*");
app.UseWebSockets(webSocketOptions);
app.UseMiddleware<SocketWare>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
public class HomePage
{
public DateTime Date { get; set; }
public string Title { get; set; }
public string Version { get; set; }
}
public class ReqMessage
{
public string Name { get; set; }
public int Age { get; set; }
}
// swagger
// https://localhost:44327/swagger/index.html
[ApiController]
[Route("webapi/[controller]")]
public class HomeController : ControllerBase
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
var str = "RESTful WebApi WebSocket HTTP/HTTPS Json Service Online!";
var hp = new HomePage { Date = DateTime.Now, Title = str, Version = "1.01" };
Log.Information(str);
return Ok(hp);
}
[HttpPost]
[Route("GetJsonString")]
public IActionResult GetJsonString([FromBody] ReqMessage req)
{
try
{
if (req != null)
{
Log.Information(req.ToJsonString());
return Ok(req);
}
else
return BadRequest("BadRequest Error Message");
}
catch (Exception e)
{
return StatusCode(500, e.StackTrace);
}
}
[NonAction]
[Route("SynchronousCall")]
public IActionResult SynchronousCall()
{
return Ok("this is normal call");
}
[NonAction]
[Route("AsynchronousCall")]
// https://stackoverflow.com/questions/41953102/using-async-await-or-task-in-web-api-controller-net-core
public async Task<IActionResult> AsynchronousCall()
{
var result = await Task.Run(() => "this is async call");
return Ok(result);
}
}
public class ChatClient
{
private WebSocket webSocket;
public ChatClient(WebSocket webSocket)
{
this.webSocket = webSocket;
}
public async Task RunAsync()
{
var buffer = new byte[4086];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
while (!result.CloseStatus.HasValue)
{
var str = Encoding.Default.GetString(buffer, 0, result.Count);
Log.Information($"RECV: [{str}]");
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);
}
}
public class SocketWare
{
private RequestDelegate next;
public SocketWare(RequestDelegate _next)
{
this.next = _next;
}
public async Task Invoke(HttpContext context)
{
if (!context.WebSockets.IsWebSocketRequest)
await next(context);
else
{
if (context.Request.Path == "/ws")
{
using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
{
if (webSocket.State == WebSocketState.Open)
{
await RunEchoServerAsync(webSocket);
}
}
}
}
}
private async Task RunEchoServerAsync(WebSocket webSocket)
{
try
{
var client = new ChatClient(webSocket);
await client.RunAsync();
}
catch (Exception ex)
{
Log.Error(ex.Message);
}
}
}
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.File("Log/WebSocket_.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}