Unable to use logger for task - c#

I have a situation where there is a synchronous call to a method and based on a parameter we switch the response for sync /async and inside async we start a task as below. The problem is tracer works until its outside the Task() but not inside. Is it happening that Task cannot access the parent thread data ?
RequestProcessor.cs file code:
public classA_Res GetListbyUserRequest(ApiRequest<object> request)
{
if(request.IsAsync)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call started"); // this works/ gets logged in db
var taskProcessEventsResponseAsync = new Task(() =>
ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId));
taskProcessEventsResponseAsync.Start();
}
else
{
response=DataManager.Instance.GetListbyUserRequest(); // this gets paginated data for UI
}
//some code for response that request has been put down for export async.
}
private void ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call in progress"); // this doesnt works/ doesnt gets logged in db but also doesnt throws any error
//some code for processing data in chunks and creating files on server
}
LocalTracer.cs
public interface ILocalTracer
{
void TraceInformation(AVEventType eventType, DummyParameter dummy = null);
}
public sealed class LocalTracer:ILocalTracer
{
static ILocalTracer _instance = new LocalTracer();
public static ILocalTracer Instance
{
get { return _instance; }
set { _instance = value; }
}
private LocalTracer()
{
}
public static void TraceInformation(AVEventType eventType, string sMessage = "", string
userName = "", string ipAddress = "",.....)
{
//tracer code
}
public void TraceInformation(AVEventType eventType, DummyParameter dummy = null)
{
TraceInformation(eventType, "");
}
}
Please assume all this code in proper try catch blocks.

Related

There is no active ActorContext, this is most likely due to use of async operations from within this actor

I have a problem, and I am not quite sure how to solve this, except for making my Akka Actor not have async methods.
Here is my Actor Code:
public class AggregatorActor : ActorBase, IWithUnboundedStash
{
public IStash Stash { get; set; }
private AggregatorTimer _aggregatorTimer;
private IActorSystemSettings _settings;
private AccountSummary _accountResponse;
private ContactDetails _contactResponse;
private AnalyticDetails _analyticsResponse;
private FinancialDetails _financialResponse;
private ActorSelection _accountActor;
private ActorSelection _contactActor;
private ActorSelection _analyticsActor;
private ActorSelection _financialActor;
public AggregatorActor(IActorSystemSettings settings) : base(settings)
{
_accountActor = Context.System.ActorSelection(ActorPaths.AccountActorPath);
_contactActor = Context.System.ActorSelection(ActorPaths.ContactActorPath);
_analyticsActor = Context.System.ActorSelection(ActorPaths.AnalyticsActorPath);
_financialActor = Context.System.ActorSelection(ActorPaths.FinancialActorPath);
_settings = settings;
}
#region Public Methods
public override void Listening()
{
ReceiveAsync<ProfilerMessages.ProfilerBase>(async x => await HandleMessageAsync(x));
}
private void Busy()
{
Receive<ProfilerMessages.ProfilerBase>(x => Stash.Stash());
}
private void Aggregate()
{
try
{
Context.Sender.Tell(AggregatedSummaryResponse.Instance(_accountResponse, _contactResponse, _analyticsResponse, _financialResponse));
}
catch (Exception ex)
{
ExceptionHandler(ex);
}
}
public override async Task HandleMessageAsync(object msg)
{
//if is summary, generate new isntance of AggregatorTimer in _eventHandlerCollection.
if (msg is ProfilerMessages.GetSummary)
{
//Become busy. Stash
Become(Busy);
//Handle different requests
var clientId = (msg as ProfilerMessages.GetSummary).ClientId;
await HandleSummaryRequest(clientId);
}
}
private async Task HandleSummaryRequest(string clientId)
{
try
{
var accountMsg = new AccountMessages.GetAggregatedData(clientId);
_accountResponse = (await _accountActor.Ask<Messages.AccountMessages.AccountResponseAll>(accountMsg, TimeSpan.FromSeconds(_settings.NumberOfSecondsToWaitForResponse))).AccountDetails;
//Need to uncomment this
var contactMsg = new ContactMessages.GetAggregatedContactDetails(clientId);
_contactResponse = (await _contactActor.Ask<Messages.ContactMessages.ContactResponse>(contactMsg, TimeSpan.FromSeconds(_settings.NumberOfSecondsToWaitForResponse))).ContactDetails;
var analyticMsg = new AnalyticsMessages.GetAggregatedAnalytics(clientId);
_analyticsResponse = (await _analyticsActor.Ask<Messages.AnalyticsMessages.AnalyticsResponse>(analyticMsg, TimeSpan.FromSeconds(_settings.NumberOfSecondsToWaitForResponse))).AnalyticDetails;
var financialMsg = new FinancialMessages.GetAggregatedFinancialDetails(clientId);
_financialResponse = (await _financialActor.Ask<Messages.FinancialMessages.FinancialResponse>(financialMsg, TimeSpan.FromSeconds(_settings.NumberOfSecondsToWaitForResponse))).FinancialDetails;
//Start new timer
_aggregatorTimer = new AggregatorTimer(_settings.NumberOfSecondsToWaitForResponse);
_aggregatorTimer.TimeElapsed += _aggregatorTimer_TimeElapsed;
}
catch (Exception ex)
{
ExceptionHandler(ex);
}
}
//Event that is raised when an external timers time elapsed.
private async void _aggregatorTimer_TimeElapsed(object sender, ElapsedTimeHandlerArg e)
{
Aggregate();
_aggregatorTimer = null;
_accountResponse = null;
_contactResponse = null;
_analyticsResponse = null;
_financialResponse = null;
//Unstash
Stash.Unstash();
//Start listening again
Become(Listening);
}
#endregion
}
Inside the _aggregatorTimer_TimeElapsed event, I call the await Aggregate function, but the following exception is thrown.
There is no active ActorContext, this is most likely due to use of async operations from within this actor
I think this is caused by the fact that the Aggregate function tries to Tell() the Sender about the responses that are aggregated, but those Tasksare not yet completed? I might be completely wrong, but I have no idea why this is thrown.
I'm not sure what do you even need an AggregatorTimer for - in akka you have a Context.System.Scheduler object, which can be used to schedule events going to happen in the future.
Another thing is that you probably shouldn't execute logic inside event handlers. If you really need them in your code, it's better to limit them only to send a message, once an event gets triggered i.e.:
Receive<TimedOut>(_ => /* handle timeout message */);
var self = Self; // bind current self to a variable, so it won't change
_aggregatorTimer.TimeElapsed += (sender, e) => self.Tell(new TimedOut(), self);

Shared resource and async Web API call

I have a simple Web API method that looks like this:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
TaskManager.Run is decalared like this:
public async Task Run(int id)
I was expecting it to return "Task was started" message immediately after TaskManager.Run(taskId) But the request continues to run synchronously.
But if to replace the call TaskManager.Run(taskId) with:
Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(100)));
Then it runs asynchronously.
So I believe this is something to do with the resources shared by TaskManager and main thread. Can a shared resource lock the execution?
I'm using Castle Windsor. One WindsorContainer container is declared in Web API project.
TaskManager utilizes BaseTaskRunner class inside of it. One more WindsorContainer is declared in BaseTaskRunner.
Web API's container uses LifeStyle.PerWebRequest for all components. BaseTaskRunner's container uses LifeStyle.Singleton (not sure if it's correct LifeStyle). Could the call be locked for example by DdContext or other classes declared in both of the containers?
UPD:
I don't want to wait the TaskManager.Run to complete. But what happens is that return statement still waits for the TaskManager.Run to complete (even without await statement on TaskManager.Run).
In other words it does not matter how I call the TaskManager.Run:
TaskManager.Run(taskId);
or
await TaskManager.Run(taskId);
It waits for TaskManager.Run to complete in both cases.
Here is the code of TaskManager:
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type, byte[] data = null, object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public async Task Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
Run(task, removeOnComplete);
}
public async Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public async Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
And some other classes:
public class SpreadsheetImportTaskRunner : BaseTaskRunner
{
public IForecastSpreadsheetManager SpreadsheetManager { get; set; }
protected override void Execute()
{
SpreadsheetManager.ImportActuals(Task.Data);
}
protected override void Initialize()
{
base.Initialize();
SpreadsheetManager = _container.Resolve<IForecastSpreadsheetManager>();
}
}
BaseTaskRunner:
public class BaseTaskRunner
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
protected IWindsorContainer _container = new WindsorContainer();
protected BackgroundTask Task { get; set; }
public async Task Run(BackgroundTask task)
{
Initialize();
Task = task;
try
{
Execute();
}
catch (Exception ex)
{
SetError(ex.ToString());
}
}
protected virtual void Execute()
{
}
protected virtual void Initialize()
{
_container.Install(new TaskRunnerComponentsInstaller());
TaskRepository = _container.Resolve<IRepository<BackgroundTask>>();
}
}
I still believe this is something to do with the WindsorContainer and common classes which are resolved in several different threads.
The issue is that you're not using await on the Task being returned from the invocation of the TaskManager.Run function. Consider the below:
public async Task<HttpResponseMessage> RunTask(TaskType taskType)
{
var taskId = await TaskManager.CreateTask(taskType);
await TaskManager.Run(taskId);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content =
new StringContent($"Task {taskType.GetDescription()} was started.")
};
}
Now it will work asynchronously as you'd expect. The await sets a continuation marker in the async state-machine, instructing it to return to this portion of the method upon completion of the asynchronous operation defined in the TaskManager.Run.
UPDATE
You are missing lots of await statements, and there are times where you need to not mark methods as async. It appears as though there are some mis-understandings as it pertains to these keywords. Here is what your TaskManager class should look like.
public class TaskManager : ITaskManager
{
public IRepository<BackgroundTask> TaskRepository { get; set; }
public async Task<int> CreateTask(TaskType type,
byte[] data = null,
object config = null)
{
var task = new BackgroundTask
{
Type = type,
Status = BackgroundTaskStatus.New,
Config = config?.SerializeToXml(),
Created = DateTime.Now,
Data = data
};
TaskRepository.Add(task);
TaskRepository.SaveChanges();
return task.Id;
}
public ask Run(int id, bool removeOnComplete = true)
{
var task = TaskRepository.GetById(id);
return Run(task, removeOnComplete);
}
public Task Run(TaskType type, bool removeOnComplete = true)
{
var tasksToRun = TaskRepository.Get(t => t.Type == type);
return tasksToRun.ForEachAsync(t => Run(t, removeOnComplete));
}
public Task Run(BackgroundTask task, bool removeOnComplete = true)
{
switch (task.Type)
{
case TaskType.SpreadsheetImport:
return new SpreadsheetImportTaskRunner().Run(task);
break;
}
}
}
}
Ideally, if the method is marked as a return type of Task and the method doesn't need to unwind any tasks within its execution it can simply return the Task functionality for its implementation. For example, notice how dramatically my TaskManager class differs from yours -- I'm only marking methods as async that need to actually await. These two keywords should be married, if a method uses async there should be an await. But only use await if the method needs to unwind and use the asynchronous operation.

How to send multiple acknowledgement to client using IHttpAsyncHandler in asp.net

I have implemented IHttpAsyncHandler in my class to perform 5-6 long running process in background and acknowledge to client on start of each task.
Earlier I was using one session variable and updating it with current status of task, and giving async call request to server from jquery in interval of 5 seconds to get current status, but this implementation is not good because its continually hitting request to server for status.
Then I implemented IHttpAsyncHandler in my application, now server itself send acknowledgement to client, but as per my implementation I am able to send only one acknowledgement! if I try to send more than one then its giving error as "object reference not set to an instance of an object"
please check my sample code.
in my code
ExecuteFirst() method works fine sending acknowledgement to client but ExecuteSecond() does not send acknowledgement its giving error.
I goggled a lot but not getting proper way to send multiple acknowledgement to client.
this is my sample code, please help me if any one have any idea.
Javascript
function postRequest(url) {
var url = 'StartLongRunningProcess.ashx?JOBCODE=18'
var xmlhttp = getRequestObject();
xmlhttp.open("POST", url, true);
xmlhttp.onreadystatechange =
function () {
if (xmlhttp.readyState == 4) {
var response = xmlhttp.responseText;
divResponse.innerHTML += "<p>" + response + "</p>";
}
}
xmlhttp.send();
}
function getRequestObject() {
var req;
if (window.XMLHttpRequest && !(window.ActiveXObject)) {
try {
req = new XMLHttpRequest();
}
catch (e) {
req = false;
}
}
else if (window.ActiveXObject) {
try {
req = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
req = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e) {
req = false;
}
}
}
return req;
}
StartLongRunningProcess.ashx.cs
public class StartLongRunningProcess: IHttpAsyncHandler, IRequiresSessionState
{
private AsyncRequestResult _asyncResult;
public void ProcessRequest(HttpContext context) {}
public bool IsReusable
{
get { return true;}
}
public IAsyncResult BeginProcessRequest(HttpContext context, System.AsyncCallback cb, object extraData)
{
int32 jobCode= convert.ToInt32(context.Request["JOBCODE"]);
_asyncResult = new AsyncRequestResult(context, cb, jobCode);
if(jobCode==18)
{
StartProcess18()
}
else
{
//StartProcessOther()
}
}
private StartProcess18()
{
var task1= new Task(() =>
{
ExecuteFirst();
});
var task2 = task1.ContinueWith((t1) =>
{
ExecuteSecond();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task1.Start();
}
private ExecuteFirst()
{
//notify to client that this job has been started
_asyncResult.CurrentContext.Response.Write("First task has been started");
_asyncResult.Notify();
// Above line of code successfully send a acknowledgement to client
//Doing some long running process
}
private ExecuteSecond()
{
//notify to client that this job has been started
_asyncResult.CurrentContext.Response.Write("Second task has been started");
// Above line of code giving error and if I skip it and call Notify() this also does not work.
_asyncResult.Notify();
//Doing some long running process
}
public void EndProcessRequest(IAsyncResult result)
{
}
}
AsyncRequestResult.cs
public class AsyncRequestResult : IAsyncResult
{
private HttpContext context;
private AsyncCallback callback;
private ManualResetEvent completeEvent = null;
private object data;
private object objLock = new object();
private bool isComplete = false;
public AsyncRequestResult(HttpContext ctx, AsyncCallback cb, object d)
{
this.context = ctx;
this.callback = cb;
this.data = d;
}
public HttpContext Context
{
get { return this.context; }
}
public void Notify()
{
//isComplete = true;
lock(objLock)
{
if(completeEvent != null)
{
completeEvent.Set();
}
}
if (callback != null)
{
callback(this);
}
}
public object AsyncState
{
get { return this.data; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public WaitHandle AsyncWaitHandle
{
get
{
lock(objLock)
{
if (completeEvent == null)
completeEvent = new ManualResetEvent(false);
return completeEvent;
}
}
}
public bool IsCompleted
{
get { return this.isComplete; }
}
}
HttpContext.Current is not null only if you access it in a thread that handles incoming requests.
Your continuation task that is running is most likely running on a ThreadPool thread without the HttpContext.Current flowing to the continuation, hence it being null.
Try setting your TaskScheduler to TaskScheduler.FromCurrentSynchronizationContext() in order to execute it in the same context.
private StartProcess18()
{
var task1= new Task(() =>
{
ExecuteFirst();
});
var task2 = task1.ContinueWith((t1) =>
{
ExecuteSecond();
}, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext());
task1.Start();
}

Control flow in asynchronous calls

I'm facing difficulties understanding how to handle program control during asynchronous flow.
I have a SessionManager class which calls the initiates the session and we need to register
for the event OnStartApplicationSessionResponse and my control will return to the calling point. I will get the session id in the eventhandler after sometime or the error code if there is an error.
class SessionManager
{
public bool startUp(Object params)
{
try
{
serviceProvider = new ServiceProvider();
serviceProvider.OnStartApplicationSessionResponse += new StartApplicationSessionResponseHandler(ServiceProvider_OnStartApplicationSessionResponse);
serviceProvider.startUp(params);
}
}
public void ServiceProvider_OnStartApplicationSessionResponse(object sender, ServiceProvider.StartApplicationSessionResponseArgs e)
{
//e.getError
//I will get the session Id here or error code
}
}
How do I get sessionId or the error as my control is now at the calling position?
You could use TaskCompletionSource to make the Event awaitable.
class SessionManager
{
private ServiceProvider _serviceProvider;
public int SessionId
{
get;
private set;
}
public Task<bool> StartUp(Object param)
{
_serviceProvider = new ServiceProvider();
var tcs = new TaskCompletionSource<bool>();
_serviceProvider.OnStartApplicationSessionResponse += (sender, args) =>
{
// do your stuff
// e.g.
SessionId = 0xB00B5;
tcs.SetResult(true);
};
_serviceProvider.startUp(param);
return tcs.Task;
}
}
The call would look like:
private static async void SomeButtonClick()
{
var mgr = new SessionManager();
var success = await mgr.StartUp("string");
if (success)
{
Console.WriteLine(mgr.SessionId);
// update ui or whatever
}
}
note: This Feature is available in .Net 4.5.
With the C# feature async and await you are able to rewrite an asynchronous flow into something that is like a synchronous flow. You have only provided some fragments of your code so to provide a complete example I have created some code that resembles your code:
class StartEventArgs : EventArgs {
public StartEventArgs(Int32 sessionId, Int32 errorCode) {
SessionId = sessionId;
ErrorCode = errorCode;
}
public Int32 SessionId { get; private set; }
public Int32 ErrorCode { get; private set; }
}
delegate void StartEventHandler(Object sender, StartEventArgs e);
class ServiceProvider {
public event StartEventHandler Start;
public void Startup(Boolean succeed) {
Thread.Sleep(TimeSpan.FromSeconds(1));
if (succeed)
OnStart(new StartEventArgs(321, 0));
else
OnStart(new StartEventArgs(0, 123));
}
protected void OnStart(StartEventArgs e) {
var handler = Start;
if (handler != null)
handler(this, e);
}
}
The ServiceProvider.Startup method will delay for a second before firing an event that either signals success or failure depending on the succeed parameter provided. The method is rather silly but hopefully is similar to the behavior of your ServiceProvider.Startup method.
You can convert the asynchronous startup into a task using a TaskCompletionSource:
Task<Int32> PerformStartup(ServiceProvider serviceProvider, Boolean succeed) {
var taskCompletionSource = new TaskCompletionSource<Int32>();
serviceProvider.Start += (sender, e) => {
if (e.ErrorCode > 0)
throw new Exception(e.ErrorCode.ToString());
taskCompletionSource.SetResult(e.SessionId);
};
serviceProvider.Startup(succeed);
return taskCompletionSource.Task;
}
Notice how an error signaled by the Start event is converted into an Exception (in production code you should use a custom exception type instead).
Using the async and await feature of C# you can now write code that looks very much like synchronous code even though it actually is asynchronous:
async void Startup(Boolean succeed) {
var serviceProvider = new ServiceProvider();
try {
var sessionId = await PerformStartup(serviceProvider, succeed);
Console.WriteLine(sessionId);
}
catch (Exception ex) {
Console.WriteLine(ex);
}
}
If an error is reported by the Start event you can now deal with in the catch block. Also the session ID is simply a return value of the function. The "magic" is that using await on a Task will return the result of the task when it completes and if an exception is thrown in the task it can be caught on the thread awaiting the task.

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).

Categories