WCF Interface service contract instance calling a function directly - c#

I have class (named Sender) that has a member of Icommunicator interface which defines a WCF Service Contract.
public class Sender
{
private ICommunicator channel;
private ChannelFactory<ICommunicator> factory = null;
Inside the same .cs file there's a class Receiver which inherits from Icommunicator.
The interface that defines the service contract is as follow:
[ServiceContract(Namespace = "P2PComm")]
public interface ICommunicator
{
[OperationContract(IsOneWay = true)]
void PostMessage(CommMessage msg);
// used only locally so not exposed as a service method
CommMessage GetMessage();
[OperationContract]
bool openFileForWrite(string fileName);
[OperationContract]
bool writeFileBlock(byte[] block);
[OperationContract]
void closeFile();
}
Inside the Sender class there's a connect function which uses the Icommunicator channel member directly to call the PostMessage function.
// attempts to connect to Receiver instance
// attempts a finite number of times to connect to a Receiver
// first attempt to send will throw exception of no listener
// at the specified endpoint
// to test that we attempts to send a connect message
public bool connect(string toAddress)
{
int timeToSleep = 500;
CreateSendChannel(toAddress);
CommMessage connectMsg = new CommMessage(CommMessage.MessageType.connect);
connectMsg.to = toAddress;
connectMsg.from = fromAddress;
connectMsg.command = Msg.Command.connect;
while (true)
{
try
{
channel.PostMessage(connectMsg);
tryCount = 0;
lastUrl = toAddress;
return true;
}
catch (Exception ex)
{
if (++tryCount < maxCount)
{
Thread.Sleep(timeToSleep);
}
else
{
lastError = ex.Message;
lastUrl = "";
tryCount = 0;
return false;
}
}
}
}
I don't understand what is happening here I'm not inheriting from the Icommunicator interface but I'm using it to call one of its function, so which function gets called in this case ?
When I ran it with a debugger it did not step into a function, yet it was still able to send a message.

Related

Not able to send GET within a GET

Im trying to build a REST proxy as windows service. But every time my program executes a GET I receive "405 method not allowed"
Structure:
Code1 --GET--> Code2
Browser --GET--> Code1 --GET--> Code2
In the first case my code just makes a GET call to another REST server. Everything works fine.
In the second case I make a GET call from my browser to the first client and it will work as a proxy, redirecting the GET call to the second client. This doesnt work. POSTs are working, only the GET does not work.
I tried different URL paths and other URL structures.
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
namespace RUST_Console_Write
{
[ServiceContract]
public interface IService // <-- interface of second REST client
{
[OperationContract]
[WebGet(UriTemplate = "Test1/{s}")]
string Test1(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
[ServiceContract]
public interface IMITM_Service
{
[OperationContract]
[WebGet(UriTemplate = "GET1?s={s}")]
string EchoGet1(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
public class REST_CALLS
{
public static string makeGET(string s)
{
string messageResponse = "Response from other REST Service:\n";
try
{
using (ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(new WebHttpBinding(), "http://localhost:8001"))
{
channelFactory.Endpoint.EndpointBehaviors.Add(new WebHttpBehavior());
IService channel = channelFactory.CreateChannel();
Console.Write("Sending the GET... ");
messageResponse += channel.Test1(s);
Console.WriteLine("Success");
}
}
catch (Exception e)
{
Console.WriteLine("Failed");
Console.WriteLine(e);
}
return messageResponse;
}
public static string makePOST(string s)
{
string messageResponse = "Response from other REST Service:\n";
try
{
using (ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(new WebHttpBinding(), "http://localhost:8001"))
{
channelFactory.Endpoint.EndpointBehaviors.Add(new WebHttpBehavior());
IService channel = channelFactory.CreateChannel();
Console.Write("Sending the POST... ");
messageResponse += channel.EchoWithPost(s);
Console.WriteLine("Success");
}
}
catch (Exception e)
{
Console.WriteLine("Failed");
Console.WriteLine(e);
}
return messageResponse;
}
}
public class MITM_Service : IMITM_Service
{
public string EchoGet1(string s)
{
return REST_CALLS.makeGET(s); // <---- this one fails (405)
}
public string EchoWithPost(string s)
{
return REST_CALLS.makePOST(s); // <---- this one works fine
}
}
class Program
{
static void Main()
{
WebServiceHost host = new WebServiceHost(typeof(MITM_Service), new Uri("http://localhost:8000"));
ServiceEndpoint serviceEndpoint = host.AddServiceEndpoint(typeof(IMITM_Service), new WebHttpBinding(), string.Empty);
host.Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageEnabled = false;
host.Open();
Console.WriteLine("First call");
Console.WriteLine(REST_CALLS.makeGET("TEST")); // <---- this one works fine
Console.WriteLine("\nSecond call");
Console.WriteLine(REST_CALLS.makePOST("TEST")); // <---- this one works fine
Console.ReadLine();
host.Close();
}
}
}
Id really appreciate every help. Cant figure it out for my life.
(I know this isnt yet a windows service, the error is the same and its better to debug as normal program)

Check if a async call to service is still alive

I have an async service
The service contract defined like:
[ServiceBehavior(InstanceContextMode = InstanceContext.PerCall]
Myservice
My client is defined like:
MyServiceClient task= null;
InstanceContext instanceContext = new InstanceContext(this);
task = new MyServiceClient(instanceContext);
task.MyMethod();
And the client class implements the call back methods (finish, progress etc...).
It's works fine, but if I call to the method, and she start running on the server and I shut down the server,I can't know the status of my call, and the client still think that the methods still running.
So, how can I check if this call is still running?
Thanks for helpers :)
Edit:
CallBack Interface:
public interface IServiceCallback
{
[OperationContract(IsOneWay=true)]
void NotifyFinished();
[OperationContract(IsOneWay=true)]
void NotifyProgress(int x);
[OperationContract(IsOneWay=true)]
void NotifyFailed(Exception exception);
}
Service Interface:
[ServiceContract(CallbackContract = typeof (IServiceCallback)]
public interface IAsyncService
{
[OperationContract(IsOneWay=true)]
void AsyncRunning();
}
Service Class:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class AsyncService : IAsyncService
{
private IServiceCallback ServiceCallback {get; set;}
public void AsyncRunningProxy ()
{
for(int x=0; x<100 ; x++)
{
AsyncService.NotifyProgress(x);
}
}
private void EndMethod(IAsyncResult res)
{
AsyncResult result = (AsyncResult)res;
try
{
((dynamic)result.AsyncDelegate).EndInvoke(res);
AsyncService.NotifyFinished();
}
catch (Exception e)
{
AsyncService.NotifyFailed(e);
}
}
public void AsyncRunning ()
{
ServiceCallback = OperationContext.Current.GetCallBackChannel<IServiceCallback>();
Action action = AsyncRunningProxy;
action.BeginInvoke(EndMethod, null);
}
}
Client Class:
public class ServiceRunner : IServiceCallback
{
private ManualResetEvent reset {get; set;}
public ServiceRunner()
{
reset = new ManualResetEvent(false);
}
public void Run()
{
AsyncServiceClient client = null;
InstanceContext instanceContext = new InstanceContext(this);
client = new AsyncServiceClient(instanceContext);
client.AsyncRunning();
reset.WaitOne();
}
public void NotifyProgress(int x)
{
Console.WriteLine(x);
}
public void NotifyFinished()
{
}
public void NotifyFailed(Exception e)
{
Console.WriteLine(e.Message);
reset.Set();
}
}
Edit: new client Class:
Client Class:
public class ServiceRunner : IServiceCallback
{
private ManualResetEvent reset { get; set; }
private string IsRunning { get; set; }
public ServiceRunner()
{
reset = new ManualResetEvent(false);
IsRunning = true;
}
public void Run()
{
AsyncServiceClient client = null;
InstanceContext instanceContext = new InstanceContext(this);
client = new AsyncServiceClient(instanceContext);
client.AsyncRunning();
new Thread(()=>
{
while(IsRunning)
{
try
{
client.IsAlive();
Thrad.Sleep(60 * 1000);
}
catch (Exception e) // The server is not responding.
{
NotifyFailed(e);
return;
}
}
}).Start();
reset.WaitOne();
}
public void NotifyProgress(int x)
{
Console.WriteLine(x);
}
public void NotifyFinished()
{
IsRunning = false;
reset.Set();
}
public void NotifyFailed(Exception e)
{
IsRunning = false;
Console.WriteLine(e.Message);
reset.Set();
}
}
In order to have more control of your clients request to the service, you should be able to use the inbuilt Task and Async support to monitor and if necessary handle connection delays.
The support for generating Task-based operations on the client side will be available to users who rely on proxies generated by our client generation tools (svcutil.exe or Add Service Reference), as well as to users who prefer to directly use ChannelFactory
The following code provides a rough example:
Task<string> task = new MyServiceClient().MyMethod();
if (task == await Task.WhenAny(task, Task.Delay(1000)))
{
Console.WriteLine(await task);
}
else
{
// handle delay …
}
Refer to the following MSDN blog entry for more information:
http://blogs.msdn.com/b/endpoint/archive/2010/11/13/simplified-asynchronous-programming-model-in-wcf-with-async-await.aspx
Regards,
As #adkSerenity mention you may implement timeout logic, but I guess your question not about that.
The callback method will be(and should be) called in case of exception for example connection lose or internal connection time out.
private static void CallbackSample(IAsyncResult asynchronousResult)
{
try
{
// State of request is asynchronous.
RequestState myRequestState=(RequestState) asynchronousResult.AsyncState;
HttpWebRequest myHttpWebRequest2=myRequestState.request;
myRequestState.response = (HttpWebResponse);
//next line may throw exception
myHttpWebRequest2.EndGetResponse(asynchronousResult);
}
catch(WebException e)
{
}
}
So async communication looks like fire and forget. Your callback method will be called when you get the result(exception too), but if you decide not handle it(custom time out logic) you must "foret" about callback processing. No way to check is alive(except of course custom api).

C# Action/Delegate makes wcf channel become faulted when non existent method is called

I have a callback service in wcf which looks like this :
[ServiceContract(CallbackContract = typeof(IMyCallbacks), Namespace = "MyNamespace")]
public interface IMyService
{
[OperationContract]
bool subscribe();
[OperationContract]
bool unsubscribe();
}
public interface IMyCallbacks
{
[OperationContract(IsOneWay=true)]
void onNewCallback(int iValue);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
Action<int> DelegateOnNewCallback { get; set; }
public bool subscribe()
{
try
{
var wClient = OperationContext.Current.GetCallbackChannel<IMyCallbacks>();
DelegateOnNewCallback += wClient.onNewCallback;
}
catch (Exception iEx)
{
Console.Writeline(iEx.Message);
return false;
}
return true;
}
public bool unsubscribe()
{
try
{
var wClient = OperationContext.Current.GetCallbackChannel<IMyCallbacks>();
DelegateOnNewCallback -= wClient.onNewCallback;
}
catch (Exception iEx)
{
Console.Writeline(iEx.Message);
return false;
}
return true;
}
// This function is called really often
public void CallingFunction(int iValue)
{
try
{
DelegateOnNewCallback(iValue);
}
catch (Exception ex)
{
Console.Writeline(ex.Message);
}
}
}
On the client side, upon loading, I make a subscribe to the callback and print the value I receive. When the client is closed, I call the unsubscribe method. The Service is independent from the client and is never destroyed in the process.
My problem is encountered when a client process is destroyed and the unsubscribe method is not called. Every subsequent client won't receive the callback because the Wcf channel is in a faulted state. Every time CallingFunction is called, I receive the exception :
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted.
I believe it is because, since unsubscribe wasn't called properly DelegateOnNewCallback still try to call the destroyed client's method which is now unexistent.
In that particular case, I would expect to receive the exception through my Try/Catch however, I wouldn't expect the service to go in faulted state.
The behavior I would want is, when CallingFunction is called, it would try to call every method DelegateOnNewCallback contains and if a method doesn't exist anymore, silently remove it from the list and continue invoking the subsequent methods.
How can I achieve this ?

Why do I get a WCF timeout even though my service call and callback are successful?

I'm playing around with hooking up an in-game console to a WCF interface, so an external application can send console commands and receive console output. To accomplish this I created the following service contracts:
public interface IConsoleNetworkCallbacks
{
[OperationContract(IsOneWay = true)]
void NewOutput(IEnumerable<string> text, string category);
}
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IConsoleNetworkCallbacks))]
public interface IConsoleInterface
{
[OperationContract]
void ProcessInput(string input);
[OperationContract]
void ChangeCategory(string category);
}
On the server I implemented it with:
public class ConsoleNetworkInterface : IConsoleInterface, IDisposable
{
public ConsoleNetworkInterface()
{
ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler);
}
public void Dispose()
{
ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
}
public void ProcessInput(string input)
{
ConsoleManager.Instance.ProcessInput(input);
}
public void ChangeCategory(string category)
{
ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler, category);
}
protected void OutputHandler(IEnumerable<string> text, string category)
{
var callbacks = OperationContext.Current.GetCallbackChannel<IConsoleNetworkCallbacks>();
callbacks.NewOutput(text, category);
}
}
On the client I implemented the callback with:
public class Callbacks : IConsoleNetworkCallbacks
{
public void NewOutput(IEnumerable<string> text, string category)
{
MessageBox.Show(string.Format("{0} lines received for '{1}' category", text.Count(), category));
}
}
Finally, I establish the service host with the following class:
public class ConsoleServiceHost : IDisposable
{
protected ServiceHost _host;
public ConsoleServiceHost()
{
_host = new ServiceHost(typeof(ConsoleNetworkInterface), new Uri[] { new Uri("net.pipe://localhost") });
_host.AddServiceEndpoint(typeof(IConsoleInterface), new NetNamedPipeBinding(), "FrbConsolePipe");
_host.Open();
}
public void Dispose()
{
_host.Close();
}
}
and use the following code on my client to establish the connection:
protected Callbacks _callbacks;
protected IConsoleInterface _proxy;
protected void ConnectToConsoleServer()
{
_callbacks = new Callbacks();
var factory = new DuplexChannelFactory<IConsoleInterface>(_callbacks,
new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/FrbConsolePipe"));
_proxy = factory.CreateChannel();
_proxy.ProcessInput("Connected");
}
So what happens is that my ConnectToConsoleServer() is called and then it gets all the way to _proxy.ProcessInput("Connected");. In my game (on the server) I immediately see the output caused by the ProcessInput call, but the client is still stalled on the _proxy.ProcessInput() call.
After a minute my client gets a JIT TimeoutException however at the same time my MessageBox message appears.
So obviously not only is my command being sent immediately, my callback is being correctly called. So why am I getting a timeout exception?
Note: Even removing the MessageBox call, I still have this issue, so it's not an issue of the GUI blocking the callback response.
You need to specify CallbackBehavior for your client class implementing the Callback interface
[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, UseSynchronizationContext=false)]
See the following for a better explanation
http://www.switchonthecode.com/tutorials/wcf-callbacks-hanging-wpf-applications
It's possible that it's your _proxy.ProcessInput("Connected") which is blocking the call - this is consistent with your timeout experience, as the server sends the response immediately, but the client can't receive it as it's stuck on "ProcessInput". When your call finally times out, the blocking call terminates, at which point the callback completes.
To verify this, could you try invoking using this (non blocking) call instead?
((Action)(() => _proxy.ProcessInput("Connected"))).BeginInvoke(null, null);

Consumed WCF service returns void although return type (& value) specified

I have a WCF service that I am attempting to connect to via a console application for testing (although will move to WPF for the final interface). I have generated the proxy, added the service reference to my project in visual studio and I can see all the methods I have created in my WCF interface:
SupportStaffServiceClient client = new SupportStaffServiceClient("WSHttpBinding_ISupportStaffService");
client.myMethod(message);
However when I call a method, which in the WCF interface is specified as returning a value, the method returns void in the console application.
client.getMethod(message);
The WCF service method is definitely returning a message, I'm just unsure as to why the client cannot "see" the return.
[service code]
[ServiceContract(Namespace="http://localhost/supportstaff")]
public interface ISupportStaffService
{
[OperationContract]
TutorMessage AddTutor(TutorMessage message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SupportStaff : ISupportStaffService
{
private ITutorService tutors;
public SupportStaff()
{
// Create the binding
WSHttpBinding logBind = new WSHttpBinding();
// Create the channel factory to the logging service
ChannelFactory<ILogger> logFactory = new ChannelFactory<ILogger>(logBind, "http://localhost:8000/logger");
// Create the connection to the logging service
this.logger = logFactory.CreateChannel();
// Create the binding
WSHttpBinding tutorBind = new WSHttpBinding();
// Create the channel factory to the Tutor service
ChannelFactory<ITutorService> tutorFactory = new ChannelFactory<ITutorService>(tutorBind, "http://localhost:8001/tutors");
// Create the connection to the Tutor service
this.tutors = tutorFactory.CreateChannel();
}
TutorMessage ISupportStaffService.AddTutor(TutorMessage message)
{
// First log that we have received an add Tutor message
// Create a log message
LogMessage logMessage = new LogMessage();
logMessage.Time = message.Time;
logMessage.Message = "[Supprt Staff Service] Add Tutor message received";
// Send the log message to the logging service
logger.Log(logMessage);
// Create a request to add the Tutor to the Tutor service
TutorMessage request = new TutorMessage();
request.Time = DateTime.Now;
request.Tutor = message.Tutor;
// Send the add Tutor message to the Tutor message
tutors.AddTutor(request);
// Display the message
Console.WriteLine("Added Tutor " + message.Tutor.Number);
// Log the message
logMessage = new LogMessage();
logMessage.Time = DateTime.Now;
logMessage.Message = "[Support Staff Service] Added Tutor " + message.Tutor.Number;
logger.Log(logMessage);
// Create the return message
TutorMessage toReturn = new TutorMessage();
toReturn.Time = DateTime.Now;
toReturn.Tutor = message.Tutor;
// Return the return message
return toReturn;
}
}
[ServiceContract(Namespace = "http://localhost/tutors")]
public interface ITutorService
{
[OperationContract]
void AddTutor(TutorMessage message);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class TutorService : ITutorService
{
private Dictionary<string, Tutor> tutors = new Dictionary<string, Tutor>();
void ITutorService.AddTutor(TutorMessage message)
{
// First log the fact that we have received an Add message
// Create the log message
LogMessage logMessage = new LogMessage();
logMessage.Time = message.Time;
logMessage.Message = "[Tutor Service] Tutor add message received";
// Send the log message to the logging service
logger.Log(logMessage);
// Now add the new Tutor to the collection of Tutors
tutors[message.Tutor.Number] = message.Tutor;
// Display message that Tutor is added
Console.WriteLine("Added tutor : " + message.Tutor.Number);
// Log the new Tutor
logMessage = new LogMessage();
logMessage.Time = DateTime.Now;
logMessage.Message = "[Tutor Service] Added tutor : " + message.Tutor.Number;
logger.Log(logMessage);
}
}
[client code]
class Program
{
static void Main(string[] args)
{
SupportStaffServiceClient client = new SupportStaffServiceClient("WSHttpBinding_ISupportStaffService");
try
{
localhost.tutor.tutor t1 = new localhost.tutor.tutor();
t1.name = "Big Dave";
t1.number = "t123";
DateTime time = DateTime.Now;
client.AddTutor(ref time, ref t1);
localhost.tutor.tutor t2 = new localhost.tutor.tutor();
client.RetrieveTutor(ref time, ref t1);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message.ToString());
}
finally
{
Console.WriteLine("Press <RETURN> to exit");
Console.ReadLine();
}
}
}
[svcutil generated code]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SupportStaffServiceClient : System.ServiceModel.ClientBase<ConsoleApplication1.SupportStaffService.ISupportStaffService>, ConsoleApplication1.SupportStaffService.ISupportStaffService {
public SupportStaffServiceClient() {
}
public SupportStaffServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public SupportStaffServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public SupportStaffServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public SupportStaffServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public string HelloWorld(string name) {
return base.Channel.HelloWorld(name);
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
ConsoleApplication1.SupportStaffService.TutorMessage ConsoleApplication1.SupportStaffService.ISupportStaffService.AddTutor(ConsoleApplication1.SupportStaffService.TutorMessage request) {
return base.Channel.AddTutor(request);
}
public void AddTutor(ref System.DateTime time, ref ConsoleApplication1.SupportStaffService.tutor tutor) {
ConsoleApplication1.SupportStaffService.TutorMessage inValue = new ConsoleApplication1.SupportStaffService.TutorMessage();
inValue.time = time;
inValue.tutor = tutor;
ConsoleApplication1.SupportStaffService.TutorMessage retVal = ((ConsoleApplication1.SupportStaffService.ISupportStaffService)(this)).AddTutor(inValue);
time = retVal.time;
tutor = retVal.tutor;
}
}
I've never seen svcutil generate a method with ref parameters before - how did it do that? Anyway, it looks like you want to call the method above that in the generated code - this one takes and returns a TutorMessage object. So you could do
TutorObject returnedTutor = client.AddTutor(inputTutorObject);
Or, it looks like if you call the method with the ref parameters, as you're currently doing, the "return" value is put into those same ref parameters. So you pass in time and t1, call AddTutor, and now those variables you've passed in will contain the returned values. So, you could do
t1.name = "Big Dave";
t1.number = "t123";
DateTime time = DateTime.Now;
client.AddTutor(ref time, ref t1);
// time now contains the returned DateTime from the service
// t1 now contains the returned Tutor from the service
I had a similar problem where we'd forgottent to mark a custom MessageContract on our Response Class with the MessageBodyMemberAttribute our messageResponse Class didn't expose any members in it's data contract thus the Call to the service returned void.
Before...
[MessageContract]
public class MyCustomResponse
{
public string Response { get; set; }
}
...
After...
[MessageContract]
public class MyCustomResponse
{
[MessageBodyMember(Namespace = "http://MyNamespace")]
public string Response { get; set; }
}
After adding the MessageBodyMember to the Response member, the svcutil generates code that hides the details of the custom Message Contract and just returns the Response as a string return value from my service's proxy.
I had the same problem with outer service (couldn't change its notation). I've added /mc parameter to svcutil - it helped.

Categories