c# TLS client without client certificate - c#

I'm trying to create a TLS client without the need for TLS client certificate.
This works with client certificate:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
private static readonly string ServerCertificateName = "MyServer";
private static readonly string ClientCertificateFile = "client.pfx";
private static readonly string ClientCertificatePassword = null;
static void Main(string[] args) {
try {
var clientCertificate = new X509Certificate2(ClientCertificateFile, ClientCertificatePassword);
var clientCertificateCollection = new X509CertificateCollection(new X509Certificate[] { clientCertificate });
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false, App_CertificateValidation)) {
Console.WriteLine("Device connected.");
sslStream.AuthenticateAsClient(ServerCertificateName, clientCertificateCollection, SslProtocols.Tls12, false);
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
sslStream.Write(outputBuffer);
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
private static bool App_CertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; } //we don't have a proper certificate tree
Console.WriteLine("*** SSL Error: " + sslPolicyErrors.ToString());
return false;
}
}
}
Trying to remove the need for TLS client certificate is as follows:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
static void Main(string[] args) {
try {
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false)) {
Console.WriteLine("Device connected.");
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
try {
sslStream.Write(outputBuffer);
} catch (Exception x) {
var baseException = x.GetBaseException();
Console.WriteLine(baseException);
}
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
}
}
But this outputs:
Device connected.
System.InvalidOperationException: This operation is only allowed using a successfully authenticated context.
at Mono.Net.Security.MobileAuthenticatedStream.CheckThrow (System.Boolean authSuccessCheck, System.Boolean shutdownCheck) [0x0001e] in <cbad0c8bbe7b432eb83038c06be00093>:0
at Mono.Net.Security.MobileAuthenticatedStream+<StartOperation>d__58.MoveNext () [0x00011] in <cbad0c8bbe7b432eb83038c06be00093>:0
***** AggregateException
***** One or more errors occurred.!

you need to change your code if use tls you need to authenticate first.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace SslClient {
class App {
private static readonly string ServerIpAddress = "127.0.0.1";
private static readonly int ServerPort = 3000;
static void Main(string[] args) {
try {
using (var client = new TcpClient(ServerIpAddress, ServerPort))
using (var sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(App_CertificateValidation)) {
sslStream.AuthenticateAsClient(ServerIpAddress);
Console.WriteLine("Device connected.");
var outputMessage = "Hello";
var outputBuffer = Encoding.UTF8.GetBytes(outputMessage);
try {
sslStream.Write(outputBuffer);
} catch (Exception x) {
var baseException = x.GetBaseException();
Console.WriteLine(baseException);
}
var inputBuffer = new byte[4096];
var inputBytes = 0;
while (inputBytes == 0) {
inputBytes = sslStream.Read(inputBuffer, 0, inputBuffer.Length);
}
var inputMessage = Encoding.UTF8.GetString(inputBuffer, 0, inputBytes);
Console.WriteLine(inputMessage);
}
} catch (Exception ex) {
Console.WriteLine("***** {0}\n***** {1}!", ex.GetType().Name, ex.Message);
}
}
private static bool App_CertificateValidation(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; } //we don't have a proper certificate tree
Console.WriteLine("*** SSL Error: " + sslPolicyErrors.ToString());
return false;
}
}
}

Related

How can I set listener for clientwebsocket in c#?

ClientWebSocket socket = new ClientWebSocket();
socket.ConnectAsync(new Uri(socketURL), CancellationToken.None);
I have created ClientWebSocket using given code above in c#.
Now I want to listen to the data received through this socket.
How can I set listener for that?
Use await Task.WhenAll(Receive(socket ), Send(socket )); and define the followings:
static async Task Send(ClientWebSocket webSocket);
static async Task Receive(ClientWebSocket webSocket);
Example from github:paulbatum/WebSocket-Samples
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Client
{
private static object consoleLock = new object();
private const int sendChunkSize = 256;
private const int receiveChunkSize = 64;
private const bool verbose = true;
private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(1000);
static void Main(string[] args)
{
Thread.Sleep(1000);
Connect("ws://localhost/wsDemo").Wait();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static async Task Connect(string uri)
{
ClientWebSocket webSocket = null;
try
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);
await Task.WhenAll(Receive(webSocket), Send(webSocket));
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex);
}
finally
{
if (webSocket != null)
webSocket.Dispose();
Console.WriteLine();
lock (consoleLock)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("WebSocket closed.");
Console.ResetColor();
}
}
}
private static async Task Send(ClientWebSocket webSocket)
{
var random = new Random();
byte[] buffer = new byte[sendChunkSize];
while (webSocket.State == WebSocketState.Open)
{
random.NextBytes(buffer);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Binary, false, CancellationToken.None);
LogStatus(false, buffer, buffer.Length);
await Task.Delay(delay);
}
}
private static async Task Receive(ClientWebSocket webSocket)
{
byte[] buffer = new byte[receiveChunkSize];
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
else
{
LogStatus(true, buffer, result.Count);
}
}
}
private static void LogStatus(bool receiving, byte[] buffer, int length)
{
lock (consoleLock)
{
Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;
Console.WriteLine("{0} {1} bytes... ", receiving ? "Received" : "Sent", length);
if (verbose)
Console.WriteLine(BitConverter.ToString(buffer, 0, length));
Console.ResetColor();
}
}
}
}

HTTP status code 500 when querying an API from a C# program, except the API works

I need to use another company's API to query data using POST requests.
The API works (= I receive all the data with no errors) when I query it from the swagger website using the UI, but when I do it from my C# program I get a 500 Internal Server Error.
Where should I be looking for the problem ? Is there a way to get a more detailed error message ?
Edit (added code) :
using System;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.Interception;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Text;
namespace credex_distribution_offers_to_interfaces
{
class Program
{
private const string jsonMediaType = "application/json";
static void Main()
{
FetchJSONAndInsertToDB();
}
private static bool FetchJSONAndInsertToDB()
{
var baseServiceUrl = new Uri("a valid url");
Root rootObject;
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(jsonMediaType));
try
{
string token = FetchToken(httpClient, baseServiceUrl);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(token);
}
catch (Exception e)
{
return false;
}
try
{
rootObject = FetchDistributionLookupOffers(httpClient, baseServiceUrl, 29612, 29613, 29614, 29617, 29621);
}
catch (Exception e)
{
return false;
}
}
// database related stuff...
// ...
return true;
}
[DataContract]
public class MortgageForDistributionLookupInputDto
{
public int[] OfferNumbers { get; set; }
}
private static Root FetchDistributionLookupOffers(HttpClient aHttpClient, Uri aBaseServiceUrl, params int[] aOfferNumbers)
{
var input = new MortgageForDistributionLookupInputDto()
{
OfferNumbers = aOfferNumbers
};
var lookup = aHttpClient.PostAsync(new Uri(aBaseServiceUrl, "v1/MortgageDetails/InvestorLookupOffers"), PayloadFor(input)).Result;
if (lookup.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Fetching investor lookup offers failed with HTTP status code '" + lookup.StatusCode + "' : " + lookup.ReasonPhrase + "}");
}
var obj = ValueFor<Root>(lookup.Content);
return obj;
}
private static HttpContent PayloadFor<T>(T aObject)
{
return new StringContent(aObject.SerializeJson(), Encoding.UTF8, jsonMediaType);
}
private static T ValueFor<T>(HttpContent aHttpContent)
{
//var content = aHttpContent.ReadAsStringAsync();
return aHttpContent.ReadAsStreamAsync().Result.DeSerializeJson<T>();
}
private static string FetchToken(HttpClient aHttpClient, Uri aBaseServiceUrl)
{
var login = new LoginRequest()
{
UserName = "some user name",
Password = "some password"
};
var authResult = aHttpClient.PostAsync(new Uri(aBaseServiceUrl, "api/Login"), PayloadFor(login)).Result;
if (authResult.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Fetching authentication token failed. Reason : " + authResult.StatusCode + " -> " + authResult.ReasonPhrase);
}
return authResult.Content.ReadAsStringAsync().Result.Trim('"');
}
}
}

Memory increase gradually after every HTTPClient Call in Xamarin iOS. GC collection is not effective

I have monitor the Application Allocation using Instrument. I have noticed that Memory is gradually increase. I just need release the memory which is used by HTTPClient.
I have tried using Dispose(),used using statement,used GC.collect; but those are not reducing the memory. It looks like not effective.
Below is code used in the program.
namespace MemoryManagementStudy
{
public partial class ViewController : UIViewController
{
protected ViewController(IntPtr handle) : base(handle)
{
}
NetworkStaticCall networkStaticCall;
public override void ViewDidLoad()
{
//lblStatusUpdate.Text = "Success Count: 0, Fail Count: 0 -- Last Update: " + DateTime.Now;
base.ViewDidLoad();
//string status = "";
networkStaticCall = new NetworkStaticCall();
networkStaticCall.init();
Timer timer = new Timer(1000 * 30);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) => {
Console.WriteLine("Memory " + GC.GetTotalMemory(true));
await networkStaticCall.MakeSMWebService();
Console.WriteLine("Memory " + GC.GetTotalMemory(true));
};
timer.Start();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
}
class NetworkStaticCall
{
//int successCount = 0;
//int failCount = 0;
private static HttpClient httpClient;
private static HttpResponseMessage httpResponseMessage;
private StringContent dataContent;
private string xmlString;
private static HttpClientHandler httpClientHandler;
private NSUrlSessionHandler nsUrlSessionHandler;
public void init()
{
httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new NetworkCredential("userName", "Password"); ;
httpClient = new HttpClient(httpClientHandler);
httpClient.DefaultRequestHeaders.Accept.Clear();
dataContent = new StringContent("Xml String Content",
Encoding.UTF8, "text/xml");
}
public async Task<string> MakeSMWebService()
{
Console.WriteLine("Call Processing");
try
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpResponseMessage = await httpClient.PostAsync("url", dataContent);
Console.WriteLine("Call success");
xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
//successCount++;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return "";
}
}
}
We have tried https://stackoverflow.com/a/27830926 but it is not working.
I have tried WebRequest but it still increasing
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using UIKit;
namespace MemoryManagementStudy
{
public partial class ViewController : UIViewController
{
protected ViewController(IntPtr handle) : base(handle)
{
}
CustomWebRequest customWebRequest;
public override void ViewDidLoad()
{
customWebRequest = new CustomWebRequest();
lblStatusUpdate.Text = "Success Count: 0, Fail Count: 0 -- Last Update: " + DateTime.Now;
base.ViewDidLoad();
string status = "";
//networkStaticCall = new NetworkStaticCall();
//networkStaticCall.init();
//
Timer timer = new Timer(1000 * 60);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) => {
status = await customWebRequest.Post();
InvokeOnMainThread(()=>{
lblStatusUpdate.Text =status + " -- Last Update: " + DateTime.Now;
});
GC.Collect();
};
timer.Start();
}
}
class CustomWebRequest{
string finalUrl = "URL";
//StreamReader reader;
int successCount = 0;
int failCount = 0;
async public Task<string> Post()
{
var request = WebRequest.Create(finalUrl);
request.Method = "GET";
request.Timeout = 10000;
try
{
using (var response = await request.GetResponseAsync())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine(reader.ReadToEnd());
}
}
successCount++;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
failCount++;
}
finally
{
if(request != null){
request.Abort();
request = null;
}
}
return string.Format("Success Count: {0}, Fail Count: {1}", successCount, failCount);
}
}
}

TCP/IP multiple clients connection in C#

I wrote client and server apps, there are those codes:
Client:
using System.Net.Sockets;
using System.Net;
using System.IO;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Program
{
private static TcpClient client = new TcpClient();
private static StreamReader reader;
private static StreamWriter writer;
private static bool refresh;
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Client";
do //try to connect
{
Console.WriteLine("Connecting to server...");
try
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8080);
}
catch (SocketException) { }
Thread.Sleep(10);
} while (!client.Connected);
// \/ CONNECTED \/
Console.WriteLine("Connected.");
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
var sendTask = Task.Run(() => SendMessage()); //task for sending messages
var recieveTask = Task.Run(() => RecieveMessage()); //task for recieving messages
var updateConvTask = Task.Run(() => UpdateConversation()); //task for update console window
Task.WaitAll(sendTask, recieveTask); //wait for end of all tasks
}
private static void SendMessage()
{
string msgToSend = string.Empty;
do
{
Console.WriteLine("Enter a message to send to the server");
msgToSend = Console.ReadLine();
writer.WriteLine(msgToSend);
writer.Flush();
} while (!msgToSend.Equals("Exit"));
EndConnection();
}
private static void RecieveMessage()
{
try
{
while (client.Connected)
{
//Console.Clear();
string msg = reader.ReadLine();
if(msg != string.Empty)
{
if (msg == "%C") //special message from server, clear messages if recieve it
{
messages.Clear();
}
else
{
messages.Add(msg);
refresh = true; //refresh console window
}
}
//Console.Clear();
//Console.WriteLine(msgFromServer);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void UpdateConversation()
{
//string conversationTmp = string.Empty;
try
{
while (true)
{
if (refresh) //only if refresh
{
refresh = false;
Console.Clear();
messages.ForEach(msg => Console.WriteLine(msg)); //write all messages
Console.WriteLine();
}
}
}
catch (Exception) { }
}
private static void EndConnection()
{
reader.Close();
writer.Close();
client.Close();
}
}
}
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Server
{
class Program
{
private static List<Client> clients = new List<Client>();
private static TcpListener listener = null;
private static StreamReader reader = null;
private static StreamWriter writer = null;
private static List<Task> clientTasks = new List<Task>();
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Server";
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
listener.Start();
Console.WriteLine("Server started...");
var connectTask = Task.Run(() => ConnectClients());
//var listenTask = Task.Run(() => ListenClients());
Task.WaitAll(connectTask);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
if (listener != null)
{
listener.Stop();
}
}
}
private static void ConnectClients()
{
Console.WriteLine("Waiting for incoming client connections...");
while (true)
{
if (listener.Pending()) //if someone want to connect
{
clients.Add(new Client(listener.AcceptTcpClient(), "Client: " + (clients.Count + 1)));
Console.WriteLine(clients[clients.Count - 1].clientName + " connected to server.");
clientTasks.Add(Task.Run(() => HandleClient(clients[clients.Count - 1]))); //start new task for new client
}
}
}
private static void HandleClient(Client TCPClient)
{
string s = string.Empty;
writer = new StreamWriter(TCPClient.client.GetStream());
reader = new StreamReader(TCPClient.client.GetStream());
try
{
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null))
{
if(!TCPClient.client.Connected)
{
Console.WriteLine("Client disconnected.");
clients.Remove(TCPClient);
}
Console.WriteLine("From client: " + TCPClient.clientName + " -> " + s);
messages.Add(TCPClient.clientName + ": " + s); //save new message
//Console.WriteLine(s);
foreach (Client c in clients) //refresh all connected clients
{
c.writer.WriteLine("%C"); //clear client
foreach (string msg in messages)
{
c.writer.WriteLine(msg);
c.writer.Flush();
}
}
}
CloseServer();
}
catch (Exception e) { Console.WriteLine(e); }
}
private static void CloseServer()
{
reader.Close();
writer.Close();
clients.ForEach(tcpClient => tcpClient.client.Close());
}
}
}
Client class code:
class Client
{
public TcpClient client;
public StreamWriter writer; //write to client
public string clientName;
public Client(TcpClient client, string clientName)
{
this.client = client;
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
this.clientName = clientName;
}
}
Clients send messages to the server that store all of them and next send back the entire conversation to all clients.
Client class contains information about the connected client, a server has a list of Client instances.
For one client it works well, but when I have two clients, in begin it works too, but after a few messages one client send messages to them two, and another client can't send messages.
Please help, I'm new in TCP communication.
I think that you would synchronize Tasks: https://www.google.pl/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=synchronizing+tasks+c%23

WCF self-hosted WebSocket Service with Javascript client

I have this WCF self-hosted WebSocket service code:
Main:
//Create a URI to serve as the base address
Uri httpUrl = new Uri("http://192.168.1.95:8080/service");
//Create ServiceHost
ServiceHost host = new ServiceHost(typeof(WebSocketService), httpUrl);
//Add a service endpoint
host.AddServiceEndpoint(typeof(IWebSocket), new NetHttpBinding(), "");
//Enable metadata exchange
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
//Start the Service
host.Open();
Console.WriteLine("Service is host at " + DateTime.Now.ToString());
Console.WriteLine("Host is running... Press <Enter> key to stop");
Console.ReadLine();
Interface:
namespace IWebSocketHostTest
{
[ServiceContract]
interface IWebSocketCallBack
{
[OperationContract(IsOneWay = true)]
void Send(int num);
}
[ServiceContract(CallbackContract = typeof(IWebSocketCallBack))]
public interface IWebSocket
{
[OperationContract]
void StartSend();
}
}
Service:
namespace IWebSocketHostTest
{
class WebSocketService : IWebSocket
{
Timer timer = null;
List<IWebSocketCallBack> callbackClientList = null;
public WebSocketService()
{
callbackClientList = new List<IWebSocketCallBack>();
timer = new Timer(3000);
timer.Elapsed += new ElapsedEventHandler(sendNumber);
timer.Start();
}
public void StartSend()
{
sender.addClient(OperationContext.Current.GetCallbackChannel<IWebSocketCallBack>());
}
private void sendNumber(Object o, ElapsedEventArgs eea)
{
timer.Stop();
var random = new Random();
int randomNum = random.Next(100);
foreach (IWebSocketCallBack callback in callbackClientList)
{
callback.Send(randomNum);
}
timer.Interval = random.Next(1000, 10000);
timer.Start();
}
}
}
This works perfect if i add a reference of this service in another .NET application.
But, what i need is to consume this service from an HTML+Javascript application, and i´m realy lost in how to do that. I couldn´t find a good example or tutorial with a Javascript client consuming a self-hosted WCF WebSocket service.
All the Javascript WebSocket code that i could find seems to be very simple, but i couldn´t make it work.
Here is my short JavaScript client test:
var ws = new WebSocket("ws://192.168.1.95:8080/service");
ws.onopen = function () {
console.log("WEBSOCKET CONNECTED");
};
it returns "WebSocket Error: Incorrect HTTP response. Status code 400, Bad Request" testing it with Fiddler.
What am i missing? Could you please give me some doc links to get more information or a code example?
Thank you!
EDIT:
Now i´ve tried using the "Microsoft.ServiceModel.WebSocket" library to try to make it work.
But, first, i don´t know if it´s still maintained by Microsoft or if it is deprecated, because i couldn´t find any information at MSDN and there is few info at internet.
And second, the "Open()" method of the "WebSocketHost" class is not found, so i don´t know how to make the server run...
Here is my code, i´ve taken it from a question at the ASP.NET forum.
using System;
using Microsoft.ServiceModel.WebSockets;
namespace WebSocketTest
{
class Program
{
static void Main(string[] args)
{
var host = new WebSocketHost<EchoService>(new Uri("ws://localhost:8080/echo"));
host.AddWebSocketEndpoint();
host.Open();
Console.Read();
host.Close();
}
}
class EchoService : WebSocketService
{
public override void OnOpen()
{
base.OnOpen();
Console.WriteLine("WebSocket opened.");
}
public override void OnMessage(string message)
{
Console.WriteLine("Echoing to client:");
Console.WriteLine(message);
this.Send(message);
}
protected override void OnClose()
{
base.OnClose();
Console.WriteLine("WebSocket closed.");
}
protected override void OnError()
{
base.OnError();
Console.WriteLine("WebSocket error occured.");
}
}
}
But, like i said before, the "host.Open()" method is not found, so i don´t know if i´m missing some reference or what, because i couldn´t find info about the WebSocketHost class... Any help?
After spending a day with the same task I finally got working solution. Hope it will help someone in the future.
Client JS script:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>WebSocket Chat</title>
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.1.js"></script>
<script type="text/javascript">
var ws;
$().ready(function ()
{
$("#btnConnect").click(function ()
{
$("#spanStatus").text("connecting");
ws = new WebSocket("ws://localhost:8080/hello");
ws.onopen = function ()
{
$("#spanStatus").text("connected");
};
ws.onmessage = function (evt)
{
$("#spanStatus").text(evt.data);
};
ws.onerror = function (evt)
{
$("#spanStatus").text(evt.message);
};
ws.onclose = function ()
{
$("#spanStatus").text("disconnected");
};
});
$("#btnSend").click(function ()
{
if (ws.readyState == WebSocket.OPEN)
{
var res = ws.send($("#textInput").val());
}
else
{
$("#spanStatus").text("Connection is closed");
}
});
$("#btnDisconnect").click(function ()
{
ws.close();
});
});
</script>
</head>
<body>
<input type="button" value="Connect" id="btnConnect" />
<input type="button" value="Disconnect" id="btnDisconnect" /><br />
<input type="text" id="textInput" />
<input type="button" value="Send" id="btnSend" /><br />
<span id="spanStatus">(display)</span>
</body>
</html>
Self hosted server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
namespace WebSocketsServer
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/hello");
// Create the ServiceHost.
using(ServiceHost host = new ServiceHost(typeof(WebSocketsServer), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
CustomBinding binding = new CustomBinding();
binding.Elements.Add(new ByteStreamMessageEncodingBindingElement());
HttpTransportBindingElement transport = new HttpTransportBindingElement();
//transport.WebSocketSettings = new WebSocketTransportSettings();
transport.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always;
transport.WebSocketSettings.CreateNotificationOnConnection = true;
binding.Elements.Add(transport);
host.AddServiceEndpoint(typeof(IWebSocketsServer), binding, "");
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
}
}
[ServiceContract(CallbackContract = typeof(IProgressContext))]
public interface IWebSocketsServer
{
[OperationContract(IsOneWay = true, Action = "*")]
void SendMessageToServer(Message msg);
}
[ServiceContract]
interface IProgressContext
{
[OperationContract(IsOneWay = true, Action = "*")]
void ReportProgress(Message msg);
}
public class WebSocketsServer: IWebSocketsServer
{
public void SendMessageToServer(Message msg)
{
var callback = OperationContext.Current.GetCallbackChannel<IProgressContext>();
if(msg.IsEmpty || ((IChannel)callback).State != CommunicationState.Opened)
{
return;
}
byte[] body = msg.GetBody<byte[]>();
string msgTextFromClient = Encoding.UTF8.GetString(body);
string msgTextToClient = string.Format(
"Got message {0} at {1}",
msgTextFromClient,
DateTime.Now.ToLongTimeString());
callback.ReportProgress(CreateMessage(msgTextToClient));
}
private Message CreateMessage(string msgText)
{
Message msg = ByteStreamMessage.CreateMessage(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgText)));
msg.Properties["WebSocketMessageProperty"] =
new WebSocketMessageProperty
{
MessageType = WebSocketMessageType.Text
};
return msg;
}
}
}
UPDATE
As of .net 4.5 new way of writing server side have emerged. The benefits are cleaner code and possibility to support secure web sockets (WSS) over https.
public class WebSocketsServer
{
#region Fields
private static CancellationTokenSource m_cancellation;
private static HttpListener m_listener;
#endregion
#region Private Methods
private static async Task AcceptWebSocketClientsAsync(HttpListener server, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var hc = await server.GetContextAsync();
if (!hc.Request.IsWebSocketRequest)
{
hc.Response.StatusCode = 400;
hc.Response.Close();
return;
}
try
{
var ws = await hc.AcceptWebSocketAsync(null).ConfigureAwait(false);
if (ws != null)
{
Task.Run(() => HandleConnectionAsync(ws.WebSocket, token));
}
}
catch (Exception aex)
{
// Log error here
}
}
}
private static async Task HandleConnectionAsync(WebSocket ws, CancellationToken cancellation)
{
try
{
while (ws.State == WebSocketState.Open && !cancellation.IsCancellationRequested)
{
String messageString = await ReadString(ws).ConfigureAwait(false);
var strReply = "OK"; // Process messageString and get your reply here;
var buffer = Encoding.UTF8.GetBytes(strReply);
var segment = new ArraySegment<byte>(buffer);
await ws.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None).ConfigureAwait(false);
}
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Done", CancellationToken.None);
}
catch (Exception aex)
{
// Log error
try
{
await ws.CloseAsync(WebSocketCloseStatus.InternalServerError, "Done", CancellationToken.None).ConfigureAwait(false);
}
catch
{
// Do nothing
}
}
finally
{
ws.Dispose();
}
}
private static async Task<String> ReadString(WebSocket ws)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await ws.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
}
#endregion
#region Public Methods
public static void Start(string uri)
{
m_listener = new HttpListener();
m_listener.Prefixes.Add(uri);
m_listener.Start();
m_cancellation = new CancellationTokenSource();
Task.Run(() => AcceptWebSocketClientsAsync(m_listener, m_cancellation.Token));
}
public static void Stop()
{
if(m_listener != null && m_cancellation != null)
{
try
{
m_cancellation.Cancel();
m_listener.Stop();
m_listener = null;
m_cancellation = null;
}
catch
{
// Log error
}
}
}
#endregion
}

Categories