A WCF file.
namespace DatabaseTransferViaWcf
{
[ServiceContract]
public interface IService1
{
[OperationContract]
int generateId();
}
}
The corresponding file.
namespace DatabaseTransferViaWcf
{
public class Service1 : IService1
{
public int generateId()
{
return 5700 ;
}
}
}
I added them to my WPF Project as a service reference called "SendRecieveData".
How I am trying to use it.
public partial class Transfer : Window
{
private void button9_Click(object sender, RoutedEventArgs e)
{
ServiceHost host = null;
try
{
using (ServiceHost host = new ServiceHost(typeof(SendRecieveData.Service1)))
{
host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <enter /> to terminate service.");
Console.ReadLine();
}
wcfHostId = wcf.generateId();
textBox5.Text = "" + wcfHostId;
}
catch (Exception ex)
{
MessageBox.Show("Error = " + ex.Message);
}
}
}
It says I am missing a reference to Service1 but all the tutorials and blogs I have looked at don't have any more steps to them.
WPF application is a client of your service so you shouldn't use ServiceHost class. It is used if you want to host a service within your application. It is not your case. In your situation you should just use a proxy generated automatically when you added a service reference to your project.
Your service reference has not been added correctly. Try removing it and make sure you name it Service1 and not Service1Service or something similar.
EDIT:
Try something like
Service1Client service1Client = new service1Client();
Console.WriteLine(service1Client.generateId());
It is usually how the services are named.
Related
I'm new to WCF services, I'm trying to replicate tutorial of "Hosting a WCF Service in a Managed Windows Service":
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-host-a-wcf-service-in-a-managed-windows-service
I managed to create service and its installer (in ServiceProject), I managed to install service with sysutil command. I was able to connect to service from separate console project (let's name it TestProject) and call its functions - it works when I run them from Visual Studio. The problem is: when I'm trying to use executable file of TestProject - it doesn't work. I tried to do it after manually starting service from windows services list, but it just returns error. Can you help me with understanding what I'm doing wrong?
The code I'm trying to run from TestProject looks like this:
static void Main(string[] args)
{
try
{
WinWCFServiceClient client = new WinWCFServiceClient();
client.ShowTextMessageAsync("it works as win service!!!");
}
catch (Exception ex)
{
Console.WriteLine("There were errors");
Console.WriteLine(ex.ToString());
}
Console.WriteLine("The end");
Console.ReadLine();
}
It crushes with exeption looking like this:
? System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)
? System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
? System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
? System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress) ? System.ServiceModel.ConfigurationEndpointTrait1.CreateSimplexFactory()
? System.ServiceModel.ConfigurationEndpointTrait1.CreateChannelFactory() ? System.ServiceModel.ClientBase1.CreateChannelFactoryRef(EndpointTrait1 endpointTrait) ? System.ServiceModel.ClientBase1.InitializeChannelFactoryRef()
? System.ServiceModel.ClientBase`1..ctor()
? WinWCFServiceClient..ctor() ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\generatedProxy.cs:?????? 35
? CheckWinWCF_NF.Program.Main(String[] args) ? C:\Projects\Training Projects\WCF Service\CheckWinWCF_NF\Program.cs:?????? 16
And my service looks like this:
[ServiceContract]
public interface IWinWCFService
{
[OperationContract]
void ShowTextMessage(string str);
}
public class WinWCFService : IWinWCFService
{
public void ShowTextMessage(string str)
{
MessageBox.Show(String.Format("You send this message {0}:", str));
}
}
Installer part:
public class WinWCFServiceBase:ServiceBase
{
public ServiceHost serviceHost = null;
public WinWCFServiceBase()
{
// Name the Windows Service
ServiceName = "WCFWinServiceRS";
}
public static void Main()
{
ServiceBase.Run(new WinWCFServiceBase());
}
// Start the Windows service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(WinWCFService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
private void InitializeComponent()
{
//
// WinWCFServiceBase
//
this.ServiceName = "WinWCFServiceRS";
}
}
What is the problem: System.TimeoutException: 'The request channel timed out while waiting for a reply after 00:00:59.977913. So, basically it can be everything.
What do I have:
I create a simple solution to found a fix. What really make me confused is that console app works just fine, however wpf app with same configuration does not work. Solution include four projects(code made for debugging purpose, please don't judge it):
library with contracts and their implementation.
public class DeviceService : IDeviceService
{
public string GetDevices()
{
return "hello world";
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
library with host.
public class DeviceServiceHostFactory
{
ServiceHost host;
public DeviceServiceHostFactory()
{
ServiceMetadataBehavior metadataBehavior;
BasicHttpBinding binding = new BasicHttpBinding();
Uri address = new Uri("http://localhost:4000/");
host = new ServiceHost(typeof(DeviceService), address);
Type contract = typeof(IDeviceService);
host.AddServiceEndpoint(contract, binding, "");
}
public void Start()
{
host.Open();
}
public void Stop()
{
host.Close();
}
}
desktop app that start service and consume it (does not work)
public partial class MainWindow : Window
{
private DeviceServiceHostFactory _deviceService;
public MainWindow()
{
InitializeComponent();
try
{
_deviceService = new DeviceServiceHostFactory();
_deviceService.Start();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
private void Btn_custom_Click(object sender, RoutedEventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
txt_custom.Text = channel.GetDevices();
Console.WriteLine();
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
console app (works fine)
class Program
{
static void Main(string[] args)
{
DeviceServiceHostFactory _deviceService = new
DeviceServiceHostFactory();
try
{
_deviceService.Start();
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
Console.WriteLine(channel.GetDevices());
Console.ReadLine();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
I really spend a lot of time for this, and I will be very grateful for every solution or thought how can I debug it more advanced.
Hosting wcf service in application with UI is little bit tricky, so I hope this will help someone.
Took it from book Learning WCF: A hands-On Guide By Michele Leroux Bustamante, Chapter 4, so fo more information please find this book.
To host service in Windows application or WPF application, we have to create a new thread to start it in a new synchronization context. It can be done in two ways:
First, is to create service host before the UI thread created. Here service executes in a new synchronization contenxt before application starts.
static class Program
{
static void Main()
{
DeviceServiceHostFactory deviceService = new DeviceServiceHostFactory();
deviceService.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow);
}
}
Second, is to initialize service host on a separate thread, after UI been created
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread;
thread = new Thread(ServiceInitialize);
thread.IsBackground = true;
thread.Start();
}
private void ServiceInitialize()
{
var service = new DeviceServiceHostFactory();
service.Start();
}
}
This means the messages are processed on threads form the thread pool instead of through the message loop.
First, we should give the current account permissions when we occupy the Operation system ports to host services.
This function could be accomplished by the below command.
Netsh http add urlacl url=https://+:80/MyUri user=DOMAIN\user
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
If we don’t want to do this, we could directly run the service with administrator accounts.
Thereby I suspect there is something wrong with the process of hosting the service. Have you tried running the WPF application with an administrator account?
Besides, I suggest you add a namespace in the service contract.
[ServiceContract(Namespace ="MyNamespace")]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
Sometimes, it could run into problems when the service contract doesn’t have a namespace property.
Feel free to let me know if the problem still exists.
Trying to get a simple demo of NetTcpBinding working in order to expand it into another project.
Architecture: 2 console apps (1 host/server, 1 client) and 1 type library project. Both console apps have a reference to the type library project.
Host application:
class Program
{
static void Main()
{
var netTcpBinding = new NetTcpBinding(SecurityMode.None)
{
PortSharingEnabled = true
};
var netTcpAdddress = new Uri("net.tcp://127.0.0.1:1234/HelloWorldService/");
var tcpHost = new ServiceHost(typeof(HelloWorldService), netTcpAdddress);
tcpHost.AddServiceEndpoint(typeof(IHelloWorld), netTcpBinding, "IHelloWorld");
tcpHost.Open();
Console.WriteLine($"tcpHost is {tcpHost.State}. Press enter to close.");
Console.ReadLine();
tcpHost.Close();
}
}
public class HelloWorldService : IHelloWorld
{
public void HelloWorld()
{
Console.WriteLine("Hello World!");
}
public void WriteMe(string text)
{
Console.WriteLine($"WriteMe: {text}");
}
}
Client application:
static void Main()
{
Console.WriteLine("Press enter when the service is opened.");
Console.ReadLine();
var endPoint = new EndpointAddress("net.tcp://127.0.0.1:1234/HelloWorldService/");
var binding = new NetTcpBinding ();
var channel = new ChannelFactory<IHelloWorld>(binding, endPoint);
var client = channel.CreateChannel();
try
{
Console.WriteLine("Invoking HelloWorld on TcpService.");
client.HelloWorld();
Console.WriteLine("Successful.");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
Console.WriteLine("Press enter to quit.");
Console.ReadLine();
}
Type Library:
[ServiceContract]
public interface IHelloWorld
{
[OperationContract]
void HelloWorld();
[OperationContract]
void WriteMe(string text);
}
I believe I have all necessary services installed and running:
Obviously I'm trying to do all the config at runtime.
I consistently get this error message on the client:
Invoking HelloWorld on TcpService.
Exception: There was no endpoint listening at
net.tcp://127.0.0.1:1234/HelloWorldService/ that could accept the
message. This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. Press enter to quit.
Am I missing something obvious?
Your service is exposing the endpoint at address:
net.tcp://127.0.0.1:1234/HelloWorldService/IHelloWorld
but your client is connecting to:
net.tcp://127.0.0.1:1234/HelloWorldService/
You'll also need to set the client NetTcpBinding SecurityMode the same as the server (None).
Have run into a slight problem regarding Client Connections that need to be passed between threads.
1.) We have a service class
public class Service : ServiceBase
{
public ServiceHost serviceHost = null;
public CMLiteService()
{
ServiceName = "MyService";
}
public static void Main()
{
ServiceBase.Run(new Service());
}
protected override void OnStart(string[] args)
{
try
{
if (serviceHost != null)
{
serviceHost.Close();
}
Uri baseAddress = new Uri("net.pipe://localhost/Service");
// Step 2 Create a ServiceHost instance
serviceHost = new ServiceHost(typeof(Service), baseAddress);
// Step 3 Add a service endpoint.
serviceHost.AddServiceEndpoint(typeof(IService), new NetNamedPipeBinding(), "Service");
serviceHost.Open();
}
catch(Exception e)
{
}
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
2.) We have an interface
[ServiceContract]
public interface IService
{
[OperationContract]
string InitalizeDataStore(string uri1, string uri2);
[OperationContract]
string CheckHealth();
[OperationContract]
string CreateObject(string parameters);
}
3.) We have a method that Initializes Our data storage
ObjectOperations objectOperations;
public InitalizeDataStore (string uri1, string uri2)
{
Admin admin = new Admin(uri1, uri2);
objectOperations = new ObjectOperations(admin.client1, admin.client2);
}
4.) Here is the admin class that does the actual connecting to the database, both there clients are thread safe and support multithreading
StorageClient1 client1
StorageClient2 client2
string URI1;
string URI2;
public AdminServices(string uri1, string uri2)
{
URI1 = uri1;
URI2 = uri2;
InitializeClient1();
InitializeClient2();
}
public StorageClient1 InitializeClient1()
{
try
{
client1 = new Client(new Uri(URI1));
client1.Connect();
return client1;
}
catch (Exception e)
{
throw e;
}
}
public Client2 InitializeClient2()
{
try
{
client2 = new Client(new Uri(URI2));
client2.Connect();
return client2;
}
catch (Exception e)
{
throw e;
}
}
5.) When we start the service and run the initialization method it connects and works. But when we start another process the client connections are null? If we run the code top down in one console app it works but we are in need of running initialization once and then the client connection must be set for future processes.
So Process 1:
IService pipeProxy = pipeFactory.CreateChannel();
pipeProxy.InitalizeDataStore(); //Returns "Connected"
Process 2:
IService pipeProxy = pipeFactory.CreateChannel();
pipeProxy.CheckHealth(); //returns null
How do we insure that the Client Connection details are also made availible in another process. I am very new too this so Im not too clued up on multithreading.
I believe what you are trying to accomplish is served by the WCF Singleton instance mode:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
Attribute your implementing class with the above, and all clients will share an instance.
The contract type HelloIndigo.Service is not attributed with
ServiceContractAttribute. In order to define a valid contract, the
specified type (either contract interface or service class) must be
attributed with ServiceContractAttribute.
I build a library class and referenced to the class in the console application.
The library class:
namespace HelloIndigo
{
public class Service : IHelloIndigoService
{
public string HelloIndigo()
{
return "Hello Indigo";
}
}
[ServiceContract(Namespace = "http://www.thatindigogirl.com/samples/2006/06")]
interface IHelloIndigoService
{
[OperationContract]
string HelloIndigo();
}
}
The console application:
namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(HelloIndigo.Service),
new Uri("http://localhost:8000/HelloIndigo")))
{
host.AddServiceEndpoint(typeof(HelloIndigo.Service),
new BasicHttpBinding(),"Service");
host.Open();
Console.WriteLine("Press enter to terminate the host service");
Console.ReadLine();
}
}
}
}
When you add the endpoint, you should supply the interface that is the contract:
host.AddServiceEndpoint(typeof(HelloIndigo.IHelloIndigoService),
new BasicHttpBinding(),"Service");