I'm using the following code to create a channel from a ChannelFactory instance. Everything is working as expected, but occasionally I'll get a 5-30 second hang on ((ICommunicationObject)channel).Close(). It doesn't happen every time Close() is called. It happens when the factory is warm (i.e. already started) and when the factory is cold (i.e. first start).
What could be causing this? I'm at a loss as to where I should start looking.
var channel = _channelFactory.CreateChannel();
try
{
((ICommunicationObject)channel).Open();
channel.UpdateEntities(serviceEndpoint, formEndpoint, departmentContextConfiguration);
if (((ICommunicationObject)channel).State != CommunicationState.Faulted)
((ICommunicationObject)channel).Close();
}
catch
{
((ICommunicationObject)channel).Abort();
throw;
}
The factory is created elsewhere using the following code:
_channelFactory = new ChannelFactory<ITCPVaultService>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(uri.Uri))
Related
I'm writing a Connect-Four game in C#, and now want to include the possibility to play games online using TCP. Each instance of the game exe should work as both a server, in order to listen to incoming game invitations, and a client, to send said invitations. Of course, only one at a time is important.
I have read and watched a few C# tutorials on this (namely Jeff Chastine's tutorial 22) and I understand the basics of network communication. After getting past a few permission-errors, fixed by executing as administrator, I am now running into two issues.
1) When I try connecting from a machine on the same network, I always get an error saying the desired server did not respond to the request. When I enter the debugger, the program is stuck at the .AcceptTcpClient call (as if no connection has been attempted). I understand that this is a blocking call, but the code should continue when a connection is attempted. I have not tried connecting two machines in different networks, as I have only one network available.
2) This one is a rather minor issue regarding threading: even though I call listenerThread.Abort() when I close the application, the thread does not stop. I do not have too tight a grip on threads in C#, so I assume this problem is a rather easy fix.
Initialisation of listener and listenerThread
listenerThread = new Thread(ListenForInvites);
listener = new TcpListener(Dns.Resolve("localhost").AddressList[0], setting.port);
client = new TcpClient();
The method for listening to incoming connections
private void ListenForInvites()
{
try
{
listener.Start();
TcpClient enemyClient = listener.AcceptTcpClient(); // the call where it gets stuck even if someone connects
onlineSr = new StreamReader(enemyClient.GetStream());
onlineSw = new StreamWriter(enemyClient.GetStream());
onlineSw.WriteLine($"ACCEPT {player.name} {player.color.R} {player.color.G} {player.color.B}"); // I am using my own protocol, not HTTP (no clue if this is a horrible idea)
HandleConnection().Wait();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error");
}
}
The method for attempting the connection
public void SendInvite(string ip)
{
try
{
string[] ipSplit = ip.Split(':');
client.Connect(ipSplit[0], Convert.ToInt16(ipSplit[1]));
onlineSr = new StreamReader(client.GetStream());
onlineSw = new StreamWriter(client.GetStream());
onlineSw.WriteLine($"INVITE {player.name} {player.color.R} {player.color.G} {player.color.B}"); // player is an instance variable
onlineSw.Flush();
HandleConnection().Wait();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Fehler");
}
}
What am I doing wrong? Any help is appreciated.
I have a process that might have multiple instances running at anytime. Each instance should only run for several seconds at most. A process might have to pass data to an earlier started instance, or receive data from a latter started instance using named pipes. Each instance is aware of each other, but doesn't know for sure if it will attempt to pass or receive data. The process has a pipe server and client that each runs on its own thread. Since the process doesn't know before hand if the other process needs to send or receive data, I need the ability to attempt a connection but to time out and close the pipe if it hasn't connected in a few seconds. I'm using the asynch NamedPipeServer.BeginWaitForConnection() method. But I'm not sure if i'm using it correctly.
The process starts with Main() creating a thread with the
receiveServer() method.
receiveServer() starts a NamedPipeServer in a using block and starts the BeginWaitForConnection() method.
the AsychWaitHandle(3000) is used in the if condition so that if it successfully connects the readMessage(namedPipeServer) and a timeout timer is started. If the AsychWaitHandle(3000) expires then control goes to the else block where NamedPipeServer.Close() method is called.
The holdtimer runs as a safeguard while readMessage() method is running in case the pipeserver connects, and waits for data that never comes. When holdtimer expires it calls and event handler that calls the pipe server's close() method.
Being new to some of this, my main questions and concerns with my code are the fact that namedPipeServer.EndWaitForConnection(asynchResult) is only called int the event that the connection succeeds. According to the documentation EndWait must be called exacly once for each BeginWait. Testing the application, if no connection is made in 3 seconds the logic just falls through to the else block and then the pipe is closed, sometimes twice with out throwing any exception.
I'm also concerned about the way that I use the namedpipeserver.close() method in the timeout event when there is a hangup. That can call an exception readMessage() because the while loop tests while (!namedPipeServer.IsMessageComplete) which might be tested on a closed pipe.
I apologize for the lack of brevity, but I thought it would be a clearer question if I included all the relevant parts of the code.
Thanks in advance for the help.
public static void readMessage(NamedPipeServerStream namedPipeServer)
{
//While block continues while the Read() method has not complete,
// but once the Read() begins even if no data is available it blocks
//and the while block continues. Which is the reason for the
//timeout.
{
//Read from pipe to a global string variable
namedPipeServer.Read(messageBuffer, 0, messageBuffer.Length);
}
while (!namedPipeServer.IsMessageComplete);
}
public static void receiveServer()
{
try
{
using (NamedPipeServerStream namedPipeServer = new NamedPipeServerStream("test-pipe", PipeDirection.InOut,
1, PipeTransmissionMode.Message, PipeOptions.Asynchronous))
{
var asynchResult = namedPipeServer.BeginWaitForConnection(null, null);
//Adds a delegate to a timer that explicitly closes the pipe server on timeout
holdtimer.Elapsed += new ElapsedEventHandler((sender, e) => clockExpired(sender, e, namedPipeServer));
holdtimer.AutoReset = true;
//If connection succeeds within 3 seconds
//then control goes to the "if block" where
//the read method is called. And the hold timer
//is started. If the connection doesn't succeed in 3
//seconds then the named pipe server Close() method is called.
if (asynchResult.AsyncWaitHandle.WaitOne(3000))
{
//
namedPipeServer.EndWaitForConnection(asynchResult);
//start timer before calling method
holdtimer.Start();
//Pass namedAPipeServer to readMessage
readMessage(namedPipeServer);
//stop timer after method completes
holdtimer.Stop();
}
else
{
Console.WriteLine("didn't get anything ----------");
}
//Explicately close the PipeServer.
namedPipeServer.Close();
}
}
catch (Exception ex)
{
//This is just for testing.
MessageBox.Show("Exception in receiveMessage :" + ex.Message);
}
}
static void Main(string[] args)
{
//assign clockExpired() delgate to holdtimer
Thread receiverThread = new Thread(receiveServer);
receiverThread.Start();
}
I'm having hard time with this one.
So in my asp.net application there is such a method:
public CopyResponse thirdStage(CopyRequest request)
{
CopyCCResponse response = new CopyCCResponse();
Task.Run(() =>
{
performCopying(request);
});
return response;
}
private void performCopying(CopyCCRequest request)
{
using (Repository = new myDbContext())
{
// do some initial action
try
{
// in general it looks like below
foreach(var children in father)
{
var newChildren = chldren.Copy();
Repository.Childrens.Add(newChildren);
foreach (var grandchldren in children.grandchildrens)
{
var newGrandchildren = grandchldren.Copy();
newGrandchildren.Parent = newChildren;
Repository.Grandchildrens.Add(newGrandchildren);
}
Repository.SaveChanges();
}
}
catch (Exception ex)
{
// log that action failed
throw ex;
}
}
}
This method and all other (there are some similar) works as designed on my local computer without any problems.
Unfortunately, on another environment those methods fail:
Copying smaller parts of data works fine. But when there is over 3000 objects to operate on, method fails.
Main application is responding correctly nevertheless.
Most of the operation is done well (most data is copied and saved in database)
Application doesn't enter catch block. Instructions for failed copying are not executed. Exception isn't caught by the error handler (BTW, I know by default the app can't catch exceptions from independent task, I wrote my handler so it will manage to do so).
IIS worker process seems to take over 300MB and 0% of processor power after copying stopped. More than half of RAM on server is still free.
I looked into windows event log, but haven't found anything.
Do you have any suggestions how I can handle this issue?
You can't do reliable "Fire and forget" tasks from inside IIS, if the site is not being served the application pool will get its AppDomain shut down after a while.
Two options to use are:
HostingEnvironment.QueueBackgroundWorkItem to tell IIS you are doing background work. This will let the server know of the work and it will delay the shutdown as long as it can (default up to 90 seconds max) before it kills your process.
public CopyResponse thirdStage(CopyRequest request)
{
CopyCCResponse response = new CopyCCResponse();
HostingEnvironment.QueueBackgroundWorkItem(() =>
{
performCopying(request);
});
return response;
}
Another option is to use a 3rd party library that is designed for doing background work in IIS like Hangfire.io, this will run a service inside of IIS that does the work and attempts to keep the instance alive till the work is done. You can also configure Hangfire to run as a separate process so you don't need to rely on the lifetime of the IIS instance.
public CopyResponse thirdStage(CopyRequest request)
{
CopyCCResponse response = new CopyCCResponse();
BackgroundJob.Enqueue(() =>
{
performCopying(request);
});
return response;
}
Note, using hangfire with a seperate process may require you to do a little redesign of performCopying(CopyCCRequest request) to support being run from a separate process, using it from inside the IIS instance should not require any changes.
I have an SOA application that uses a duplex WCF service hosted within a Windows Service. The client itself is a WPF application.
I'm seeing unusual behaviour on closing and restarting the client application. If I start a new instance after closing one, nothing visibly appears to happen. However, checking task manager shows the new instance is running as a background process. If I try to start another new instance of the client application, it will display the error screen I've written - stating an error with the service. Investigation has shown that the client cannot create a new instance of the service callback channel because another application has already registered the URL. This is a System.ServiceModel.AddressAlreadyInUseException.
If I then end the background client task in task manager, my client displaying the error message is then able to connect to the service and run as normal. I have also noticed that if I close the background task before starting a new instance, the new instance will also not appear.
My concern here is that this is not useable and feels like a real hassle for users. What could be going wrong? It seems as if something is not cleaning up unmanaged resource but I've used ANTS and can't identify it. The client is created as:
IServiceCallback callback = new Callback();
_context = new InstanceContext(callback);
_channelFactory = new DuplexChannelFactory<IMyService>(_context, binding, endpoint);
_proxy =
_channelFactory.CreateChannel();
((ICommunicationObject)_proxy).Open(TimeSpan.FromSeconds(5));
The Service's constructor uses the following code:
_callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
var commObject = _callback as ICommunicationObject;
if (commObject != null)
{
commObject.Faulted += ChannelFaulted;
commObject.Closing += ChannelClosing;
commObject.Closed += ChannelClosed;
}
OperationContext.Current.Channel.Faulted += ChannelFaulted;
OperationContext.Current.Channel.Closed += ChannelFaulted;
Before closing, the client calls the service's Disconnect method, which does:
var commObject = _callback as ICommunicationObject;
if (commObject != null)
{
commObject.Faulted -= ChannelFaulted;
commObject.Closing -= ChannelClosing;
commObject.Closed -= ChannelClosed;
}
OperationContext.Current.Channel.Faulted -= ChannelFaulted;
OperationContext.Current.Channel.Closed -= ChannelFaulted;
Finally, the client closes the channels like this:
foreach (var incomingChannel in _context.IncomingChannels.ToArray())
{
incomingChannel.Close();
}
try
{
var proxy = _proxy as IChannel;
if (proxy != null)
{
proxy.Close();
}
}
catch (Exception)
{
_channelFactory.Abort();
}
Why am I seeing this unusual behaviour? Is there something I'm missing to close the channel or something I'm doing wrong to create it? Or is it likely that there must be an issue elsewhere in my code that keeps the channel or session alive?
**UPDATE: ** I have been trying a few things and found out that if I start a client instance, close it, then leave it for an hour, I can start another instance with no issue. I've also discovered that if I restart the Windows Service after creating and closing an instance of the client application then I'm also able to create another in those circumstances.
**UPDATE 2: ** Stepping through, I can see that the incomingChannel.Close() does not complete and does not throw an error. I've removed that section and also find proxy.Close() does not complete and does not throw an exception. I've tried using the overloads and added a timeout, but no timeout exception is being thrown. The Service's Dispose() method is not hit at all.
Try closing your channel factory too.
proxy.ChannelFactory.Close();
proxy.Close();
I have a piece of code that calls a WCF service that is hosted on a server.
The code keeps looping around and around calling this method over and over again. (It's asking for a 'status', so it's not doing any work at all).
That's fine except that after a short period of time I get an error:
This request operation sent to net.tcp://serverName:9001/service1 did not receive a reply within the configured timeout (00:00:09.9843754)
And suddenly i cannot get to the server at all EVER. I increased the timeout to 1min but still the same problem. Note that the program that hosts the service is doing nothing else, just offering it's 'status'. So it's not an issue with the WCF service app being busy.
I think it's a problem with the code calling the service because when i re-start the app it can connect to the service just fine ... until after another short time i get the timeout error again. For this reason i don't thnk it's a network error either, as when I restart the app it's ok for a period of time.
Here is the code i use to call the service. Do i need to dispose of the ChannelFactory after each call to clean it up or what am i doing worng?
NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message);
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointAddress endPoint = new EndpointAddress(new Uri(clientPath));
ChannelFactory<IClient> channel = new ChannelFactory<IClient>(binding, endPoint);
channel.Faulted += new EventHandler(channel_Faulted);
IClient client = channel.CreateChannel();
((IContextChannel)client).OperationTimeout = new TimeSpan(0, 0, 10);
ClientStatus clientStatus = client.GetStatus();
You do have to close client connections after you finish calling GetStatus. The best way to do this is to use a using block. But you can also do something like this after your call client.GetStatus()
ClientStatus clientStatus = client.GetStatus();
try
{
if (client.State != System.ServiceModel.CommunicationState.Faulted)
{
client.Close();
}
}
catch (Exception ex)
{
client.Abort();
}