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.
Related
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).
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.
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.
When creating a NServiceBus SendOnly endpoint, the purpose is to just fire-and-forget, i.e. just send a message and then someone else will take care of it. Which seems like the thing I need. I dont want any communication between the bus and the system handling messages. System "A" wants to notify system "B" about something.
Well the creation of an SendOnly endpoint if very straightforward but what about the system listening for messages from an SendOnly endpoint.
I'm trying to set up a listener in a commandline project that will handle messages. The messages get sent to the queue but they doesnt get handled by system "B".
Is this the wrong approach? Is a bus overkill for this type of functionality?
System A:
public class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.SendOnly();
while(true)
{
Console.WriteLine("Send a message");
var message = new Message(Console.ReadLine());
bus.Send(message);
}
}
}
System B:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
var bus = Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
Console.WriteLine("Waiting for messages...");
while(true)
{
}
}
}
public class MessageHandler : IHandleMessages<Message>
{
public void Handle(Message message)
{
Console.WriteLine(message.Data);
}
}
public class Message : IMessage
{
public Message()
{
}
public Message(string data)
{
Data = data;
}
public string Data { get; set; }
}
In the MessageEndpointMappings you need to update it as follows:
Replace DLL with the name of the assembly containing your messages (e.g. "Messages")
Change the Endpoint to the name of the queue which System B is reading from (You can check the queue name by looking in the MSMQ snapin under private queues).
<add Messages="Messages" Endpoint="SystemB" />
NServiceBus 3 automatically creates the queue name based upon the namespace of the hosting assembly.
Additionally, you may want to look at using the NServiceBus.Host to host your handlers instead of your own console application.
I am trying to connect my application to azure with wcf role. Everything works fine until i call more than one wcf method at once. I think it is because threading. Exception is:
There was no endpoint listening at http://localhost:57579/Service1.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
I was searching how to add threading to wcf service and i found this:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
or
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall]
I tried to combine this properties but it doesnt work:(
this is my simple code:
Client:
public MainPage()
{
InitializeComponent();
service = new Service1Client();
service.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service.GetDataAsync(1);
service.GetDataAsync(2);
}
void getDataCompleted(object sender, GetDataCompletedEventArgs e)
{
if (e.Error != null)
{
}
else
{
this.textBlock1.Text = e.Result;
}
}
Server:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
I think the problem is that you're using the same client to do two operations at the same time. Have you tried spinning up two clients and asking each of them to perform the operation?
public MainPage()
{
InitializeComponent();
service1 = new Service1Client();
service1.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service1.GetDataAsync(1);
service2 = new Service1Client();
service2.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(getDataCompleted);
service2.GetDataAsync(2);
}
Note there are other ways to do the async calls that won't require as much pain with subscribing / unsubscribing the event handlers.