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.
Related
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.
I've a Duplex TCP IP WCF service. I'm currently unit-testing it.
In everyone of my test, I setup a new server, create a new ChannelFactory, create the InstanceContext and do the call.
Then I trigger the event(it's a Mock on the server side), and the server give me this exception when it tries to reach the client:
Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
Additional information: Cannot access a disposed object.
Important point, this happens ONLY when I run all the tests in a row(sequentially executed but in the same execution).
There is nothing special about my service:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IMyServiceCallback))]
public interface IMyService{
[OperationContract]
void SomeVariousMethods();
}
[ServiceContract]
public interface IMyServiceCallback
{
[OperationContract]
void HandleMessageFromServer(String message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService{
public MyService(ISomeServerComponent component){
component.OnMessage += OnMessageReceived;
}
public void SomeVariousMethods(){
//...
}
private void OnMessageReceived(object sender, EventArgs<String> e){
IMyServiceCallback callback = OperationContext.Current.GetCallbackChannel<IMyServiceCallback>();
callBack.HandleMessageFromServer(e.Data);//Crash here
}
}
And here is how I'm currently UnitTesting it(not exactly, I've a lot of this that has been extracted in some helpers:
[TestFixture]
public class MyServiceTest:IMyServiceCallback{
private Mock<ISomeServerComponent> _mock;
[OneTimeSetUp]
public void Setup(){
//... Creating a mock for the ISomeServerComponent that the MyService receives
}
[Test]
public void TestSomeVariousMethods(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
service.SomeVariousMethods();
}
}
}
[Test]
public void TestCallback(){
string serviceName = nameof(TestSomeVariousMethods);
using(ServiceHost host = CreateServer(_mock.Object,serviceName)){
using (IMyService service = CreateClient(serviceName, this)){
_mock.TriggerCallBack();
//Assert-that-the-flag-has-been-set
}
}
}
public void HandleMessageFromServer(String msg){
//Flag that this method has been called
}
private ServiceHost CreateServer(ISomeServerComponent mock, string serviceName){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Any, 9999, serviceName));
ServiceEndpoint serviceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(IMyService)), binding, uri);
serviceEndpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
serviceHost.AddServiceEndpoint(serviceEndpoint);
return serviceHost;
}
private IMyService CreateClient(string serviceName, IMyServiceCallback callback){
UnityServiceHost serviceHost = new UnityServiceHost(m_container);//This extends ServiceHost to be able to inject some objects to my services
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ReliableSession.Enabled = true;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.MaxBufferPoolSize = Int64.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/{2}", IPAddress.Loopback, 9999, serviceName));
InstanceContext context = new InstanceContext(callBack);
DuplexChannelFactory channelFactory = new DuplexChannelFactory<T>(context, binding, new EndpointAddress(uri));
return channelFactory.CreateChannel()
}
}
Funny part is that all of this works when I'm ONLY running TestCallback test, but if I run all the test of the class, it fails, like if the second time, the InstanceContext was not creating properly the callback.
Any idea how to avoid this?
I finally found the issue. I feel a little bit stupid, but in fact, in the Service implementation, I was not unregistering from the OnMessage correctly, so when the event was triggered, the previous service instance were trying to communicate with the already closed client.
So here's how it is.
There is a WCF service. I've generated a proxy for it by "Add Service Reference" with task-based operations.
Endpoint address for that service might change for different users. I have no control over this service, vendor just does that this way.
Then I wrap that service into another type and through that type interaction with WCF service occurs.
It all looks like this:
//Generated code
public partial class MyServiceClient: System.ServiceModel.ClientBase<IMyService>, IMyService
{
public async Task<ResultDataContractType> GetResultsAsync(ArgsDataContractType args)
{
return base.Channel.GetResultsAsync(args);
}
}
...
...
...
//end of generated code
public class ClientFactory
{
public static IMyService CreateClient(string url)
{
var binding = new BasicHttpBinding();
var address = new EndpointAddress(url);
var client = new MyServiceClient(binding, address);
return client;
}
}
public class Wrapper()
{
public async Task<ResultType> GetResultsAsync(string url, ArgsType args, CancelationToke cancelationToken)
{
var client = ClientFactory.CreateClient(url);
try
{
cancellationToken.Register(target =>
{
var communicationObject = target as ICommunicationObject;
if (communicationObject != null)
{
communicationObject.Abort();
}
}, client);
ArgsDataContractType requestArgs = MapArgs(args);
ResultDataContractType result = await client.GetResultsAsync(args);
}
}
}
public class Consumer
{
public async void DoWork()
{
var args = new ArgsType
{
...
};
var cts = new CancellationTokenSource()
var wrapper = new Wrapper();
Task<ResultType> task = wrapper.GetResultsAsync("http://someaddress.com", args, cts.Token);
cts.Cancel(); //This is made intentionaly, normaly there is timeout timespan for token source
await task;
...
...
...
}
}
Consumer is actually the NUnit unit test, but calling the same code from ASP.NET application would also end up in a deadlock. It gets stuck on await task;
What I have noticed, that if I would set MyServiceClient.CacheSetting = CacheSetting.AlwaysOn; will make that code run without deadlocking.
Also, if I would configure MyServiceClient from App.config or Web.config will make code running without deadlocking. But if I would set MyServiceClient.CacheSetting = CacheSetting.AlwaysOff; before instantiating MyServiceClient this code will deadlock.
Also, configuring awaiter like this:
ResultDataContractType result = await client.GetResultsAsync(args).ConfigureAwait(false)
Will make code run without deadlocking.
Could you please enlighten me with any idea why's that deadlock doesn't happens when ChannelFactory for MyServiceClient is cached, and will happen if it is not cached?
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.
I'm trying to set up a simple duplex service whereby clients connect to the server. Any connected client may execute the BookAdded service operation. When this occurs the server is supposed to raise a callback on all connected clients to notify them of the change.
The callback seems to be working fine except that the callback operation needs to run something on the UI thread using Dispatcher.BeginInvoke.
In my case Console.WriteLine("Callback thread") gets executed buy Console.WriteLine("Dispatcher thread") does not. What is the reason for this?
My service contract:
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void BookAdded(string bookId);
}
[ServiceContract(
CallbackContract = typeof(ICallback),
SessionMode = SessionMode.Required)]
public interface IService
{
[OperationContract]
bool BookAdded(string bookId);
}
My service implementation:
[ServiceBehavior(
UseSynchronizationContext = false,
InstanceContextMode = InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IService
{
public bool BookAdded(string bookId)
{
try
{
Console.WriteLine("Client Added Book " + bookId);
foreach (ICallback callback in connectedClients)
{
callback.BookAdded(bookId);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return true;
}
}
My client implementation:
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallBack: ICallback, IDisposable
{
private Dispatcher theDispatcher;
private InstanceContext context;
private WcfDuplexProxy<IService> proxy;
[ImportingConstructor]
public MyCallBack()
{
theDispatcher = Dispatcher.CurrentDispatcher;
context = new InstanceContext(this);
proxy = new WcfDuplexProxy<IService>(context);
proxy.Connect();
}
public IService Service
{
get
{
return proxy.ServiceChannel;
}
}
public void CallServiceOperation()
{
Service.BookAdded("BOOK1234");
}
public void BookAdded(string bookId)
{
Console.WriteLine("Callback thread");
theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
}
public void Dispose()
{
Service.Disconnect();
proxy.Close();
}
What I suspect is happening is that the UI thread is still blocked on the original call to the server witch hasn't finished yet. I think if you change the concurrencymode on the client to reentrant it could work. . What you need to do is set [CallbackBehavior(UseSynchronizationContext = false)] on the callback.
This article explains this issue quite well.
GJ
I think I have encountered similar issue with yours. I resolved it with a new thread to invoke Dispatcher.beginInvoke. As I understand, the UI thread sends request to Service, the Service will invoke callback contract that implements in your client during the service operation. So if in callback operation it invoke a control of UI thread which is pending to wait response from Service operation. This is why the client is deadlocked. So you can try code below: Thread th=new Thread(new ThreadStart(()=>{Console.WriteLine("Callback thread");
theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
})); th.Start();