Hallo
I need a Tcp connection to a server alive in backgrond and applications will send data with this connection.I searched around and found WCF singleton is apporiate for this task
here is a code snippet that i use below
my question is that the good way and any problem can be with this?
string hostAddress = string.Empty;
try
{
srvHost = new ServiceHost(typeof(ControllerClass));
NetTcpBinding netTcpBinding = new NetTcpBinding(SecurityMode.None);
netTcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
netTcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
srvHost.AddServiceEndpoint(typeof(IControllerContract), netTcpBinding, hostAddress);
srvHost.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
ServiceThrottlingBehavior serviceThrottlingBehavior = new ServiceThrottlingBehavior();
serviceThrottlingBehavior.MaxConcurrentCalls = 1000;
serviceThrottlingBehavior.MaxConcurrentInstances = 1000;
serviceThrottlingBehavior.MaxConcurrentSessions = 1000;
srvHost.Description.Behaviors.Add(serviceThrottlingBehavior);
srvHost.Open();
}
catch (System.TimeoutException timeoutEx)
{
Thread.Sleep(1000);
ReOpenHostConnection();//initialize again Controller Class
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("cannot start Service Ex:{0}", ex.ToString()), TraceEventType.Error.ToString());
}
//Controller Class Initialize Code Snippet
TcpClient iTcpClient = new TcpClient();
iTcpClient.Connect(serverIP, serverPort);
networkStream = iTcpClient.GetStream();
aSychDataByte = new byte[iTcpClient.ReceiveBufferSize];
networkStream.BeginRead(aSychDataByte, 0, incommTcpClient.ReceiveBufferSize, ReadAsych, null);
Why do you combine TcpClient with WCF? If you need low level Tcp communication build client and server based on low level Tcp classes. If you need service and you don't bother with message formats use WCF.
For your problem. You don't need singleton. You just need the connection to be opened. For this you need to create WCF proxy instance (open channel) on the client and call the service. It will create connection to service instance wich will live until you close the client proxy, until your service host stops working or until timeout (10 minutes of client inactivity by default).
Related
I am posting this because I was unable to find any place on Stack Overflow that addresses this issue for a .Net-Core project utilizing WCF by adding the service reference through Connected Services.
My issue was that I was facing client side timeouts because of long running operation requests.
So, how does one increase the timeout values for the wcf client objects since .Net-Core no longer uses the web config to store the configuration values for the WCF service references? (Please see my provided answer)
Under Connected Services in Solution Explorer, after adding a WCF service, a few files are generated for that service. You should see a folder with the name you gave the WCF service reference and under that a Getting Started, ConnectedService.json and a Reference.cs file.
To increase any of the client service object's timeout values, open Reference.cs and locate method: GetBindingForEndpoint
Inside this method you should see something like this:
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IYourService))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
//Here's where you can set the timeout values
result.SendTimeout = new System.TimeSpan(0, 5, 0);
result.ReceiveTimeout = new System.TimeSpan(0, 5, 0);
return result;
}
Just use result. and the timeout you want to increase like SendTimeout, ReceiveTimeout, etc. and set it to a new TimeSpan with the desired timeout value.
I hope this proves to be a useful post to someone.
Answer by Ryan Wilson will work but only until you will try to update service. Reference.cs will be overwritten.
In .NET Core 3.1 you can grammatically modify binding timeouts:
public MemoqTMServiceClass(string api_key)
{
client = new TMServiceClient();
var eab = new EndpointAddressBuilder(client.Endpoint.Address);
eab.Headers.Add(
AddressHeader.CreateAddressHeader("ApiKey", // Header Name
string.Empty, // Namespace
api_key)); // Header Value
client.Endpoint.Address = eab.ToEndpointAddress();
client.Endpoint.Binding.CloseTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.OpenTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
client.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
}
Just implement the following partial method in the generated proxy class to configure the service endpoint. Place the partial method in your own file to make sure it will not be overwritten.
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
I am working on a simple WCF service, MiniCalcService which has only one operation Add. The client and host are both console applications. The client application takes in the operands necessary for each operation and passes them over to the service. The service returns the result which would be displayed on the client console.
Host is running
I am doing everything in code so far and there is no app.config.
There is no large data being passed, just two or three numbers
This worked for me yesterday. Today when I tried the same thing, it throws the following exception:
There was no endpoint listening at http://localhost:8091/MiniCalcService that could accept the message.
Here is the Stack Trace. Not that it might matter, but MiniCalcClient is developed in Visual Studio and MiniCalcService and MiniCalcHost are developed in SharpDevelop.
MiniCalcHost:
using(ServiceHost host = new ServiceHost(typeof(MiniCalcService.Service), new Uri("http://localhost:8091/MiniCalcService")))
{
host.AddServiceEndpoint(typeof(MiniCalcService.IService),new BasicHttpBinding(),"Service");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
host.Open();
Console.WriteLine("Serving MiniCalcService since {0}", DateTime.Now);
Console.Write("Press ENTER key to terminate the MiniCalcHost . . . ");
Console.ReadKey(true);
}
MiniCalcClient:
static string Calculator(string operation, params string[] strOperands)
{
EndpointAddress ep = new EndpointAddress("http://localhost:8091/MiniCalcService");
IService proxy = ChannelFactory<IService>.CreateChannel(new BasicHttpBinding(), ep);
int[] operands;
string result = string.Empty;
try { operands = Array.ConvertAll(strOperands, int.Parse); }
catch (ArgumentException) { throw; }
switch (operation)
{
case "add":
result = Convert.ToString(proxy.Add(operands));//<---EXCEPTION
break;
default:
Console.WriteLine("Why was this reachable again?");
break;
}
return result;
}
Service Contract IService:
[ServiceContract(Namespace="learning.wcf.MiniCalc")]
public interface IService
{
[OperationContract]
double Add(params int[] operands);
}
Can you please help me identify what's causing this exception?
Solution: I changed this line:
EndpointAddress ep = new EndpointAddress("http://localhost:8091/MiniCalcService");
to this:
EndpointAddress ep = new EndpointAddress("http://localhost:8091/MiniCalcService/Service");
and it worked.
I'm not sure if you can use the params in a WCF service call.... seems unnecessary, anyway....
Could you try these two service contracts instead, just to see if those would work:
[ServiceContract(Namespace="learning.wcf.MiniCalc")]
public interface IService2
{
[OperationContract]
int Add(int op1, int op2);
}
and
[ServiceContract(Namespace="learning.wcf.MiniCalc")]
public interface IService3
{
[OperationContract]
int Add(List<int> operands);
}
I'm just wondering if removing the params from your service contract might make it run - everything seems fine at first glance...
OK, so it wasn't this first attempt ......
Well - quite obvious, really: you're using a using block around the service host instantiation:
using(ServiceHost host = new ServiceHost(typeof(MiniCalcService.Service), new Uri("http://localhost:8091/MiniCalcService")))
{
host.AddServiceEndpoint(typeof(MiniCalcService.IService),new BasicHttpBinding(),"Service");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
host.Open();
Console.WriteLine("Serving MiniCalcService since {0}", DateTime.Now);
Console.Write("Press ENTER key to terminate the MiniCalcHost . . . ");
}
So by the time the code reaches the closing bracket }, the ServiceHost instance will be disposed and thus the service host closed. There's no running service host anymore!
You need to stop the code execution somewhere after the call to host.Open() by e.g.
Console.ReadLine();
or something else.
So your first claim that Host is running really doesn't hold up - it's running briefly and then is terminated again right away.....
I have clients that upload files to my server using a wcf service with streaming. The code on the client is something like this (omitting some details):
NetTcpBinding binding = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://" + ipAddress + ":5000/DataUploader");
ChannelFactory<IDataUploader> channel = new ChannelFactory<IDataUploader>(binding, address);
IDataUploader uploader = channel.CreateChannel();
try
{
uploader.Upload(msg);
ConsoleText.Record("The file was sent...\n");
}
catch (CommunicationException)
{
ConsoleText.Record("The file was not sent...\n" + "Interrupted connection...\n");
}
finally
{
uploadStream.Close();
((IClientChannel)uploader).Close();
}
I want to implement a routing service between server and client, the routing service would be something like this:
private static void ConfigureRouterViaCode(ServiceHost serviceHost)
{
string clientAddress = "http://localhost:5000/DataUploader";
string routerAddress = "http://localhost:5000/RouterService";
Binding routerBinding = new WSHttpBinding();
Binding clientBinding = new WSHttpBinding();
serviceHost.AddServiceEndpoint(typeof(IRequestReplyRouter), routerBinding, routerAddress);
ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter));
ServiceEndpoint client = new ServiceEndpoint(contract, clientBinding, new EndpointAddress(clientAddress));
RoutingConfiguration rc = new RoutingConfiguration();
List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>();
endpointList.Add(client);
rc.FilterTable.Add(new MatchAllMessageFilter(), endpointList);
serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc));
}
It's confused how I can connect my client to the routing service first. Is this a good approach?? Thanks.
your approach is correct. On the client, change the address pointing to the routing service, leaving all other settings as they were. I suggest you study http://msdn.microsoft.com/en-us/library/ee517423.aspx or find some demo routing implementations.
I am using WCF for sending and getting data to and from 2 different win form applications running in the same machine. I am using namedpipe and duplexchannel. My client side implementation is shown below.
InstanceContext myContext = new InstanceContext(this);
NetNamedPipeBinding nb = new NetNamedPipeBinding();
nb.MaxBufferPoolSize = 5000000;
nb.MaxBufferSize = 500000;
nb.MaxReceivedMessageSize = 500000;
nb.ReceiveTimeout = TimeSpan.FromMinutes(5);
DuplexChannelFactory<IService> myProxy = new DuplexChannelFactory<IService>(myContext, nb, new EndPointAddress("net.pipe://localhost/MyService"));
IService myServiceClient = myProxy.CreateChannel();
And Server side implementation is shown below:
NetNamedPipeBinding np = new NetNamedPipeBinding();
np.MaxBufferPoolSize = 5000000;
np.MaxBufferSize = 500000;
np.MaxReceivedMessageSize = 500000;
host.AddServiceEndpoint(typeof(IService), np, "net.pipe://localhost/MyService");
host.OpenTimeout = TimeSpan.FromMinutes(5);
host.CloseTimeout = TimeSpan.FromMinutes(5);
host.Open();
I can pass about 100 object collection (ObservableCollection<Customer>) from 1 application through callback to other app. But if I make it 1000 or greater objects, the following Timeout Exception error occurs.
The write to the pipe did not complete
within the allotted timeout of
00:00:00. The time allotted to this
operation may have been a portion of a
longer timeout.
What is the fault in my code ? Please help me to overcome this issue.
Thanks in advance...
Looks like this question was also asked and answered here:
http://social.msdn.microsoft.com/Forums/eu/wcf/thread/38926593-8ea6-481d-8c43-072b73292f6a
How can I implement one way WCF operations?
I just tried using IsOneWay attribute as:
[OperationContract(IsOneWay=true)]
void MethodName(string param1, int param2)
Is there any other change I need to make or any specific change in app.config?
FYI, my WCF service implements netTcpBinding, though I think that shouldn't make any difference.
As shown, your code looks ok. There should be no problem with doing one-way calls with netTcpBinding.
If you're interested, chapter 5 in Juval Lowy's awesome Programming WCF Services 2nd Edition contains a good bit of information about one-way services.
From what you've shown, so far though I don't see anything wrong. Please give us some more details.
We had a problem with one-way calls not returning immediately using the NetTcpBinding. This blog post identifies the problem and provides a solution.
http://blogs.msdn.com/b/distributedservices/archive/2009/02/12/client-proxy-close-method-call-does-not-finish-immediately-in-one-way-wcf-calls.aspx
From the article:
Problem: Clients calling a one-way method in WCF Service and then close method on proxy does not return until the call is actually finished or call times out. Ever wonder why this happens?
Cause: When you specify “One-Way” on your interface, the underlying channel operation is still two-way since the one way binding element is not in the channel stack. Thus, the close operation gets blocked until the one way operation completes.
This is by design and the development team is working to change it in future versions of .Net framework.
...
Solution (Work around):
Layer the OneWayBindingElement on top of netTcpBinding as shown in the below code. This way, close call on proxy will return immediately and eventually the one-way call will return in fire and forget fashion.
[ServiceContract]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void SetData(int value);
}
public class Service1 : IService1
{
public void SetData(int value)
{
//Application specific code
}
}
Service Host code:
Form1ServiceHost = new ServiceHost(this, new Uri("net.tcp://localhost:8091/WindowsFormApp/Form1/"), new Uri("http://localhost:8090/WindowsFormApp/Form1/"));
Binding binding = new NetTcpBinding();
BindingElementCollection oldBindingElements = binding.CreateBindingElements();
BindingElementCollection bindingElements = new BindingElementCollection();
bindingElements.Add(new OneWayBindingElement());
foreach (BindingElement bindingElement in oldBindingElements)
{
bindingElements.Add(bindingElement);
}
binding = new CustomBinding(bindingElements);
Form1ServiceHost.AddServiceEndpoint("WCFServiceLibrary.IService1", binding, "");
Form1ServiceHost.Open();
Client Code:
Binding binding = new NetTcpBinding();
BindingElementCollection oldBindingElements = binding.CreateBindingElements();
BindingElementCollection bindingElements = new BindingElementCollection();
bindingElements.Add(new OneWayBindingElement());
foreach (BindingElement bindingElement in oldBindingElements)
{
bindingElements.Add(bindingElement);
}
binding = new CustomBinding(bindingElements);
Service1Client client = new Service1Client(binding, new EndpointAddress("net.tcp://localhost:8091/WindowsFormApp/Form1/"));
client.SetData(10);
Console.WriteLine("set data");
Console.WriteLine("Now closing the channel,Before close, current time is {0}", DateTime.Now.ToString() + " " + DateTime.Now.Millisecond.ToString());
client.Close();
Console.WriteLine("Now closing the channel,After close, current time is {0}", DateTime.Now.ToString() + " " + DateTime.Now.Millisecond.ToString());`