I'm new in WCF, just learning it so far. But I was wondering how to close a WCF client connection from the client side (if it is needed at all? I think so).
I have an interface called
[ServiceContract]
ICalculatorService { blabla... }
The question is on the client side.
So far, I used the following format:
EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
ICalculatorService calculatorProxy = ChannelFactory<ICalculatorService>.CreateChannel(new WSHttpBinding(), epAddress);
and now I can:
Result numeralResult = calculatorProxy.AddNumbers(4, 5);
and I got the result and I was happy.
Every single (for example) Button pressing caused the mentioned code to run once.
My question is: is the efficient?
Now I'm thinking of putting this into a separate class, for example:
class CalculatorProxy
{
static EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
public static ChannelFactory<ICalculatorService> GetCalculatorProxy()
{
}
public void Dispose() { ... }
}
... and use it like:
using (ICalculatorService calculatorClient = CalculatorProxy.GetCalculatorProxy())
{
calculatorClient.AddNumbers(4, 4);
}
which one would be more efficient?
UPDATE:
Thank you all for your answers.
I finally ended up with this class:
class CalculatorServiceClient : ClientBase<ICalculatorService>, IDisposable
{
static EndpointAddress epAddress = new EndpointAddress("http://localhost:8090/CalculatorService");
ICalculatorService myCalculatorProxy;
public CalculatorServiceClient()
: base(new WSHttpBinding(), epAddress)
{
myCalculatorProxy = ChannelFactory.CreateChannel();
}
public static CalculatorServiceClient GetNewInstance()
{
return new CalculatorServiceClient();
}
public Result AddNumbers(int aIn, int bIn)
{
return myCalculatorProxy.AddNumbers(aIn, bIn);
}
public void Dispose()
{
try
{
Close();
}
catch (CommunicationObjectFaultedException ex)
{
throw new DBCommunicationException("CalculatorServiceClient is in the Faulted state.", ex);
}
catch (Exception ex)
{
throw new DBCommunicationException("Communication is unsuccessful between the CalculatorServiceClient and the CalculatorService.", ex);
}
}
}
And use it in this way:
try
{
using (CalculatorServiceClient calculatorClient = CalculatorServiceClient.GetNewInstance())
{
Result aResult = calculatorClient.AddNUmbers(tbA.Text, tbB.Text);
}
}
catch (DBCommunicationException ex)
{
MessageBox.Show("Service is shut down.");
}
My question is: is this efficient?
You should just close the client when each operation you have done is completed and you don't need anymore to make other calls.
When your work is finished, just close the client using the Close method:
calculatorProxy.Close();
About the Close() method, the MSDN documentation states:
This method causes a CommunicationObject to gracefully transition from
any state, other than the Closed state, into the Closed state. The
Close method allows any unfinished work to be completed before
returning. For example, finish sending any buffered messages.
About your approach, I think the second one is fine and more efficient, because you're also implementing the Dispose pattern and release the used resources (this depends on the resources you're using). Just add the Close() method when the work is finished:
calculatorClient.AddNumbers(4, 4);
calculatorProxy.Close();
Remember also that there's no performance issue creating and closing continuously the WCF clients. This is just a normal habitude.
using (var client = new CalculatorServiceClient())
{
client.SomeMethod();
}
The CalculatorServiceClient object will be available once you add a Service Reference to your Calculator WebService to your client project.
you can call the close method of your proxy class.
like
calculatorProxy.Close();
Alternatively you call the abort method on your service proxy class in case of exception.
try
{
calculatorProxy.SomeMethod();
calculatorProxy.Close();
}
catch
{
calculatorProxy.Abort();
}
Refer to this link for further details
I think you would find it better to put all of that in a class. Establishing an instance of the class can construct the connection and close/dispose when the time comes. Until then, you have an open and active channel to make calls to.
Related
I have a web application that serves users through connections to other third party web services.
I am not sure about the safe/efficient way to create those web service clients in my application.
As of .NET 4.5, I can use client code generated through svcutil and cache channel factories per service by setting the static CacheSetting property.
Example from MSDN site:
class Program
{
static void Main(string[] args)
{
ClientBase<ITest>.CacheSettings = CacheSettings.AlwaysOn;
foreach (string msg in messages)
{
using (TestClient proxy = new TestClient (new BasicHttpBinding(), new EndpointAddress(address)))
{
// ...
proxy.Test(msg);
// ...
}
}
}
}
// Generated by SvcUtil.exe
public partial class TestClient : System.ServiceModel.ClientBase, ITest { }
As a result there is no need to custom implement that functionality as well mentioned in :
creating WCF ChannelFactory<T>
https://philmunro.wordpress.com/2012/02/15/creating-a-wcf-service-proxy-with-channelfactory/
Also MSDN states that we should not use the C# "using" statement to automatically clean up resources when using a typed client and handle it with try/catch.
Example from MSDN site:
try
{
...
double result = client.Add(value1, value2);
...
client.Close();
}
catch (TimeoutException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
catch (CommunicationException exception)
{
Console.WriteLine("Got {0}", exception.GetType());
client.Abort();
}
1) Is the above way of calling a service safe to follow? Do I miss something? Or it's better to handle factory creation manually?
2) Am I going to have any problems with faulty states (both factory/channel)?
3) I need to create a new client for each service call right?
using IPC over local TCP to communicate from Client to a Server thread. The connection itself doesn't seem to be throwing any errors, but every time I try to make one of the associated calls, I get this message:
System.Runtime.Remoting.RemotingException: Could not connect to an IPC Port: The System cannot Find the file specified
What I am attempting to figure out is WHY. Because this WAS working correctly, until I transitioned the projects in question (yes, both) from .NET 3.5 to .NET 4.0.
Listen Code
private void ThreadListen()
{
_listenerThread = new Thread(Listen) {Name = "Listener Thread", Priority = ThreadPriority.AboveNormal};
_listenerThread.Start();
}
private void Listen()
{
_listener = new Listener(this);
LifetimeServices.LeaseTime = TimeSpan.FromDays(365);
IDictionary props = new Hashtable();
props["port"] = 63726;
props["name"] = "AGENT";
TcpChannel channel = new TcpChannel(props, null, null);
ChannelServices.RegisterChannel(channel, false);
RemotingServices.Marshal(_listener, "Agent");
Logger.WriteLog(new LogMessage(MethodBase.GetCurrentMethod().Name, "Now Listening for commands..."));
LogEvent("Now Listening for commands...");
}
Selected Client Code
private void InitializeAgent()
{
try
{
_agentController =
(IAgent)RemotingServices.Connect(typeof(IAgent), IPC_URL);
//Note: IPC_URL was originally "ipc://AGENT/AGENT"
// It has been changed to read "tcp://localhost:63726/Agent"
SetAgentPid();
}
catch (Exception ex)
{
HandleError("Unable to initialize the connected agent.", 3850244, ex);
}
}
//This is the method that throws the error
public override void LoadTimer()
{
// first check to see if we have already set the agent process id and set it if not
if (_agentPid < 0)
{
SetAgentPid();
}
try
{
TryStart();
var tries = 0;
while (tries < RUNCHECK_TRYCOUNT)
{
try
{
_agentController.ReloadSettings();//<---Error occurs here
return;
} catch (RemotingException)
{
Thread.Sleep(2000);
tries++;
if (tries == RUNCHECK_TRYCOUNT)
throw;
}
}
}
catch (Exception ex)
{
HandleError("Unable to reload the timer for the connected agent.", 3850243, ex);
}
}
If you need to see something I haven't shown, please ask, I'm pretty much flying blind here.
Edit: I think the issue is the IPC_URL String. It is currently set to "ipc://AGENT/AGENT". The thing is, I have no idea where that came from, why it worked before, or what might be stopping it from working now.
Update
I was able to get the IPC Calls working correctly by changing the IPC_URL String, but I still lack understanding of why what I did worked. Or rather, why the original code stopped working and I needed to change it in the first place.
The string I am using now is "tcp://localhost:63726/Agent"
Can anyone tell me, not why the new string works, I know that...but Why did the original string work before and why did updating the project target to .NET 4.0 break it?
what's the problem with the following code...
I have this Complex class:
public class Complex : MarshalByRefObject
{
public double imaginary{get;set;}
public double real{get;set;}
public void setReal(double re)
{
real = re;
}
public void setImaginary(double im)
{
imaginary = im;
}
public Complex(double im, double re)
{
imaginary = im;
real = re;
}
public void writeMembers()
{
Console.WriteLine(real.ToString() + imaginary.ToString());
}
}
Actually, there's a little more to it, but the code it's too big, and we don't use the rest of it in the context of this.
Then, I implemented a server which listens for connections:
HttpChannel channel = new HttpChannel(12345);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(SharedLib.Complex), "ComplexURI", WellKnownObjectMode.SingleCall);
Console.WriteLine("Server started. Press any key to close...");
Console.ReadKey();
foreach (IChannel ichannel in ChannelServices.RegisteredChannels)
{
(ichannel as HttpChannel).StopListening(null);
ChannelServices.UnregisterChannel(ichannel);
}
Then, we have the client:
try
{
HttpChannel channel = new HttpChannel();
RemotingConfiguration.Configure("Client.exe.config", false);
Complex c1 = (Complex)Activator.GetObject(typeof(Complex), "http://localhost:12345/ComplexURI");
if (RemotingServices.IsTransparentProxy(c1))
{
c1.real = 4;
c1.imaginary = 5;
c1.writeMembers();
Console.ReadLine();
}
else
{
Console.WriteLine("The proxy is not transparent");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
Then, I run the server, which opens a console window, and I run the client.
Instead of displaying 4 and 5 on the server window, I merely get 00, a sign that the members weren't changed.
How do I do, so the members change?
Thanks.
The problem is that you're using WellKnownObjectMode.SingleCall. As the documentation says:
SingleCall Every incoming message is serviced by a new object instance.
Singleton Every incoming message is serviced by the same object instance.
See also the documentation for RegisterWellKnownServiceType:
When the call arrives at the server, the .NET Framework extracts the URI from the message, examines the remoting tables to locate the reference for the object that matches the URI, and then instantiates the object if necessary, forwarding the method call to the object. If the object is registered as SingleCall, it is destroyed after the method call is completed. A new instance of the object is created for each method called.
In your case, the statement c.Real = 4 is a call to the Real property setter. It makes a call to the remote object, which creates a new object, sets the Real property to 4, and returns. Then when you set the imaginary property, it creates a new object, etc.
If you want this to work, you'll have to use WellKnownObjectMode.Singleton. But you might want to ask yourself if you really want such a "chatty" interface. Every time you set a property, it requires a call through the proxy to the server.
And, finally, you might consider abandoning Remoting altogether. It's old technology, and has a number of shortcomings. If this is new development, you should be using Windows Communications Foundation (WCF). The Remoting documentation says:
This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using the Windows Communication Foundation (WCF).
My answer:
After getting annoyed, I have found a solution. The problem was indeed C# either C#'s garbage collector or C#'s multithreading, it probably thought the object was no longer needed within THAT thread, and deleted it. The solution was found as follows:
I implemented the ClientThread into the Server class, passing the Client object as a parameters, this minor change made it work. Thank you for all your responses, if anyone in the future has this problem maybe it wasn't C#'s garbage collector. But C# mutithreading OR networking must be done within the same class. I kept my client class and just made the thread object run the function within the Server class.
If anyone can figure out what my problem was, feel free to comment so I can expand my little knowledge of C#'s memory management.
Thanks again to all the people who attempted to help me in this thread.
Original Question
I'm a C++ programmer so I'm used to managing memory myself, and I'm really not sure how to solve this problem.
For instance in C++:
while(true)
{
void* ptr = new char[1000];
}
This would be an obvious memory leaking program, so I need to go ahead and clean it up with:
delete ptr;
But there are cases when I want to create memory for use in a different thread and I DO NOT WANT IT DELETED AFTER THE LOOP.
while(true)
{
socket.Accept(new Client());
}
//////////Client Constructor////////////
Client()
{
clientThread.Start();
}
This snippet is basically what I want to do in C#, but my client connects then disconnects immediately, I'm assuming this is because at the end of the while loop my new Client() is being deleted by our favorite Garbage Collector.
So my question is, how do I get around this and make it NOT delete my object.
Many have replied saying various things about having other links to it in the code. I forgot to mention that I also save the new client in a list of clients located globally
List<Client> clients;
//inside loop
clients.Add(new Client(socket.Accept()));
Ok because I'm unsure if I'm missing more information here is the ACTUAL code snippet
// Server class
internal Socket socket { get; set; }
internal Thread thread { get; set; }
internal List<Client> clients { get; set; }
internal void Init()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
thread = new Thread(AcceptThread);
}
internal void Start(int port,List<Client> clients)
{
var ipep = new IPEndPoint(IPAddress.Any, port);
this.socket.Bind(ipep);
this.socket.Listen(10);
this.clients = clients;
this.thread.Start();
}
internal void End()
{
socket.Close();
thread.Abort();
}
internal void AcceptThread()
{
int ids = 0;
while (true)
{
Client client = new Client();
client.Init(socket.Accept());
client.clientid = ids++;
client.Start();
clients.Add(client);
}
}
// Client class
public class Client
{
.....
#region Base Code
internal void Init(Socket socket)
{
this.socket = socket;
this.status = new SocketStatus();
this.thread = new Thread(ClientThread);
this.stream = new Stream();
}
internal void Start()
{
thread.Start();
}
internal void Close()
{
socket.Close();
status = SocketStatus.Null;
thread.Abort();
}
internal void ClientThread()
{
try
{
while (true)
{
byte[] data = new byte[1];
int rec = socket.Receive(data);
if (rec == 0)
throw new Exception();
else
stream.write(data[0]);
}
}
catch(Exception e)
{
Close();
}
}
#endregion
}
I thank you for all your replies.
That's not how it works at all. If there exists any reference to the instance of Client you created, it is not garbage-collected. This doesn't just apply to your own code, either. Therefore, if GCing is indeed the source of your issue, you never could have accessed it in the first place!
If you weren't intending to access it, you can hold on to them anyway by putting them in a List. However, I believe that once you actually use them in the other thread you're talking about, your problems will go away.
I've been out of the c# game for a while but I don't see anything immediately wrong there. Garbage collection shouldn't kick in until objects are actually not referenced anymore. if your socket.Accept() doesn't keep a reference, perhaps you could do this manually:
var clients = new List<Client>();
while(true)
{
client = new Client();
clients.Add(client);
socket.Accept(client);
}
////////// Client Constructor ////////////
Client()
{
clientThread.Start();
}
From MSDN:
If no data is available for reading, the Receive method will block until data is
available, unless a time-out value was set by using
Socket.ReceiveTimeout. If the time-out value was exceeded, the Receive
call will throw a SocketException. If you are in non-blocking mode,
and there is no data available in the in the protocol stack buffer,
the Receive method will complete immediately and throw a
SocketException. You can use the Available property to determine if
data is available for reading. When Available is non-zero, retry the
receive operation.
If you are using a connection-oriented Socket, the Receive method will
read as much data as is available, up to the size of the buffer. If
the remote host shuts down the Socket connection with the Shutdown
method, and all available data has been received, the Receive method
will complete immediately and return zero bytes.
This appears to be the only way to get a 0 return value from the Receive method, and not get an exception, so it would appear that whatever is on the other end is closing the connection.
The garbage collector only deletes resources that aren't reachable through any reference in your program. As long as you still have a variable that refers to the object, it'll continue to exist.
I am creating an HttpListener by attempting to grab a random port that is open (or one that is not in IpGlobalProperties.GetActiveTcpConnections()). The issue I am running into is that after a while of making these connections and disposing them I am getting this error : No more memory is available for security information updates
Is there any way to resolve this or is there a proper way of getting rid of HttpListeners. I am just calling listener.Close().
Here is the method used to create the listeners :
private HttpListener CreateListener()
{
HttpListener httpListener;
DateTime timeout = DateTime.Now.AddSeconds(30);
bool foundPort = false;
do
{
httpListener = new HttpListener();
Port = GetAvailablePort();
string uriPref = string.Format("http://{0}:{1}/", Environment.MachineName.ToLower(), Port);
httpListener.Prefixes.Add(uriPref);
try
{
httpListener.Start();
foundPort = true;
break;
}
catch
{
httpListener.Close();
FailedPorts.Add(Port);
}
} while (DateTime.Now < timeout);
if (!foundPort)
throw new NoAvailablePortException();
return httpListener;
}
Have you tried calling listener.Stop() before Close()?
Another thing to try is to wrap your code in a using() {} block to make sure your object is disposed properly.
Finally, what are you doing with the listener (a code snippet might help)? Are you leaving any streams open?
This is the hackish way to force HttpListener to unregister all your Prefixes associated with that httpListener (this uses some of my custom reflection libraries but the basic idea is the same)
private void StopListening()
{
Reflection.ReflectionHelper.InvokeMethod(httpListener, "RemoveAll", new object[] {false});
httpListener.Close();
pendingRequestQueue.Clear(); //this is something we use but just in case you have some requests clear them
}
You need to remove the failed prefix before adding a new one, which is a lot simpler then Jesus Ramos proposed.
httpListener.Prefixes.Remove(uriPref);