Create a self hosted WCF Service inside a Windows Form - c#

If I use this code for self Host a WCF service in a Console application it works. I run the host app and then from another app (which I call the client app,) I can add the service reference from visual studio > solution explorer > ADD SERVICE REFERENCE > http://10.131.131.14:8080/sendKioskMessage > click GO, add the service with no problems and consume it from the client app (which is a windows form)
But if I run the same code in a Windows Form, I run first the (SELF HOST WCF) windows form app, then from the other app (client app) in visual studio I try to add the service reference from ADD SERVICE REFERENCE in solution explorer (Just the same way that it works before but with the Console App self host) but it throws the following error:
*
An error (Details) occurred while attempting to find services at
http://10.131.131.14:8080/sendKioskMessage.
(If I click Details Link, says the following:)
There was an error downloading
'http://10.131.131.14:8080/sendKioskMessage/$metadata'. Unable to
connect to the remote server. Metadata contains a reference that
cannot be resolved: 'http://10.131.131.14:8080/sendKioskMessage'.
There was no endpoint listening at
http://10.131.131.14:8080/sendKioskMessage that could accept the
message. This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. Unable to connect to
the remote server. If the service is defined in the current solution,
try building the solution and adding the service reference again.
*
The IP that I use is the IP of my pc where both apps are running. I also used localhost instead of my actual IP with the same result.
Windows Form Code (can't add the service from another app):
public partial class KioskosServerForm : Form
{
[ServiceContract]
public interface IKioskMessageService
{
[OperationContract]
string SendKioskMessage(string message);
}
public class KioskMessageService : IKioskMessageService
{
public string SendKioskMessage(string message)
{
return string.Format("Message sent: {0}", message);
}
}
public KioskosServerForm()
{
InitializeComponent();
}
private void KioskosServerForm_Load(object sender, EventArgs e)
{
Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");
try
{
// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(KioskMessageService), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
}
}
catch (Exception exp)
{
MessageBox.Show(exp.InnerException.Message);
}
}
}
Console App Code (Works! I can add the service from other client app):
[ServiceContract]
public interface IKioskMessageService
{
[OperationContract]
string SendKioskMessage(string message);
}
public class KioskMessageService : IKioskMessageService
{
public string SendKioskMessage(string message)
{
return string.Format("Message sent: {0}", message);
}
}
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8080/sendKioskMessage");
// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(KioskMessageService),baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
}
}
I don't know why I can consume the service if the service is self hosted in a console app, but I can't add it if the service is self hosted in a Windows Form.
I will appreciate a lot your help to achieve this from a Windows From, since I need to self host the WCF service from a windows form, no a console app.
I'm using Visual Studio 2017, .Net Framework 4.6.1
THANKS IN ADVANCE GUYS!!

TL;DR the console app works because you have a delay before shutting down the service; the WinForms host doesn't
The reason your console WCF host service works is that you start the hosting and continue until the Console.ReadLine() line:
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine(); // <-------- program waits here
// Close the ServiceHost.
host.Close();
...after which the service is torn down. Prior to that, your other clients can connect fine and add Service References.
The WinForms app has no such delay:
private void KioskosServerForm_Load(object sender, EventArgs e)
{
Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");
try
{
// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(KioskMessageService), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open(); // <------ opened here
} // <------ shutdown here
}
catch (Exception exp)
{
MessageBox.Show(exp.InnerException.Message);
}
}
...it is immediately shutdown when the code goes out of scope of the using block. The using will automatically call Dispose() on the host object which in turn calls Close().
Consider placing the host into a variable like so:
ServiceHost _host; // <---------- new!
private void KioskosServerForm_Load(object sender, EventArgs e)
{
Uri baseAddress = new Uri("http://10.131.131.14:8080/sendKioskMessage");
try
{
// Create the ServiceHost.
_host = new ServiceHost(typeof(KioskMessageService), baseAddress))
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
_host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
_host.Open();
}
catch (Exception exp)
{
MessageBox.Show(exp.InnerException.Message);
}
}
Later, you can close the _host instance with a call to Close.

Related

WCF.ServiceChannel cannot communicate because of 'FaultedState' of Service

I am creating a selfhosted WCF Service.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface IStateChecker
{
[OperationContract]
void SetState(string state);
}
This is my Service:
public class StateCheckerService : IStateChecker
{
public void SetState(string state)
{
Console.WriteLine($"{DateTime.Now.ToString("dd.MM.yyyy HH:mm:sss")} : {state}");
}
}
And this my Implementation:
//Define baseaddres:
Uri baseAddress = new Uri("http://localhost:8000/ServiceModelSamples/Service");
//create host:
ServiceHost selfHost = new ServiceHost(typeof(StateCheckerService), baseAddress);
try
{
//Add endpoint to host:
selfHost.AddServiceEndpoint(typeof(IStateChecker), new WSHttpBinding(), "StateCheckerService");
//Add metadata exchange:
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Faulted += SelfHost_Faulted;
//Start service
selfHost.Open();
Console.WriteLine("Starting Service...");
if (selfHost.State == CommunicationState.Opened)
{
Console.WriteLine("The service is ready.");
}
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
//Shutdown service
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
private static void SelfHost_Faulted(object sender, EventArgs e)
{
ServiceHost host = sender as ServiceHost;
Console.WriteLine(host?.State);
Console.WriteLine(e?.ToString());
host?.Open();
}
Now when it comes to the client I get an error.
try
{
//Works using the ServiceReference (wsdl ... created by VisualStudio):
using (StateCheckerServiceReference.StateCheckerClient client = new StateCheckerClient())
{
client.SetState("Test");
}
//Does not work:
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:8000/ServiceModelSamples/Service");
using (ChannelFactory<IStateCheckerChannel> factory = new ChannelFactory<IStateCheckerChannel>("WSHttpBinding_IStateChecker", endpointAddress))
{
using (IStateCheckerChannel channel = factory.CreateChannel(endpointAddress))
{
channel?.SetState("Test");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Exception:
The communication object, "System.ServiceModel.Channels.ServiceChannel",
cannot be used for communication because it is in the Faulted state.
I never enter SelfHost_Faulted nor are there any Exceptions on my Service
I am doing this because I want to change the Endpoint the client should connect to at runtime.
If I'm doin it wrong please tell me. Otherwise any hints on what is wrong with my code are highly appreciated.
The issue is quite trivial, but hidden by the WCF infrastructure (strange implementation of a standard pattern).
If you change
channel?.SetState("Test");
to
try
{
channel?.SetState("Test");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
you will see 2 messages:
There was no endpoint listening at http://localhost:8000/ServiceModelSamples/Service that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
and
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.
The first one is the real exception (of type EndpointNotFoundException) caught by the inner catch.
The second (misleading) exception is of type CommunicationObjectFaultedException and is thrown by channel.Dispose() (?!) called at the end of your using block, hence hides the original one. WCF implementation simply is not following the rule that Dispose() should not throw!
With that being said, the problem is in your client endpoint. According to the service configuration, it should be "baseAddress/StateCheckerService" while currently it's just "baseAddress". So simply use the correct endpoint address
var endpointAddress = new EndpointAddress(
"http://localhost:8000/ServiceModelSamples/Service/StateCheckerService");
and the issue will be solved.

How to keep WCF Soap Service Open for the duration of the program running

I am working on an C# WCF project and I have got it pretty much working except for quite a big but hopefully simple problem.
The WCF service is hosted from within my Console application and my console application calls a function to a different class to open the connection for the WCF service.
However, if the last line of the function is host.open(); the function call then finishes to the connection gets closed and the service can no longer be used. However, if I put Console.ReadLine() after the host.open then the service stays open and I can use it but obviously the rest of the flow of the program no longer runs.
Below is the code I am using to open the host connection.
public void startSoapServer()
{
string methodInfo = classDetails + MethodInfo.GetCurrentMethod().Name;
if (String.IsNullOrEmpty(Configuration.soapServerSettings.soapServerUrl) ||
Configuration.soapServerSettings.soapPort == 0)
{
string message = "Not starting Soap Server: URL or Port number is not set in config file";
library.logging(methodInfo, message);
library.setAlarm(message, CommonTasks.AlarmStatus.Medium, methodInfo);
return;
}
//baseAddress = new Uri(string.Format("{0}:{1}", Configuration.soapServerSettings.soapServerUrl,
// Configuration.soapServerSettings.soapPort));
baseAddress = new Uri("http://localhost:6525/hello");
using (ServiceHost host = new ServiceHost(typeof(SoapServer), baseAddress))
{
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.Opened += new EventHandler(host_Opened);
host.Faulted += new EventHandler(host_Faulted);
host.Open();
Console.ReadLine();
}
Without the Console.ReadLine() there the function finishes so the connection closes. How can I keep the host open for the duration that the C# is app is running.
This function call is called from within the Main method halfway through initiliasing some stuff within the console stuff.
Thanks for any help you can provide.
You need to declare ServiceHost at class scope instead of function scope and do not use using.
using {} will automatically Dispose the object to which it pertains and Disposal means closing. Also, since your ServiceHost is defined at function scope, it will go out of scope as soon as the function finishes and will be cleaned up by the garbage collector.
The reason that your ReadLine call is preventing the closing is because it is inside the using statement and stops the program inside the function where the variable is declared keeping it in scope.
You need to do something like this:
private ServiceHost host;
public void startSoapServer()
{
// trimmed... for clarity
host = new ServiceHost(typeof(SoapServer), baseAddress));
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.Opened += new EventHandler(host_Opened);
host.Faulted += new EventHandler(host_Faulted);
host.Open();
// etc.
You will close host when you exit the application.

Windows service starts on Windows 7 but fails to start on Windows Server 2008 R2

I have created a wcf service which is deployed via a managed windows service. what the onstart() does is it creates and opens a tcp host for the wcf serice.
everything works fine in windows 7 but when I try to install the service in windows server 2008 R2 the service starts and then stops with the error that sometimes services stop when there is nothing to do. It is run under the network service account.
I cant find anything usefull in the windows logs.
I have tryed installing a dubug build and call debugger.launch() but its not working. I cant use remode debug because the the process does not stay open long enough for me to attach to it.
I really dont know what to do. Here is my code:
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
try
{
//if (!System.Diagnostics.EventLog.SourceExists("i2s CU Service (eng)"))
//{
// System.Diagnostics.EventLog.CreateEventSource("i2s CU Service", "Application");
//}
System.Diagnostics.EventLog.CreateEventSource("i2s CU Service", "Application");
}
catch (Exception)
{
//throw;
}
eventLog1.Source = "i2s CU Service";
eventLog1.Log = "Application";
if (serviceHost != null)
{
serviceHost.Close();
}
System.Configuration.AppSettingsReader reader = new System.Configuration.AppSettingsReader();
Uri tcpUri = null;
try
{
tcpUri = new Uri((string)reader.GetValue("Uri", typeof(string))); //net.tcp://localhost:8008/i2sServer
serviceHost = new ServiceHost(typeof(ConcurrentUsers), tcpUri);
// Create a binding that uses TCP and set the security mode to none.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.None;
// Add an endpoint to the service.
serviceHost.AddServiceEndpoint(typeof(IConcurrentUsers), b, "");
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
catch (Exception ex)
{
eventLog1.WriteEntry(ex.Message, EventLogEntryType.Error);
}
if (serviceHost.State == CommunicationState.Opened)
{
eventLog1.WriteEntry("Service started.", EventLogEntryType.Information);
}
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
eventLog1.WriteEntry("Service stopped.", EventLogEntryType.Information);
}
this code as is works perfectly fine in windows 7 but I cant get it to run on win 2008 R2 server.
Thanks in advance
Refactor your application as a console application, and then run it on the desired environment to be able to debug it easily.
I'm sure that the problem will reveal itself once you run your console replica under the same user account that is assigned to your windows service

WCF Service is not hosted on the machine

I have implemented a simple chat console app and it worked well. When i tried to apply the same concept on GUI app. the service side when hosting , there is any error but if i use CMD command netstat -ao to show all ports , it is not exists.So when i run client app , there is an Exception (No connection could be made because the target machine actively refused). How can i solve these problem ?
Server
ServiceHost host;
using (host = new ServiceHost(typeof(Service), new Uri("net.tcp://localhost:4111")))
{
host.AddServiceEndpoint(typeof(IService), new NetTcpBinding(), "IService");
try
{
host.Open();
}
catch
{
}
}
Client
public bool Connect()
{
DuplexChannelFactory<IService> pipeFactory = new DuplexChannelFactory<IService>(new InstanceContext(this),
new NetTcpBinding(),
new EndpointAddress(AppConfiguration.GetValue(net.tcp://localhost:4111/IService"));
try
{
pipeProxy = pipeFactory.CreateChannel();
if (pipeProxy.Register())
{
return true;
}
}
catch
{
}
return false;
}
Assuming you are showing all your code.
You need to add a line after host.Open();, you could add Console.ReadLine();
This would get the program to stop from existing. What happens now is that the host opens, then the program exists, and the host gets closed/garbage collected.
I have solve it.
In GUI remove the (using) at defined new ServiceHost. Why i don't know but it works!!!
ServiceHost host;
host = new ServiceHost(typeof(Service), new Uri("net.tcp://localhost:4111"));

Send message to all via Dual Binding by specific request?

The main goal is to let users send message to the host. The host will think for two seconds, and then with DUAL, will send a message back. This is working fine for me.
The thing is, for every user who send a message, I'm subscribing him to a list. The thing I'm trying to accomplish is, if the user Console.Readline() == "b" ( brodadcast ), send all the subscribers "Hello".
But the list of subscribers is at the service, and the Console.Readline() is at the host.
The host:
static void Main(string[] args)
{
ServiceHost duplex = new ServiceHost(typeof (ServiceClass));
duplex.Open();
Console.WriteLine("Press 'b' To Broadcast All subscibers : Hello");
if (Console.ReadLine()=="b")
{
foreach (var registered in lstOfRegisteredUsers) //<== I cant access lstOfRegisteredUsers because its on the Service Class.
{
registered.SendBack("Hello");
}
}
Console.WriteLine("Host is running, press <ENTER> to exit.");
Console.ReadLine();
}
The service:
public class ServiceClass : ISend
{
public List<ISendBack> lstOfRegisteredUsers = new List<ISendBack>();
public void Send(string data)
{
ISendBack callback = OperationContext.Current.GetCallbackChannel<ISendBack>();
lstOfRegisteredUsers.Add(callback); // <== here i'm adding subscribers for future broadcast " hello".
Console.WriteLine("goind to process " + data);
System.Threading.Thread.Sleep(2000);
callback.SendBack("done " +data);
}
}
How can I send from the host, to each of the subscribers: "hello"?
If I understand correctly then you wish to broadcast a message to each of your service's callback clients if a key-press input is received into the console application hosting your service?
To do this you need to be able to call into your service instance from your host application.
This can be achieved by creating an instance of your service class within your host. Then when you create your ServiceHost you pass the instance into the ServiceHost constructor. Then in your service you have a method which does the actual callback and you can call it.
For example:
// Create an instance of your service class
ServiceClass sc = new ServiceClass();
// Instantiate new ServiceHost and pass in the instance as a singleton
serviceHost = new ServiceHost(sc, "(Service uri here)");
// Call the method on the service (which then calls the clients)
sc.DoCallbacks();

Categories

Resources