I've a service which should initially immediately return a result, then after a query time of around 2 minutes there is an additional response ready.
How to implement single-request/multiple-responses with WCF?
Best option would be to retrieve the initial result sync and the second result async, however, both async is also okay.
My only idea so far is to use a callback (duplex channel), however, with the new async features there is maybe a better way to implement such a service?
You can use IEnumerable interface with streamed service. You can check following link.
http://weblogs.asp.net/cibrax/streaming-large-content-with-wcf-and-deferred-execution
Related
I am working on SOAP-client in WCF to communicate with a self-hosted WCF service for remote controlling a piece of software that I am developing. This software has a very long running operation (lets call it Print) that will run for several minutes, perhaps up to an hour. I am trying to figure out how to implement the method Print given the following requirements:
The server should be able to raise FaultExceptions to the client, in case something goes wrong.
The client should be informed ASAP should the connection to the service be lost.
The server-side process of Print should continue to run if disconnected, so that the client can reconnect and continue to monitor the process and abort it if necessary.
Since I am new to WCF, I am unsure how to implement this. I currently see two alternatives:
Make Print an async method so that I can "fire and forget" it until it finishes or throws a FaultException. This seems straight-forward, but I see this "problem": There is a client-side request timeout in WCF with default value of 1 minute, which also applies to async methods (if I am not mistaken) and which I would therefore have to increase significantly. This seems a bit like a hack.
Implement the async behavior of Print myself by splitting its behavior into a non-async method StartPringing that starts a server-side task for printing and returns directly (or throws an exception in case something goes wrong) and a client-callback method PrintingFinished. I could then use the callback PrintingFinished to signal to the client, when the print-process has finished or a use an additional callback PrintingFailed to send an exceptions in case something goes wrong. This implementation would be "hidden" behind the async method Print, so that it behaves like any other async method that might throw an exception. Here I see the following challenge: I will have to implement the whole exception callback-stuff myself, to handle exceptions that occur after StartPringing has returned (from StartPringing itself I can throw FaultExceptions).
For both cases I will have to work out how to detect, when the connection is servered (which I am currently doing using a ping method on the service) and then somehow get that event to throw an exception from within the method Print. Implementation-wise this seems more aligned with alternative (2), since I need to already implement all the other event handlers for when the print-process finishes or an exception is thrown. However I am unsure how I would implement this for alternative (1).
So which one of the two alternatives is "better". By better I mean the following considerations:
1. Aligned with the "standard" way in WCF for implementing such a long running method.
2. Maintainability and extensibility.
If I should consider any other alternative, I would be grateful for any other suggestion.
For what I understand of your problem I think if you need a real async communication with reliability to use a message queue like MSMQ. You can use it with WCF : https://msdn.microsoft.com/en-us/library/ms789048(v=vs.110).aspx
Update
In your case, you can use a SOAP call to send print command to the server because it sync and you need to know if the server handle the request. After in the printing operation is long and async. When this operation finish (exception or not) it need to notify client(s). But client could be shutdown for example. For that communication a Message Queue is the solution, MQ ensure that the message will be transmit.
https://en.wikipedia.org/wiki/Message_queue
If you don't want use MSMQ, you can implement a web service on client side to be notified by the printing server, using for example a UUID to match call and notification in a map in memory or in a Data Base.
I am dealing with a web-service call that may take anywhere from a few seconds to several minutes to complete. It constructs the requested data and returns it. Right now for a long-running call into the WS the user interface (WinForms) becomes unresponsive; the user has no way to cancel the operation.
The ideal approach to solving this (I think) would be to break the operation into two web-service calls: first a request, second to get the status or available data.
But if the web-service structure cannot be changed, what is the best way to interrupt the web-service call?
UPDATE:
The WS call could be made asynchronously. If the user wants to cancel the operation, then I'd like to relieve the server of unfinished work (rather than letting the thread complete normally and throw away the response). Thread.Abort() is a possibility but I want to know if there is a better way.
The web services I am working with are WCF based. The operations are read-only, so there is nothing to undo if interrupted.
You can generate Asynchronous proxy class to implement this feature.
Please look at the following link for sample,
http://msdn.microsoft.com/en-us/library/wyd0d1e5(v=vs.100).aspx
WCF contains Server and Client side In my case Server is the program that produces data (logs). There are several subscribers that should be notified when a new bunch of data is ready to be posted.
So I think WCF Server should callback some method for all interested clients....
Should I use "CallbackContract" keyword to define one-way callback operation?
I need is void Log(string) method which will be called by server for all clients every time something should be possted, how to define such method in terms of WCF?
probably I should avoid "callback" but instead use string[] getLogs() method which will return new logs? then client may call getLogs method every one or two or three seconds to get logs for the last interval?
What you described looks like Publisher/Subscriber pattern. Check this out: http://blogs.msdn.com/b/tomholl/archive/2008/05/17/building-a-pub-sub-message-bus-with-wcf-and-msmq.aspx
There are also specialized frameworks, like NServiceBus that solve broader problem of asynchronous messaging.
what you are asking sounds reasonable, have a look at this one: WCF Callbacks; a beginners guide
Since it's a long question, cliff notes come first.
Cliff notes:
One client sends input to several services and they keep on working and sending results until the client tells them to stop or they have reached a pre-set maximum number of results.
Do you know how one should go about implementing this, or do you have a C#-example for sth. like this? Is WCF & streaming the right toolset for this ? (Consider that results are custom objects, so it's not exactly the same as streaming a file)
More Detailed Problem Definition:
Situation:
I have full control over the code of the client and the services (iow not dependent on closed 3rd party stuff)
everything is in C#
We have one client who wants to get one task done and has several equal independent services for that.
(equal = equal service-software, the hardware on which each service runs can vary -> service-speeds can vary)
One task consists of "1000 pieces of work" which are all independent from one another.
Within one task all of the 1000 pieces of work are based upon the same piece of input data.
I mention solutions A+B since I think they help explaining the problem:
Solution (A) - The slow non-parallel way:
1. Client sends input to one service.
2. Service initializes based upon the input.
3. Service processes all 1000 pieces of work
(results get added up(super fast btw) so the result of 1000 pieces of work has the same size as the result of one)
4. Service sends result to the client.
5. Client receives result and is happy
Solution (B) - Parallel faster way:
Let's say ten services, so we evenly split it up and each should process 100.
The problem is some services may be much faster than others so giving each the same number(100) is slower than
necessary.
Furthermore we can't split up according to an a priori speed-test since the speed of one service can change and
some might even go down during processing, these are the reasons why I think the following would be best for my purpose.
Solution (C) - The way I would like to implement it:
Client sends out the same request to all services. (same request still implies that the task get's processed in parallel, parallelization is super easy for my problem 1000 pieces of work are so independent that doing 1000 times the "first" piece of work means we are done)
A service keeps working and sending results until it is told to stop or has processed 1000 pieces of work.
One result gets sent for 10 pieces of work done.
This means all services work parallel on the task and when the client has gotten a sum of 1000 results from all service replies combined it will send the stop signal.
That means normally no single service should reach 1000, but with having 1000 we have covered the situation where there is only one service and we have a fail-safe to avoid infinite loops if the stop signal gets lost. (client neither needs to wait nor to be absolutely sure that the stop signal has reached a service)
Throwing away additional results beyond our goal of 1000 is fine.
(The alternative of instead making follow-up requests to services that have responded faster than others would come
with the overhead of wasted time due to messages going back and forth and additional initializations.
(Add. inits could be avoided but it would be complicated and you still have the other overhead))
I basically have solutions/would know how to implement A+B but I have no clue how I would go about realizing (C).
How do you implement a client/service-architecture in C# where the service keeps sending results and doesn't just return one object/value? (Results are custom objects, btw)
Does someone know about C#-example-code where sth. like that is implemented? Would streaming be the right way?
I've found the "writing a custom stream"-example but it seems like it's a pretty long way from there to what I want. (As a WCF-noob I can easily be wrong on that though.)
Streaming in the WCF doesn't work in the way that you will open a stream, return the stream to the client and service will still generate results to the stream. If you want to work this way you must go deeper and use sockets directly. In WCF the stream must be written prior to returning it from the operation (I tried to write to returned stream from other thread but it didn't work). Streaming in WCF is only for data transport.
I don't like any of your solution. I would try:
Variant of B. But tasks will not be divided equally upfront. If you have 10 services and 1000 tasks you will send first 10 tasks (each to one service) only only after the service returns the result it will get another task. If tasks can be completed within reasonable time you will need only multiple async calls to services and wait for responses. If any service will not be able to complete task within defined timeout you will send the task to another service. If tasks can be completed fast you can send small batches instead of single task. If task completion takes long you will need duplex communication.
Use Transactional Message queue - MSMQ. You client will generate 1000 messages to "producer queue" and services will take these messages one by one and process them. They will send results as message to another "consumer queue" where client will take results and process them (each result must have correlation to the task). Transactional queue will ensure that each task can be processed only by single service but if service fails or timeout of the transaction will occur the task will be available for processing in another service. MSMQ also offers some additional features like queue for faulty tasks etc. This is little bit advanced scenario. The main problem of this scenario can be limitation in size of messages (max. 4MB per message).
Edit:
Ok because of your clarification it looks like you need to send the same task to multiple services and task will just trigger series of the same computation on the same data. You can achieve it in this way:
Build a duplex service using Net.tcp binding
Service will implement service contract which will have operations to start computation and to stop computation (you can use IsInitiating and IsTerminating properties of OperationContract)
Service will do computation in separate thread started in start operation
Stop operation will abort computation thread
Client will implement callback contract to receive results from the service
Service will call the client callback when the processing thread has result (or multiple results) to send back
Here is an example of using duplex services with WsDualHttpBinding - don't use this binding in your scenario because it is much more complicated if you want to have single client to communicate with multiple same services over duplex HTTP.
What you describe as Solution (C) sounds like a good use for Asynchronous WCF. Some of these might help...
Synchronous and Asynchronous Operations
Asynchronous Programming Design Patterns
How to: Call WCF Service Operations Asynchronously
I need a console app which will calling webmethod.
It must be asynchronous and without timeout (we don't know how much time takes this method to deal with task.
Is it good way:
[WebMethod]
[SoapDocumentMethod(OneWay = true)]
??
Don't use one-way if you need results
First, if you need a response from your method, you don't want [SoapDocumentMethod(OneWay = true)]. This attribute creates a "fire and forget" call which never returns a response back to the caler and must return void. Instead, use a regular method call and call it async.
One method or two?
If you're using ASMX, there are two basic solutions: one method with a very long timeout, or two methods (as #Aaronaught suggested above): one to kick off the operation and return an ID of the operation, and another to pass in the ID and retrieve results (if available).
Personally, I would not recommend this two-method approach in most cases because of the additional complexity involved, including:
client and server code needs to be changed to suppport 2-step invocation
ASP.NET intrinsic objects like Request and Response are not available when called from a background task launched with ThreadPool.QueueUserWorkItem.
throttling on a busy server gets much harder if there are multiple threads involved with each request.
the server must hang onto the results until the client picks them up (or you decide to throw them out), which may eat up RAM if results are large.
you can't stream large, intermediate results back to the client
True, in some scenarios the 2-method approach may scale better and will be more resilient to broken network connections between client and server. If you need to pick up results hours later, this is something to consider. But your operations only take a few minutes and you can guarantee the client will stay connected, given the addiitonal dev complexity of the 2-method approach I'd consider it a last resort to be used only if the one-method solution doesn't match your needs.
Anyway, the solution requires two pieces. First, you need to call the method asynchronously from the client. Second, you need to lengthen timeouts on both client and server. I cover both below.
Calling ASMX Web Services Asynchronously
For calling an ASMX web service asynchronously from a command-line app, take a look at this article starting with page 2. It shows how to call a web service asynchronously from a .NET cilent app using the newer Event-Based Async Pattern. Note that the older .NET 1.0 approach described here, which relies on BeginXXX/EndXXX methods on the proxy, is not recommended anymore anymore since Visual Studio's proxy generator doesn't create those methods. Better to use the event-based pattern as linked above.
Here's an excerpt/adaptation from the article above, so you can get an idea of the code involved:
void KickOffAsyncWebServiceCall(object sender, EventArgs e)
{
HelloService service = new HelloService();
//Hookup async event handler
service.HelloWorldCompleted += new
HelloWorldCompletedEventHandler(this.HelloWorldCompleted);
service.HelloWorldAsync();
}
void HelloWorldCompleted(object sender,
HelloWorldCompletedEventArgs args)
{
//Display the return value
Console.WriteLine (args.Result);
}
Lengthen server and client timeouts
To prevent timeouts, http://www.dotnetmonster.com/Uwe/Forum.aspx/asp-net-web-services/5202/Web-Method-TimeOut has a good summary of how to adjust both client and server timeouts. You didn't specify in your question if you own the server-side method or just the client-side call, so the excerpt below covers both cases:
there has two setttings that will
affect the webservice call timeout
behavior:
** The ASP.NET webservice's server-side httpruntime timeout
setting, this is configured through
the following element:
httpRuntime Element (ASP.NET Settings Schema)
http://msdn2.microsoft.com/en-us/library/e1f13641.aspx
<configuration> <system.web>
<httpRuntime .............
executionTimeout="45"
.............../> </system.web>
</configuration>
Also, make sure that you've set the
<compilation debug="false" /> so as to
make the timeout work correctly.
** If you're using the wsdl.exe or VS IDE "add webreference" generated
proxy to call webservice methods,
there is also a timeout setting on the
client proxy class(derived from
SoapHttpClientProtocol class). This is
the "Timeout" property derived from
"WebClientProtocol" class:
WebClientProtocol.Timeout Property http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webclientprotocol.timeout.aspx
Therefore, you can consider adjusting
these two values according to your
application's scenario. Here is a
former thread also mentioned this:
http://groups.google.com/group/microsoft.public.dotnet.framework.webservices/browse_thread/thread/73548848d0544bc9/bbf6737586ca3901
Note that I'd strongly recommend making your timeouts long enough to encompass your longest operation (plus enough buffer to be safe should things get slower) but I wouldn't recommend turning off timeouts altogether. It's generally bad programming practice to allow unlimited timeouts since an errant client or server can permanently disable the other. Instead, just make timeouts very long--- and make sure to be logging instances where your clients or servers time out, so you can detect and diagnose the problem when it happens!
Finally, to echo the commenters above: for new code it's best to use WCF. But if you're stuck using ASMX web services, the above solution should work.
If the method is actually one-way, and you don't care about the result or ever need to follow up on the status of your request, then that is good enough.
If you do need a result (eventually), or need to check on the status of the operation, then this won't work very well. What your method should do in that case is start the work in a background thread, then immediately return an ID that can be used in a different web method to look up the status.
So something like this:
public enum JobStatus { Running, Completed, Failed };
public class MyService : WebService
{
[WebMethod]
public int BeginJob()
{
int id = GetJobID();
// Save to a database or persistent data source
SaveJobStatus(id, JobStatus.Running);
ThreadPool.QueueUserWorkItem(s =>
{
// Do the work here
SaveJobStatus(id, JobStatus.Completed);
}
return id;
}
[WebMethod]
public JobStatus GetJobStatus(int id)
{
// Load the status from database or other persistent data source
return ( ... )
}
}
That's one method to start the work, and another method to check on its status. It's up to the client to poll periodically. It's not a very good system, but you don't have a lot of options with ASMX.
Of course, if you do need a response from this operation, a much better way is to use WCF instead. WCF gives you callback contracts, which you can use to begin a one-way operation and subscribe to a notification when that operation is complete, which eliminates the need for polling above.
So, to summarize all that:
If you don't need any response or status updates, just use IsOneWay = true.
If you do need updates, and can use WCF on the service side, use that with a callback contract. You should be using WCF for new Web Service projects anyway.
If you need updates and cannot use WCF, do the work in a background thread and implement a periodic polling system with an additional status-check web method.