Launching different service host with the same contract fails - wcf

I'm trying to write a generic host process (WinForm) which host different WCF Service implementation of the same contract.
When I run the first one it works OK, but when I launch the other one (in parallel) with a different address is throws that I use the same address twice (addr and port) -> path is different though..
private bool InitializeServiceHost()
{
bool isInitialized = true;
try
{
Log.InfoFormat("Loading service DLL {0} and class {1}", _dllPath, _serviceClassName);
var asm = Assembly.LoadFile(_dllPath);
_service = (IGfnService) asm.CreateInstance(_serviceClassName);
if (_service == null)
throw new ApplicationException(string.Format("Could not instansiate {0} from DLL {1}", _serviceClassName, _dllPath));
_service.Init(_myGuidStr);
Uri uri = new Uri("net.tcp://localhost:9085/GfnService/" + _myGuidStr);
var host = new ServiceHost(_service, uri);
Log.InfoFormat("About to open host, State: {0}, URI: {1} ", host.State, uri);
host.Open();
_serviceUri = uri.ToString();
Log.InfoFormat("Gfn service started successfully, State: {0}, URI: {1} ", host.State, uri);
}
catch (Exception ex)
{
Log.Error(ex.Message, ex);
isInitialized = false;
Application.Exit();
}
return isInitialized;
}
Any help will be appreciated....

Got it! it works now! (thanks to all commenters)
var host = new ServiceHost(_service);
Log.Info("Service host generated.");
ServiceEndpoint serviceEndpoint = host.Description.Endpoints.Find(typeof(IGfnService));
if (serviceEndpoint == null)
{
serviceEndpoint = host.AddServiceEndpoint(typeof(IGfnService), new NetTcpBinding
{
MaxConnections = 10,
PortSharingEnabled = true
}, uri);
Log.InfoFormat("Endpoint [{0}] added", serviceEndpoint);
}
The trick was to add the PortSharingEnabled! so the two instances can share the same port! (I should have though about it before, but at least I got a chance to share!)
Thanks!

Related

completion port thread is leaking when client terminates the connection

I have a ASP.NET WebApi self-hosted application. HttpSelfHostConfiguration is configured as below
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://0.0.0.0:54781")
{
TransferMode = TransferMode.StreamedResponse,
MaxConcurrentRequests = 1000,
SendTimeout = TimeSpan.FromMinutes(60),
};
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}",
defaults: new { #controller = "Default" }
);
HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
for (;;)
{
int workerThreads, completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine("Available Completion Port Threads = {0};", completionPortThreads);
Console.Out.Flush();
Thread.Sleep(2000);
}
There is an action accepts HTTP GET request as below
public class DefaultController : ApiController
{
public HttpResponseMessage GET()
{
Console.WriteLine("Receive HTTP GET request");
Func<Stream, HttpContent, TransportContext, Task> func = (stream, httpContent, transportContext) =>
{
return Monitor(httpContent, stream);
};
HttpResponseMessage response = Request.CreateResponse();
response.StatusCode = HttpStatusCode.OK;
response.Content = new PushStreamContent(func, new MediaTypeHeaderValue("text/plain"));
return response;
}
async Task Monitor(HttpContent httpContent, Stream stream)
{
try
{
using (StreamWriter sw = new StreamWriter(stream, new UTF8Encoding(false)))
{
for (;;)
{
sw.WriteLine(Guid.NewGuid().ToString());
sw.Flush();
await Task.Delay(1000);
}
}
}
catch (CommunicationException ce)
{
HttpListenerException ex = ce.InnerException as HttpListenerException;
if (ex != null)
{
Console.WriteLine("HttpListenerException occurs, error code = {0}", ex.ErrorCode);
}
else
{
Console.WriteLine("{0} occurs : {1}", ce.GetType().Name, ce.Message);
}
}
catch (Exception ex)
{
Console.WriteLine("{0} occurs : {1}", ex.GetType().Name, ex.Message);
}
finally
{
stream.Close();
stream.Dispose();
httpContent.Dispose();
Console.WriteLine("Dispose");
}
}
}
Open the url http://127.0.0.1:54781/ and I see progressive response comming.
But If the client terminates the connection when the server is sending the response, the completion port thread is taken up and never released.
It able to bring down the application by exhausting the completion port threads pool.
After changing to OWIN self-hosting, this problem disappears. It seems a bug in System.Web.Http.SelfHost
Here is updated code:
class Program
{
static void Main(string[] args)
{
var server = WebApp.Start<Startup>(url: "http://*:54781");
for (;;)
{
int workerThreads, completionPortThreads;
ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
Console.WriteLine("Worker Threads = {0}; Available Completion Port Threads = {1};", workerThreads, completionPortThreads);
Console.Out.Flush();
Thread.Sleep(2000);
}
}
}
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}",
defaults: new { #controller = "Default" }
);
appBuilder.UseWebApi(config);
}
}
For others coming to this post there is a similar issue in System.Web.Http.SelfHost which by default uses CPU Cores * 100 threads which is the same as the default ThreadPool limit ending in a deadlock as Mono pre-creates all the threads.
The easiest way to get around this is to set the MONO_THREADS_PER_CPU environment variable to a value greater than 1 or use the --server flag when running the Mono application.

Monotouch WCF call crashes with SIGILL error on 10th attempt

Using latest monotouch(4.0.3) we have WCF services that are called. After performing the call the 10th attempt crashes. I have created a test program that calls simple WCF call to see if service is up. Responds with an OK message. On 10th call it fails. Tried Server config settings, Close, Dispose on client still same results. Sample Test code segment below:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
mailButton.TouchUpInside += (o, e) =>
{
BasicHttpBinding BindType = new BasicHttpBinding();
BindType.ReceiveTimeout = new TimeSpan(0,0,15);
EndpointAddress ep = new EndpointAddress(#"http://myservice.mydomain.com/MyBusServiceBusService/MFService.svc/BaseService");
BaseServiceClient MFService = new BaseServiceClient(BindType, ep);
MFService.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0,0,10);
MFService.BaseServiceTestCompleted += delegate(object sender, BaseServiceTestCompletedEventArgs ex)
{
UIAlertView alert = new UIAlertView();
alert.Title = "Base Service Test";
alert.AddButton("Ok");
++timesThrough;
alert.Message = ex.Result + " Times=" + timesThrough.ToString();;
alert.InvokeOnMainThread(delegate{alert.Show(); });
var clientObject = sender as BaseServiceClient;
if (clientObject != null && clientObject.State == System.ServiceModel.CommunicationState.Opened)
{
(clientObject.ChannelFactory).Close();
(clientObject).Close();
((IDisposable)clientObject).Dispose();
clientObject = null;
}
if (MFService != null)
{
(MFService.ChannelFactory).Close();
(MFService).Close();
((IDisposable)MFService).Dispose();
MFService = null;
}
GC.Collect();
};
try
{
MFService.BaseServiceTestAsync();
}
catch (Exception ex)
{
UIAlertView alert = new UIAlertView();
alert.Title = "Base Service Test";
alert.AddButton("Ok");
alert.Message = ex.Message ;
alert.InvokeOnMainThread(delegate{alert.Show();});
MFService = null;
GC.Collect();
}
};
}
This issue was fixed in the latest MonoTouch (4.1 beta). The 4.2 (stable) release should be available soon.

How to detect connectivity to my server using Silverlight 4

The users of my Silverlight application will access the server via a VPN connection. Thus, the built in NetworkInterface.GetIsNetworkAvailable is of no use.
I tried 2 different methods for checking connection to my server; WebClient and a WCF service.
As for the service, I tried the following method. I can't see how I would use a regular service call since the return handler would never hit.
var ping = new PingServiceClient();
ping.InnerChannel.Open( new TimeSpan(1500) );
var result = ping.State == CommunicationState.Opened;
Using WebClient, I tried this:
var client = new WebClient();
client.OpenReadCompleted += (s, e) => { MessageBox.Show( "Returned from server" ); };
client.OpenReadAsync( new PingServiceClient().Endpoint.Address.Uri );
In both cases, the results were the same (indicates connected) whether or not I was connected to the server (I pushed the samples to the live server and connected/disconnected using the VPN client.
The next thing I would try is sockets, but just getting a working sample is beyond difficult. Before going down that road any further, is there some other way of accomplishing this?
The WebClient will probably return completed regardless. You'll need to check if there was an error in the request.
var client = new WebClient();
client.OpenReadCompleted += (s,e) =>
{
if (e.Error == null)
{
MessageBox.Show("Returned from server");
}
}
client.OpenReadAsync( new PingServiceClient().Endpoint.Address.Uri );
I placed a small text file on the server and read it's contents. So this test worked reliably [edit: see comment]:
var client = new WebClient();
client.OpenReadCompleted += (s, e) =>
{
if ( e.Error == null )
{
var bytesReceived = new byte[ e.Result.Length ];
e.Result.Read( bytesReceived, 0, 50 );
var result = Encoding.UTF8.GetString( bytesReceived, 0, bytesReceived.Length );
if ( result.Contains( "pingback" ) )
{
MessageBox.Show("Server up");
}
else
{
MessageBox.Show( "Server down" );
}
}
else
{
MessageBox.Show("Server down");
}
};
var uri = string.Format( "{0}{1}{2}{3}{4}{5}", App.Current.Host.Source.Scheme, "://", App.Current.Host.Source.DnsSafeHost, ":", App.Current.Host.Source.Port, "/Ping.txt" );
client.OpenReadAsync( new Uri(uri) );

WCF: ServiceHost problem (cached adresses?)

i use a WCF-Service.
It workes fine, and if i use a forbidden IP it shows me a message.
But if i change the ip in my textbox to the right IP it will be again catch the TCP exception, with the OLD IP... The IP-string in the textbox is the corret one and all variables contains the right IP...
The exception:
CommunicationException TCP-Fehler
(10049: Die angeforderte Adresse ist
in diesem Kontext ungültig) beim
Lauschen am
IP-Endpunkt=192.168.178.2:7997.
Should be 192.168.178.25
And after correcting the IP in the textbox and restarting the server i get the same exception with the old IP...
Here is my method:
I create all ressources new in this methode.
Only the ServiceHost host; Variable is stored outside the methode and i tried to set it null before starting or after exception.
Configure Host:
private void MenuItemServerStart_Click(object sender, RoutedEventArgs e)
{
**[ omitted ]**
//Define base addresses so all
//endPoints can go under it
Uri tcpAdrs = new Uri("net.tcp://" +
textBoxLocalIP.Text.ToString() + ":" +
textBoxPort.Text.ToString() + "/WPFHost/");
Uri httpAdrs = new Uri("http://" +
textBoxLocalIP.Text.ToString() + ":" +
(int.Parse(textBoxPort.Text.ToString()) + 1).ToString() +
"/WPFHost/");
Uri[] baseAdresses = { tcpAdrs, httpAdrs };
try
{
host = new ServiceHost(typeof(ChatService.ChatService), baseAdresses);
}
catch (TargetInvocationException ex)
{
if (ex.InnerException != null)
{
**[ omitted ]**
}
return;
}
catch (Exception)
{
**[ omitted ]**
}
NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None, true);
//Updated: to enable file transefer of 64 MB
tcpBinding.MaxBufferPoolSize = (int)67108864;
tcpBinding.MaxBufferSize = 67108864;
tcpBinding.MaxReceivedMessageSize = (int)67108864;
tcpBinding.TransferMode = TransferMode.Buffered;
tcpBinding.ReaderQuotas.MaxArrayLength = 67108864;
tcpBinding.ReaderQuotas.MaxBytesPerRead = 67108864;
tcpBinding.ReaderQuotas.MaxStringContentLength = 67108864;
tcpBinding.MaxConnections = 100;
**[ omitted ]**
host.AddServiceEndpoint(typeof(ChatService.IChatService),
tcpBinding, "tcp");
//Define Metadata endPoint, So we can
//publish information about the service
ServiceMetadataBehavior mBehave =
new ServiceMetadataBehavior();
host.Description.Behaviors.Add(mBehave);
host.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexTcpBinding(),
"net.tcp://" + textBoxLocalIP.Text.ToString() + ":" +
(int.Parse(textBoxPort.Text.ToString()) - 1).ToString() +
"/WPFHost/mex");
Start host (Exception):
try
{
**host.Open();** **//Exception here !!!**
}
catch (Exception ex)
{
**[ omitted ]**
}
finally
{
if (host.State == CommunicationState.Opened)
{
((StatusBarItem)statusBar1.Items.GetItemAt(0)).Content = "Gestartet";
MenuItemServerStop.IsEnabled = true;
}
}
}
I have a hunch that there may be some static state associated with the channel runtime infrastructure for HTTP bindings, which maintains details of HTTP listeners keyed by service Uri. If you are not properly tearing down ServiceHost instances which threw on Open, perhaps the old details remain registered in this static state.
What happens in your catch block following the call to host.Open()? If you are not calling host.Abort() and host.Dispose() on the instances which threw on Open, this might be the problem.

Duplex WCF + Static Collection of COM objects

I am trying to build a WCF service that exposes the functionality of a particular COM object that I do not have the original source for. I am using duplex binding so that each client has their own instance as there are events tied to each particular instance which are delivered through a callback (IAgent). It appears there is a deadlock or something because after the first action, my service blocks at my second action's lock. I have tried implementing these custom STA attribute and operation behaviors (http://devlicio.us/blogs/scott_seely/archive/2009/07/17/calling-an-sta-com-object-from-a-wcf-operation.aspx) but my OperationContext.Current is always null. Any advice is much appreciated.
Service
Collection:
private static Dictionary<IAgent, COMAgent> agents = new Dictionary<IAgent, COMAgent>();
First action:
public void Login(LoginRequest request)
{
IAgent agent = OperationContext.Current.GetCallbackChannel<IAgent>();
lock (agents)
{
if (agents.ContainsKey(agent))
throw new FaultException("You are already logged in.");
else
{
ICOMClass startup = new ICOMClass();
string server = ConfigurationManager.AppSettings["Server"];
int port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
bool success = startup.Logon(server, port, request.Username, request.Password);
if (!success)
throw new FaultException<COMFault>(new COMFault { ErrorText = "Could not log in." });
COMAgent comAgent = new COMAgent { Connection = startup };
comAgent.SomeEvent += new EventHandler<COMEventArgs>(comAgent_COMEvent);
agents.Add(agent, comAgent);
}
}
}
Second Action:
public void Logoff()
{
IAgent agent = OperationContext.Current.GetCallbackChannel<IAgent>();
lock (agents)
{
COMAgent comAgent = agents[agent];
try
{
bool success = comAgent.Connection.Logoff();
if (!success)
throw new FaultException<COMFault>(new COMFault { ErrorText = "Could not log off." });
agents.Remove(agent);
}
catch (Exception exc)
{
throw new FaultException(exc.Message);
}
}
}
Take a look at this very similar post: http://www.netfxharmonics.com/2009/07/Accessing-WPF-Generated-Images-Via-WCF
You have to use an OperationContextScope to have access to the current OperationContext from the newly generated thread:
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
using (System.ServiceModel.OperationContextScope scope = new System.ServiceModel.OperationContextScope(context))
{
result = InnerOperationInvoker.Invoke(instance, inputs, out staOutputs);
}
}));