i am new in wcf. so often read basic tutorial & guide line from many site on wcf. i saw people design their wcf service with special attribute like [OperationContract(IsOneWay=true)]
[ServiceContract]
public interface IArticleService
{
[OperationContract(IsOneWay=true)]
void OneWayMethod();
}
after reading on this one-way operation i understand what it is as follow....
When an operation has no return value, and the client does not care about the success or failure of the invocation. WCF offers one-way operations to support this sort of fire-and-forget invocation,: once the client issues the call, WCF generates a request message, but no correlated reply message will ever return to the client
i like to know if i do not specify IsOneWay=true or IsOneWay=false then IsOneWay=true is default. just tell me what happen when we do not specify this attribute IsOneWay=true ?
or specify like IsOneWay=false
thanks
UPDATE
i read a write up from this url http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.isoneway%28v=vs.110%29.aspx and understand what is the meaning of IsOneWay=true or IsOneWay=false
[ServiceContract]
public class OneAndTwoWay
{
// The client waits until a response message appears.
[OperationContract]
public int MethodOne (int x, out int y)
{
y = 34;
return 0;
}
// The client waits until an empty response message appears.
[OperationContract]
public void MethodTwo (int x)
{
return;
}
// The client returns as soon as an outbound message
// is queued for dispatch to the service; no response
// message is generated or sent.
[OperationContract(IsOneWay=true)]
public void MethodThree (int x)
{
return;
}
}
IsOneway is false by default and you have to explicitly set it to true if you want your operation to be a one way
Check this out :
http://msdn.microsoft.com/en-us/library/ms733035(v=vs.110).aspx
Related
I use WCF to async communicate between 2 processes.
till now I implemented the IAsyncResult pattern, and did it by having 3 methods:
BeginOperation - client.BeginOperation, when service receive it queue the job on threadpool with delegate for Operation
Operation - run on service side
EndOperation - this is what client callback.
My question is, I want to send strings from client to service, I want the send to be async, AND I dont want to get response - just want the service to print the string.
Is this enough ? This must be Non-Blocking
[OperationContract(IsOneWay = true)]
void PrintString(string message);
OR i need to do as following:
[OperationContract(IsOneWay = true, AsyncPattern=true)]
void BeginPrintString(string message, AsyncCallback callback, object state);
void EndPrintString(IAsyncResult asyncResult);
IsOneWay should be enough, but it still can block your client in specific circumstances, as well as throw errors.
See this and this posts for more details:
General things you should keep in mind about OneWay operations -
O/W operations must return void. O/W operations can still yield
exceptions. invoking an operation on the client channel might still
throw an exception if it couldn’t transmit the call over to the
service. O/W operations can still block. if the service is pumped with
messages and a queue had started, calling O/W operation may block your
following code.
You can make it more asynchronous by using a separate thread to do your work.
Instead of:
public void MyOneWayServiceOperation() {
// do stuff
}
do something like:
public void MyOneWayServiceOperation() {
new Thread(() => {
// do stuff
}).Start();
}
The service operation will have been executed on a new thread anyway, so it shouldn't cause any more problems for your code to be on a different new thread.
You can add a Thread.Sleep() call before your work if you want the service operation to have completed before you begin. This allowed me to quit the service from a service operation without having an exception thrown.
i am very new in WCF. so often gaze for wcf code & article. after viewing many code i often stuck for very basic things and got no elaborate discussion for the below question. so here are my few basic question....and looking for details discussion with sample situation and with sample code.
[OperationContract(IsInitiating=false, IsOneWay=false)]
bool Add_Contact(int sessionkey, string Newusrname);
What is the meaning of IsInitiating=false or true. when i should set it true or false ? what is the meaning of IsOneWay=false or true. when i should set it true or false ?
i belief my question are very basic and lots of scholar every time monitoring this forum. i hope i will get the best answer in details with many situation like when one should choose which option over other option with few sample code for simulating situations. thanks
IsInitiating
The IsInitiating parameter specifies whether or not an operation implemented by the associated method
can initiate a session on the server. Session instancing is the ability to have separate instances of a class
be maintained for each client channel. This property controls whether an operation is allowed to be the
first operation called when a session is created. The default for this parameter is true, meaning that the
specified operation can be the first called on a channel. In this scenario, all following calls to this method
have no effect (meaning, no other sessions are created). If this parameter is set to false, the client is forced
to call other methods prior to calling this method.
This comes in handy when you are trying to set an “order of operation,” meaning that you need a specific
method to be called first because the other methods called depend on something returned from the
first method.
For example, the following contains three methods, or service operations. The first operation creates the
session and must be the first method called. The final operation, Logout, closes the session:
[ServiceContract]
public interface IBuyStock
{
[OperationContract(IsInitiating = true, IsTerminating = false)]
void Login(user);
[OperationContract(IsInitiating = false, IsTerminating = false)]
void BuyStock(string stocksymbol, int quantity);
[OperationContract(IsInitiating = false, IsTerminating = true)]
void Logout(user);
}
Once the initiating method has been called, subsequent calls can be made to that method with no effect
to its initiating properties.
If any method other than the initiating method is called first, the following error is returned:
The operation ‘operationname’ cannot be the first operation to be called because
IsInitiating is false.
The initiating method must be called first, then other operations can be called.
IsOneWay
Service communication by default is bi-directional. Bi-directional service communication means that a
service operation can receive incoming messages and send a reply.
The IsOneWay parameter specifies whether a service operation returns a reply message. The default
value for this parameter is false, meaning that the method does not return a reply message.
The following example illustrates a one-way communication:
[ServiceContract]
public interface IBuyStock
{
[OperationContract(IsOneWay = true)]
void Login(user);
[OperationContract(IsOneWay = false)]
void BuyStock(string stocksymbol, int quantity);
}
In a one-way communication, the client initiates the communication and continues code execution and
does not wait for a response from the service. In a two-way communication, it waits for a response from
the service before continuing code execution.
The downside to using one-way communication is that the caller has no way of knowing whether or not
the service processed the message successfully.
Any methods that return a value where the IsOneWay property is set to false will return an exception.
IsTerminating
The IsTerminating property specifies whether a called service operation is to terminate the communication
session. The following example shows the last call,
Logout(), has the IsTerminating property set to true:
[ServiceContract]
public interface IBuyStock
{
[OperationContract(IsInitiating = true, IsTerminating = false)]
void Login(user);
[OperationContract(IsInitiating = false, IsTerminating = false)]
void BuyStock(string stocksymbol, int quantity);
[OperationContract(IsInitiating = false, IsTerminating = true)]
void Logout(user);
}
When the IsTerminating property is set to true, the session is closed after the reply message is sent (if
a reply message needs to be sent). On the client side, an IsTerminating value of true tells WCF to close
the channel only after the reply arrives at the client.
[OperationContract(IsInitiating = true, IsTerminating = false)]
Blockquote
In above code IsInitiating property is set to true when we want to create session .
Blockquote
We know login method is called first before other methods,hence we
use IsInitiating = true for login method and for other methods we set it as false.
Blockquote
In the same way we use Isterminating=True for logout method then session is deleted.
The question pretty much sums it up. I have a WCF service, and I want to wait until it finished to do something else, but it has to be until it finishes. My code looks something like this. Thanks!
private void RequestGeoCoordinateFromAddress(string address)
{
GeocodeRequest geocodeRequest = new GeocodeRequest();
GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
geocodeService.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);
// Make the geocode request
geocodeService.GeocodeAsync(geocodeRequest);
//if (geocodeResponse.Results.Length > 0)
// results = String.Format("Latitude: {0}\nLongitude: {1}",
// geocodeResponse.Results[0].Locations[0].Latitude,
// geocodeResponse.Results[0].Locations[0].Longitude);
//else
// results = "No Results Found";
// wait for the request to finish here, so I can do something else
// DoSomethingElse();
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
bool isErrorNull = e.Error == null;
Exception error = e.Error;
try
{
double altitude = e.Result.Results[0].Locations[0].Latitude;
double longitude = e.Result.Results[0].Locations[0].Longitude;
SetMapLocation(new GeoCoordinate(altitude, longitude));
}
catch (Exception ex)
{
// TODO: Remove reason later
MessageBox.Show("Unable to find address. Reason: " + ex.Message);
}
}
There is a pattern, supported by WCF, for a call to have an asynchronous begin call, and a corresponding end call.
In this case, the asynchronous methods would be in the client's interface as so:
[ServiceContract]
interface GeocodeService
{
// Synchronous Operations
[OperationContract(AsyncPattern = false, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
GeocodeResults Geocode(GeocodeRequestType geocodeRequest);
// Asynchronous operations
[OperationContract(AsyncPattern = true, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
IAsyncResult BeginGeocode(GeocodeRequestType geocodeRequest, object asyncState);
GeocodeResults EndGeocode(IAsyncResult result);
}
If you generate the client interface using svcutil with the asynchronous calls option, you will get all of this automatically. You can also hand-create the client interface if you aren't using automatically generating the client proxies.
The End call would block until the call is complete.
IAsyncResult asyncResult = geocodeService.BeginGeocode(geocodeRequest, null);
//
// Do something else with your CPU cycles here, if you want to
//
var geocodeResponse = geocodeService.EndGeocode(asyncResult);
I don't know what you've done with your interface declarations to get the GeocodeAsync function, but if you can wrangle it back into this pattern your job would be easier.
You could use a ManualResetEvent:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
Obviously doing this makes absolutely no sense, so the question here is: why do you need to do this? Why using async call if you are going to block the main thread? Why not use a direct call instead?
Generally when using async web service calls you shouldn't block the main thread but do all the work of handling the results in the async callback. Depending of the type of application (WinForms, WPF) you shouldn't forget that GUI controls can only be updated on the main thread so if you intend to modify the GUI in the callback you should use the appropriate technique (InvokeRequired, ...).
Don't use this code with Silverlight:
private ManualResetEvent _wait = new ManualResetEvent(false);
private void RequestGeoCoordinateFromAddress(string address)
{
...
_wait = new ManualResetEvent(false);
geocodeService.GeocodeAsync(geocodeRequest);
// wait for maximum 2 minutes
_wait.WaitOne(TimeSpan.FromMinutes(2));
// at that point the web service returned
}
private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
...
_wait.Set();
}
When we call _wait.WaitOne(TimeSpan.FromMinutes(2)), we are blocking the UI thread, which means the service call never takes place. In the background, the call to geocodeService.GeocodeAsync is actually placed in a message queue, and will only be actioned when the thread is not executing user code. If we block the thread, the service call never takes place.
Synchronous Web Service Calls with Silverlight: Dispelling the async-only myth
The Visual Studio 11 Beta inludes C# 5 with async-await.
See Async CTP - How can I use async/await to call a wcf service?
It makes it possible to write async clients in a 'synchronous style'.
I saw one guy did use ManualReset and waitAll, but he had to wrap all code inside of ThreadPool..
It is very bad idea...thought it works
I have the following situation: My WCF service allows a client to register to wait for some event. The waiting is asynchronous on the service side, that is, the waiter is registered and when the process is finished, the waiter is notified. At the moment, it's simply a ManualResetEvent.
Now I want to expose this method via WCF. I tried to use AsyncPattern=true and created two methods, BeginWait which bundles the event into a IAsyncResult, and EndWait which calls AsyncWaitHandle.WaitOne(). However, if I call BeginWait, EndWait from the client, the server side EndWait is not executed. I'm using a manually implemented wrapper (my proxy class is derived from ChannelBase<IWaitService>, IWaitService), which basically calls Channel.EndWait(), and this function is indeed called; but on the server side, the call never arrives.
What am I doing wrong here? Follow-up question: If the asynchronous call is working, is there an easy way to make that synchronous on the client side?
The line
var task = Task.Factory.StartNew(() => IsPrime(a));
uses overload
TaskFactory.StartNew(Action)
which results in
((IAsyncResult)task).AsyncState == null
the call to callback(task) results in an ArgumentException, complaining that the state object is different from the state object that was passed to the BeginXxx method. The line must be modified to
var task = Task.Factory.StartNew((actionState) => IsPrime(a), state);
using overload
TaskFactory.StartNew(Action<object>, object)
such that the state object passed by WCF ends up in the task:
((IAsyncResult)task).AsyncState.GetType().FullName == System.ServiceModel.Dispatcher.MessageRpc+Wrapper
The synchronous/asynchronous decision can be made independently on the server or client side. Calling EndWait on the client does not translate into an EndWait call on the server. I would recommend testing an async service with a sync client just to keep things simple and avoid confusion.
I would further recommend that you not call WaitOne inside of the EndWait method. The contract is that this method will only be called after the IAsyncResult tells the framework that it is done. This is done in one of three ways:
CompletedSynchronously returns true
The AsyncCallback is invoked
The AsyncWaitHandle is signalled
CompletedSynchronously should only return true if BeginWait had enough information to complete the request before it returned. This is probably not the case. You can satisfy the other two conditions with your ManualResetEvent as follows:
class EventBasedAsyncResult : IAsyncResult
{
private readonly ManualResetEvent _manualResetEvent;
private readonly AsyncCallback _asyncCallback;
private readonly object _asyncState;
public EventBasedAsyncResult(AsyncCallback callback, object asyncState)
{
_manualResetEvent = new ManualResetEvent(false);
_asyncState = asyncState;
_asyncCallback = callback;
}
public void WaitCompleted()
{
_manualResetEvent.Set();
_asyncCallback(this);
}
public object AsyncState
{
get { return _asyncState; }
}
public WaitHandle AsyncWaitHandle
{
get { return _manualResetEvent; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return _manualResetEvent.WaitOne(0); }
}
}
I think once you do this you'll find that EndWait is called, even if the client is synchronous.
I'm trying to implement a reconnect logic for a wcf client. I'm aware that you have to create a new channel after the current channel entered the faulted state. I did this in a channel faulted event handler:
internal class ServiceClient : DuplexClientBase, IServiceClient
{
public ServiceClient(ICallback callback, EndpointAddress serviceAddress)
: base(callback, MyUtility.GetServiceBinding("NetTcpBinding"), serviceAddress)
{
// Open the connection.
Open();
}
public void Register(string clientName)
{
// register to service
}
public void DoSomething()
{
// some code
}
}
public class ClientApp
{
private IServiceClient mServiceClient;
private ICallback mCallback;
public ClientApp()
{
mServiceClient = new ServiceClient( mCallback, new EndpointAddress("someAddress"));
mServiceClient.Register();
// register faulted event for the service client
((ICommunicationObject)mServiceClient).Faulted += new EventHandler(ServiceClient_Faulted);
}
void ServiceClient_Faulted(object sender, EventArgs e)
{
// Create new Service Client.
mServiceClient = new ServiceClient( mCallback, new EndpointAddress("someAddress"));
// Register the EI at Cell Controller
mServiceClient.Register();
}
public void DoSomething()
{
mServiceClient.DoSomething();
}
}
But in my unit test I still get a "The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state" exception.
Is it possible that the callback channel is still faulted and if yes how can I replace the callback channel?
so far I have experienced that a WCF connection needs to be recreated on fault - there doesn't seem to be a way to recover it otherwise. As for when a fault occurs, the method seems to fire fine, but often it fires and cleans up the WCF connection (establishing a new one, etc) as the current request is going through - causing this to fail - especially true on timeouts.
A couple of suggestions:
- If it is timeout related, keep track of the last time a call was made and a constant containing the timeout value. If the WCF connection will have been dropped due to inactivity, drop it and recreate it before you send the request over the wire.
- The other thing, it looks like you are not re-adding the fault handler, which means the first fault will get handled, but the second time it faults it will fall over without a handler cause no new one has been attached.
Hope this helps
Have you tried to reset the communications channel by calling mServiceClient.Abort in the Faulted event handler?
Edit:
I see that you do not reinitialize the mCallback object in your recovery code. You may need to assign it to a new instance.