I'm trying to maintain a list of WebSockets for a server which only needs to send messages to the client and not receive any replies. When the WebSocket is created initially all I want to do is just add the socket reference to a list for later use.
...
static Dictionary<int,WebSocket> wsDict = new Dictionary<int,WebSocket>();
...
private Task ProcessWS(AspNetWebSocketContext context)
{
wsDict[id] = (context.WebSocket);
...
}
(Finishes running the method and returns)
The issue I'm having is that I believe GC is disposing of the WebSocket, so when I try to use it at a later time I receive 'System.ObjectDisposedException'. Is there any way of permanently stopping GC from disposing of the socket?
Edit:
Sorry for not being clear originally, the whole class which inherits ApiController is (as the name suggests) is a control. A client initiates the WebSocket via a GET request and it calls the method above where it tries to store the socket into a dictionary (mapped to a int). The dictionary itself is Static.
It saves it into the Dict fine and in the debugger everything looks great. Its just literally disposing it after ProccessWS is complete and I can't seem to find a way to stop it. If I add a loop/sleep timer to the bottom of the ProcessWS it works fine - but thats not a viable solution.
The is a problem which originally I wasn't sure if it would be possible as each of the REST calls are stateless yet I need to maintain and overall list of all the connections which seems to contradict the original statement.
You have to await reads while the WS is still connected:
public class WSHandler : IHttpHandler
{
public bool IsReusable { get { return false; } }
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(ProcessWS);
}
}
private async Task ProcessWS(AspNetWebSocketContext context)
{
WebSocket socket = context.WebSocket;
...
while (socket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None)
.ConfigureAwait(false);
...
}
}
}
Related
I encountered connection issue while developing chat application on Android, it uses SignalR Core on the server side. Connection with server is established properly, client invokes for the first time server's method, server then invokes client's method successfully and in the end of execution of Android's listener connection drops. Each subsequent request to the server after the first one needs reconnection, becuase hubConnection.connectionState == HubConnectionState.DISCONNECTED. Reconnecting after each request is obviously bad. SignalR docs don't mention such case.
What am I doing wrong?
Kotlin code:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val hubConnection = HubConnectionBuilder.create("http://192.168.0.171:6000/chathub").build()
hubConnection.start()
hubConnection.on("MessageAdded", {msg ->
chat_view_text.text = msg.from+": "+msg.content
}, ChatMessage::class.java)
chat_view_send_button.setOnClickListener{
if (hubConnection.connectionState == HubConnectionState.CONNECTED){
hubConnection.send("SendMessage", Message("android", "hello world"));
}
}
}
.NET code:
public class ChatHub : Hub<IClientChatActions>, IServerChatActions
{
public override Task OnConnectedAsync()
{
Console.WriteLine("connected");
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
Console.WriteLine("disconnected");
return base.OnDisconnectedAsync(exception);
}
public async Task SendMessage(Message msg)
{
await Clients.All.MessageAdded(msg);
}
}
Android loses the connection while updating the UI this way ...
Try to update your UI in the main thread using Kotlin Coroutines.
Dispatchers.Main is the recommended dispatcher for performing UI-related events.
To do so, add to your build.gradle:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
In your activity.kt file, change it to something like:
private var job: Job = Job()
private val scope = CoroutineScope(job + Dispatchers.Main)
...
hubConnection.on("MessageAdded", {msg ->
scope.launch(Dispatchers.Main) {
chat_view_text.text = msg.from+": "+msg.content
}
}, ChatMessage::class.java)
I am using System.Net.Http.HttpClient to make postaysnc request. While request is in progress I unplug the network cable, receive HttpRequestException.
After some time plug the network cable again and make the postasync request, getting the HttpRequestException - sometimes i get the response server not available,sometimes timeout
Do i need to dispose the httpclient on exception and recreate when the request is made? How to make the query successful on network restore.
private async Task<string> GetServerResult()
{
try
{
var response = await myHttpClient.PostAsync("https://google.com", httpContent);
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex)
{
throw new HttpRequestException(ex.Message, ex.InnerException);
}
}
As per your requirement, you have to change implement some sort of implementation in that case. My proposed solution is use to a caching mechanism at WCF Client and update it periodically.
The very simple implementation could be as: You have a very simple singleton class of and a periodic Timer fetches the data from your mentioned endpoint. It stores the last cached data so that you have a copy of the data and when the hits are failed you can configure a fallback mechanism for that. For instance you have an implementation like
//You single Cache class
public sealed class ClientCache
{
#region Singleton implementation
private static ClientCache _clientCache = new ClientCache();
private ClientCache()
{
}
public static ClientCache Instance => _clientCache;
#endregion
//Timer for syncing the data from Server
private Timer _timer;
//This data is the cached one
public string data = string.Empty;
internal void StartProcess()
{
//Initializing the timer
_timer = new Timer(TimeSpan.FromMinutes(1).TotalMilliseconds); //This timespan is configurable
//Assigning it an elapsed time event
_timer.Elapsed += async (e, args) => await SyncServerData(e, args);
//Starting the timer
_timer.Start();
}
//In this method you will request your server and fetch the latest copy of the data
//In case of failure you can maintain the history of the last disconnected server
private async Task ProcessingMethod(object sender, ElapsedEventArgs e)
{
//First we will stop the timer so that any other hit don't come in the mean while
timer.Stop();
//Call your api here
//Once the hit is completed or failed
//On Success you will be updating the Data object
//data = result from your api call
//Finally start the time again as
timer.Start();
}
}
Now coming to Step two where to initialize the ClientCache Class. The best options are to initialize it in Global.asax class
protected void Application_Start()
{
//As
ClientCache.Instance.StartProcess();
}
Now whenever your frontend calls the method you don't need to go back to the server. Just send back the result from your cache as:
private Task<string> GetServerResult()
{
return Task.FromResult(ClientCache.Instance.data);
}
I have an API in which i do a lot of processing like sending a service bus queue message and receiving it, adding entries to table and then finally send an event to socket.io server. I want all this to be protected by concurrent executions. I am using Lock, but it doesnt seem to do the trick. Am i missing anything? below is my code
public class BroadcastController : ApiController
{
private readonly Object _Lock = new Object();
[HttpPost]
[ActionName("UploadRecording")]
public async Task<HttpResponseMessage> UploadRecording()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string path = Path.GetTempPath();
var provider = new MultipartFormDataStreamProvider(path);
// Read the form data and return an async task.
var response = await Request.Content.ReadAsMultipartAsync(provider);
// processing the mime content
lock (_Lock)
{
// sending and receiving service bus messages
// adding records to table
// sending an event to socket.io
return Request.CreateResponse(HttpStatusCode.OK, new ResponseMessage<PersistedAudioRecord> { SuccessCode = 1, Message = "Broadcast Uploaded", Data = updatedRecord });
} } }
Make the _Lock object static. Otherwise, you are using a different lock for each instance of the controller. Since the framework creates a new instance of the controller to process each request, each request is locking on a different _Lock object, thus providing no concurrency safety.
However, note that even a static lock object will only work if you have a single server. If you have multiple servers handling requests you'll need to manage concurrency by another means.
I have a streaming server that with a contract looking something like this:
[ServiceContract]
public interface IStreamingService
{
[OperationContract(Action = "StreamingMessageRequest", ReplyAction = "StreamingMessageReply")]
Message GetStreamingData(Message query);
}
Here's a rudimentary implementation with stuff (like error handling) removed to simplify things:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[ErrorBehavior(typeof(StreamingServiceErrorHandler))]
public class StreamingService : IStreamingService
{
public StreamingService()
{
}
public Message GetStreamingData(Message query)
{
var dataQuery = query.GetBody<DataQuery>();
// Hook up events to let us know if the client disconnects so that we can stop the query...
EventHandler closeAction = (sender, ea) =>
{
dataQuery.Stop();
};
OperationContext.Current.Channel.Faulted += closeAction;
OperationContext.Current.Channel.Closed += closeAction;
Message streamingMessage = Message.CreateMessage(
MessageVersion.Soap12WSAddressing10,
"QueryMessageReply",
new StreamingBodyWriter(QueryMethod(dataQuery));
return streamingMessage;
}
public IEnumerable<object> QueryMethod (DataQuery query)
{
// Returns a potentially infinite stream of objects in response to the query
}
}
This implementation uses a custom BodyWriter to stream results from the QueryMethod:
public class StreamingBodyWriter : BodyWriter
{
public StreamingBodyWriter(IEnumerable items)
: base(false) // False should be passed here to avoid buffering the message
{
Items = items;
}
internal IEnumerable Items { get; private set; }
private void SerializeObject(XmlDictionaryWriter writer, object item)
{
// Serialize the object to the stream
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
foreach (object item in Items)
{
SerializeObject(writer, item);
}
}
}
The client connects and starts reading the data stream. Something like this:
public IEnumerable<T> GetStreamingData<T>(Message queryMessage)
{
Message reply = _Server.GetStreamingData(queryMessage);
// Get a chunckable reader for the streaming reply
XmlReader reader = reply.GetReaderAtBodyContents();
// Read the stream of objects, deserializing each one as appropriate
while (!reader.EOF)
{
object item = DeserializeObject(reader);
if (item == null)
continue;
// Yield each item as it's deserialized, resulting in a [potentially] never-ending stream of objects
yield return (T)item;
}
}
This works very well and I get a stream of objects back to the client. Very nice. The problem is when the client disconnects mid-stream (either gracefully or ungracefully). In either case, the server doesn't get notified of this disconnect other than as a fault picked up by the service's error handler.
As you can see, I've tried hooking the Faulted and Closed channel events in the service method but they are not firing when the client disconnects.
I suspect that these events don't fire because with a streaming contract the service has already returned from the operation method (GetStreamingData). This method has returned a Message with a custom body-writer and it's this body-write that (lower in the service channel stack) is grabbing results from the calculation thread (via an IEnumerable) and streaming them in to the reply message. Since the operation method has returned then I'm guessing these channel events don't get fire.
The binding is a customized version of net.tcp binding (non-duplex) with only two binding elements: BinaryMessageEncodingBindingElement and TcpTransportBindingElement. No security or anything. Basically just raw net.tcp with binary messages.
The problem is that when a client disconnects, I want the server to stop the background calculation thread that is generating results and feeding them into the IEnumerable being read by the BodyWriter. The body writer has stopped (obviously), but the thread continues to live.
So where can I hook to discover if a client has disconnected mid-stream?
Update:
There are two main disconnection cases: Explicit disconnection, due either to the disposal of the client proxy or termination of the process at the client; Passive disconnection, usually due to a network failure (example: ISP drops the connection, or the network cable gets yanked).
In the first case, there is an explicit connection exception that get's received by the server when it tries to send new data down the stream. No problem.
The second scenario of a broken network pipe is more troublesome. Usually this condition is detected based on the Send timeout, but since this is a streaming interface the send timeout is cranked way up (I have it cranked to several days since it is conceivable that streaming data transfers could last that long). So when a client is disconnected due to a flaky network pipe, the service continues to send data down a connection that does really exist any more.
At this point I don't know of a good way to resolve the second option. Suggestions?
The Faulted event is really the best thing for handling these types of scenarios, but it will only fire if reliableSession is enabled. It is enabled by default in the standard netTcpBinding, but won't be enabled in this case because you are using a custom stripped down version of the binding. Try adding this to your custom binding :)
I have a simple class that handles the connection being made between a client and server.
To let more than one user communicate with the server at one time each new Client connection is made on a separate thread.
In this class I create two streams that act as the inbound and outbound streams for the client. I create the fields first and then initialise the object in a separate method, simply because the object is used in several other places.
I've come to the point where I want to refactor the code to make it more robust, my first port of call was memory management. I've come to love the using() statement but noticed that I can't really see a way to do implement it due to the way the code is structured.
This means I have a fairly annoying method that is just used for closing the underlying connections and nothing more.
Furthermore, I came to implement exception handling and was curious whether the notion of wrapping the entire code in a method with a try{} statement and then having sequential catch() blocks with the applicable exception types was the best idea.
I hope I explained myself correctly, I'll post a snippet for you to look at.
Thanks!
//Fields
TcpClient tcpClient;
//The thread that will send information to the client
private Thread thrSender;
private StreamReader srReceiver;
private StreamWriter swSender;
private string currentUser;
private string strResponse;
//The constructor of the class takes in a TCP connection
public Connection(TcpClient tcpCon)
{
tcpClient = tcpCon;
//The thread that accepts the client and waits messages
thrSender = new Thread(AcceptClient);
//The thread calls the AcceptClient method
thrSender.Start();
}
private void CloseConnection()
{
//Close the currently open objects
tcpClient.Close();
srReceiver.Close();
swSender.Close();
}
//Occurs when a new client is accepted
private void AcceptClient()
{
srReceiver = new StreamReader(tcpClient.GetStream());
swSender = new StreamWriter(tcpClient.GetStream());
//Read account information from the client
currentUser = srReceiver.ReadLine();
//Examine response from client
if (currentUser != "")
{
//Store the user name in the hash table
if (ChatServer.htUsers.Contains(currentUser) == true)
{
//0 means not connected - Writes error to Client and Server log
swSender.WriteLine("0|This username already exists.");
swSender.Flush();
CloseConnection();
return;
}
//More if/else if/else statements
//...
}
}
You can dispose of the two streams fairly easily within the AcceptClient method by making them local variables since they aren't referenced elsewhere something like this:
private void AcceptClient()
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
The tcpClient is more tricky because it is being created on one thread and cleaned up on another. Unless you can change that then perhaps the best option is going to be to implement the cleanup within a try/finally.
private void AcceptClient()
{
try
{
using (StreamReader srReceiver = new StreamReader(tcpClient.GetStream()))
{
using (StreamWriter swSender = new StreamWriter(tcpClient.GetStream()))
{
// ...
}
}
}
finally
{
tcpClient.Dispose();
}
}
The finally clause will get called whether or not the try clause throws an exception.