WCF discovery slowing processing of callbacks - wcf

I have a WCF service that is processing a call, sending that processed data onto another service, and alerting the caller and any other instances of that application by firing a callback. Originally the callbacks were being called at the end but I found that if the second service was not running that there would be a twenty second delay while we attempted to discover it. Only then were the callbacks called. I moved the callback notification before the call to the second service but it still had the delay. I even tried firing the callbacks on a background process but that didn't work either. Is there a way to get around this delay, outside of changing the timeout of the discovery? Here is a code snippet.
// Alert the admins of the change.
if (alertPuis)
{
ReportBoxUpdated(data.SerialNumber);
}
// Now send the change to the box if he's online.
var scope = new Uri(string.Format(#"net.tcp://{0}", data.SerialNumber));
var boxAddress = DiscoveryHelper.DiscoverAddress<IAtcBoxService>(scope);
if (boxAddress != null)
{
var proxy = GetBoxServiceProxy(boxAddress);
if (proxy != null)
{
proxy.UpdateBox(boxData);
}
else
{
Log.Write("AtcSystemService failed on call to update toool Box: {0}",
data.SerialNumber);
}
}
else if (mDal.IsBoxDataInPendingUpdates(data.SerialNumber) == false)
mDal.AddPendingUpdate(data.SerialNumber, null, true, null);
}
and
private static void ReportBoxUpdated(string serialNumber)
{
var badCallbacks = new List<string>();
Action<IAtcSystemServiceCallback> invoke = callback =>
callback.OnBoxUpdated(serialNumber);
foreach (var theCallback in AdminCallbacks)
{
var callback = theCallback.Value as IAtcSystemServiceCallback;
try
{
invoke(callback);
}
catch (Exception ex)
{
Log.Write("Failed to execute callback for admin instance {0}: {1}",
theCallback.Key, ex.Message);
badCallbacks.Add(theCallback.Key);
}
}
foreach (var bad in badCallbacks) // Clean out any stale callbacks from the list.
{
AdminCallbacks.Remove(bad);
}
}

Have you considered caching the result?

Related

How to detect when client has closed stream when writing to Response.Body in asp.net core

I'm trying to write an infinite length response body and detect when a client disconnects so I can stop writing. I'm used to getting socket exceptions or similar when a client closes the connection but that doesn't seem to be happening when writing directly to Response.Body. I can close the client applications and the server side just keeps on writing. I've included the relevant code below. It's entirely possible there is a better way to do it but this came to mind. Basically I have a live video feed which should go on forever. I'm writing to ResponseBody as chunked content (No content length, flushing after each video frame). The video frames are received via an event callback from elsewhere in the program so I'm subscribing to the events in the controller method and then forcing it to stay open with the await Task.Delay loop so the Response stream isn't closed. The callback for H264PacketReceived is formatting the data as a streaming mp4 file and writing it to the Response Stream. This all seems to work fine, I can play the live stream with ffmpeg or chrome, but when I close the client application I don't get an exception or anything. It just keeps writing to the stream without any errors.
public class LiveController : ControllerBase
{
[HttpGet]
[Route("/live/{cameraId}/{stream}.mp4")]
public async Task GetLiveMP4(Guid cameraId, int stream)
{
try
{
Response.StatusCode = 200;
Response.ContentType = "video/mp4";
Response.Headers.Add("Cache-Control", "no-store");
Response.Headers.Add("Connection", "close");
ms = Response.Body;
lock (TCPVideoReceiver.CameraStreams)
{
TCPVideoReceiver.CameraStreams.TryGetValue(cameraId, out cameraStream);
}
if (this.PacketStream == null)
{
throw new KeyNotFoundException($"Stream {cameraId}_{stream} not found");
}
else
{
connected = true;
this.PacketStream.H264PacketReceived += DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed += PacketStream_StreamClosed;
}
while(connected)
{
await Task.Delay(1000);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
connected = false;
this.PacketStream.H264PacketReceived -= DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed -= PacketStream_StreamClosed;
}
}
private bool connected = false;
private PacketStream PacketStream;
private Mp4File mp4File;
private Stream ms;
private async void PacketStream_StreamClosed(PacketStream source)
{
await Task.Run(() =>
{
try
{
Console.WriteLine($"Closing live stream");
connected = false;
ms.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
private async void DefaultStream_H264PacketReceived(PacketStream source, H264Packet packet)
{
try
{
if (mp4File == null && packet.IsIFrame)
{
mp4File = new Mp4File(null, packet.sps, packet.pps);
var _p = mp4File.WriteHeader(0);
await ms.WriteAsync(mp4File.buffer, 0, _p);
}
if (mp4File != null)
{
var _p = mp4File.WriteFrame(packet, 0);
var start = mp4File._moofScratchIndex - _p;
if (_p > 0)
{
await ms.WriteAsync(mp4File._moofScratch, start, _p);
await ms.FlushAsync();
}
}
return;
}
catch (Exception ex)
{
connected = false;
Console.WriteLine(ex.ToString());
}
}
Answering my own question.
When the client disconnects mvc core sets the cancellation token HttpContext.RequestAborted
By monitoring and/or using that cancellation token you can detect a disconnect and clean everything up.
That said, the entire design can be improved by creating a custom stream which encapsulates the event handling (producer/consumer). Then the controller action can be reduced to.
return File(new MyCustomStream(cameraId, stream), "video/mp4");
The File Method already monitors the cancellation token and everything works as you'd expect.

Catching an exception from wrapped EAP request to WCF

I have a WCF request in WP8 environment that I wrapped according to this
http://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx#EAP
My call to the WCF service proceeds as follows:
try
{
var result = await mWCFClient.PerformRequestAsync();
}
catch(Exception e)
{
}
where PerformRequestAsync is an extension method. i.e.
public static ResultType PerformRequestAsync(this WCFClient client)
{
// EAP wrapper code
}
What happens is that occasionally something goes wrong on the WCF service and it returns "NotFound". I am not 100% sure why this happens and it seems like a rare occasion. The problem, however, is not the WCF service behavior, but the fact that it breaks in the EndPerformRequestAsync() in the automatically generated WCF code instead of going to my exception handler.
How and where should I be catching this exception as it never reaches my intended handler?!
[Edit]
As per Stephen's request, I've included the wrapper code here:
public static Task<RegistrationResult> RegisterAsync(this StoreServiceReference.StoreServiceClient client, string token, bool dummy)
{
var tcs = new TaskCompletionSource<RegistrationResult>();
EventHandler<RegisterCompletedEventArgs> handler = null;
handler = (_, e) =>
{
client.RegisterCompleted -= handler;
if (e.Error != null)
tcs.TrySetException(e.Error);
else if (e.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(e.Result);
};
client.RegisterCompleted += handler;
PerformStoreRequest(client, () => client.RegisterAsync(), token);
return tcs.Task;
}
private static void PerformStoreRequest(StoreServiceClient client, Action action, string token)
{
using (new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers[STORE_TOKEN_HTTP_HEADER] = token;
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
action.Invoke();
// TODO: Do we need to add handler here?
}
}
Now that I look at it, I think the problem stems from the nature of action invoke. But adding custom headers to WP8 WCF services already is a pain.
The action inside is an async operation, but Invoke as far as I know is not.
What's the proper way to go about it here?

nservicebus and eventstore

I'm wondering if anyone has encountered this before:
I handle a command, and in the handler, I save an event to the eventstore (joliver).
Right after dispatching, the handler for the same command is handled again.
I know its the same command because the guid on the command is the same.
After five tries, nservicebus says the command failed due to the maximum retries.
So obviously the command failed, but I don't get any indication of what failed.
I've put the contents of the dispatcher in a try catch, but there is no error caught. After the code exits the dispatcher, the event handler will always fire as if something errored out.
Tracing through the code, the events are saved to the database (I see the row), the dispatcher runs, and the Dispatched column is set to true, and then the handler handles the command again, the process repeats, and another row gets inserted into the commits table.
Just what could be failing? Am I not setting a success flag somewhere in the event store?
If I decouple the eventstore from nServicebus, both will run as expected with no retries and failures.
The dispatcher:
public void Dispatch(Commit commit)
{
for (var i = 0; i < commit.Events.Count; i++)
{
try
{
var eventMessage = commit.Events[i];
var busMessage = (T)eventMessage.Body;
//bus.Publish(busMessage);
}
catch (Exception ex)
{
throw ex;
}
}
}
The Wireup.Init()
private static IStoreEvents WireupEventStore()
{
return Wireup.Init()
.LogToOutputWindow()
.UsingSqlPersistence("EventStore")
.InitializeStorageEngine()
.UsingBinarySerialization()
//.UsingJsonSerialization()
// .Compress()
//.UsingAsynchronousDispatchScheduler()
// .DispatchTo(new NServiceBusCommitDispatcher<T>())
.UsingSynchronousDispatchScheduler()
.DispatchTo(new DelegateMessageDispatcher(DispatchCommit))
.Build();
}
I had a transaction scope opened on the save that I never closed.
public static void Save(AggregateRoot root)
{
// we can call CreateStream(StreamId) if we know there isn't going to be any data.
// or we can call OpenStream(StreamId, 0, int.MaxValue) to read all commits,
// if no commits exist then it creates a new stream for us.
using (var scope = new TransactionScope())
using (var eventStore = WireupEventStore())
using (var stream = eventStore.OpenStream(root.Id, 0, int.MaxValue))
{
var events = root.GetUncommittedChanges();
foreach (var e in events)
{
stream.Add(new EventMessage { Body = e });
}
var guid = Guid.NewGuid();
stream.CommitChanges(guid);
root.MarkChangesAsCommitted();
scope.Complete(); // <-- missing this
}
}

Callback is not invoked on the client

I have a self-hosted service that processes long running jobs submitted by a client over net.tcp binding. While the job is running (within a Task), the service will push status updates to the client via a one-way callback. This works fine, however when I attempt to invoke another callback to notify the client the job has completed (also one-way), the callback is never received/invoked on the client. I do not receive any exceptions in this process.
My Callback contract looks like this:
public interface IWorkflowCallback
{
[OperationContract(IsOneWay = true)]
[ApplySharedTypeResolverAttribute]
void UpdateStatus(WorkflowJobStatusUpdate StatusUpdate);
[OperationContract(IsOneWay = true)]
[ApplySharedTypeResolverAttribute]
void NotifyJobCompleted(WorkflowJobCompletionNotice Notice);
}
Code from the service that invokes the callbacks: (not in the service implementation itself, but called directly from the service implementation)
public WorkflowJobTicket AddToQueue(WorkflowJobRequest Request)
{
if (this.workflowEngine.WorkerPoolFull)
{
throw new QueueFullException();
}
var user = ServiceUserManager.CurrentUser;
var context = OperationContext.Current;
var workerId = this.workflowEngine.RunWorkflowJob(user, Request, new Object[]{new DialogServiceExtension(context)});
var workerjob = this.workflowEngine.FindJob(workerId);
var ticket = new WorkflowJobTicket()
{
JobRequestId = Request.JobRequestId,
JobTicketId = workerId
};
user.RegisterTicket<IWorkflowCallback>(ticket);
workerjob.WorkflowJobCompleted += this.NotifyJobComplete;
workerjob.Status.PropertyChanged += this.NotifyJobStatusUpdate;
this.notifyQueueChanged();
return ticket;
}
protected void NotifyJobStatusUpdate(object sender, PropertyChangedEventArgs e)
{
var user = ServiceUserManager.GetInstance().GetUserWithTicket((sender as WorkflowJobStatus).JobId);
Action<IWorkflowCallback> action = (callback) =>
{
ICommunicationObject communicationCallback = (ICommunicationObject)callback;
if (communicationCallback.State == CommunicationState.Opened)
{
try
{
var updates = (sender as WorkflowJobStatus).GetUpdates();
callback.UpdateStatus(updates);
}
catch (Exception)
{
communicationCallback.Abort();
}
}
};
user.Invoke<IWorkflowCallback>(action);
}
protected void NotifyJobComplete(WorkflowJob job, EventArgs e)
{
var user = ServiceUserManager.GetInstance().GetUserWithTicket(job.JobId);
Action<IWorkflowCallback> action = (callback) =>
{
ICommunicationObject communicationCallback = (ICommunicationObject)callback;
if (communicationCallback.State == CommunicationState.Opened)
{
try
{
var notice = new WorkflowJobCompletionNotice()
{
Ticket = user.GetTicket(job.JobId),
RuntimeOptions = job.RuntimeOptions
};
callback.NotifyJobCompleted(notice);
}
catch (Exception)
{
communicationCallback.Abort();
}
}
};
user.Invoke<IWorkflowCallback>(action);
}
In the user.Invoke<IWorkflowCallback>(action) method, the Action is passed an instance of the callback channel via OperationContext.GetCallbackChannel<IWorkflowCallback>().
I can see that the task that invokes the job completion notice is executed by the the service, yet I do not receive the call on the client end. Further, the update callback is able to be invoked successfully after a completion notice is sent, so it does not appear that the channel is quietly faulting.
Any idea why, out of these two callbacks that are implemented almost identically, only one works?
Thanks in advance for any insight.

Asynchronous call in one more Asynchronous call not working in silverlight

I have a UI view lossreport.xaml in that below code is there
LossReportTowGlassServiceClient wcf = new LossReportTowGlassServiceClient();
wcf.HouseholdSearchCompleted += (o, ev) =>
{
string a = errorMessg.ToUpper();
//Code to work with ev
};
wcf.HouseholdSearchAsync(lossDate, txtPolicyNumber.Text, errorMessg);
in service.svc page
try
{
policyinq.retrieveHouseHoldPoliciesCompleted += new retrieveHouseHoldPoliciesCompletedEventHandler(policyinq_retrieveHouseHoldPoliciesCompleted);
policyinq.retrieveHouseHoldPoliciesAsync(reqh, searchCriteria, lossdate, true, string.Empty, string.Empty);
break;
}
catch (Exception ex)
{
Logger.Exceptions("", "HouseholdSearch", ex);
errorToSend = "Household error";
}
void policyinq_retrieveHouseHoldPoliciesCompleted(object sender, retrieveHouseHoldPoliciesCompletedEventArgs e)
{
{
if (e.transactionNotification != null && e.transactionNotification.transactionStatus == TransactionState.S)
{
}
else
{
ErrorHandling.ErrorSend(e.transactionNotification, "HouseHold");
}
};
}
now before retrieveHouseHoldPolicies is completed HouseholdSearchCompleted event is fired.How to make it wait
You have an architectural issue here, The service should not invoke async request unless you go ta good reason (maybe invoke some paralleled stuff. Just invoke your server side code synchronously.
A service entry point got it's own handler thread, it should be the one who starts and end the request response process on service side. what you do is call an async method on service side making the thread that handle the request finish his job. So you either make this thread wait or execute the entire logic on him without calling async method, kapish?
using System.Threading;
ManualResetEvent _wait = new ManualResetEvent(false);
_wait.Set();//In completed event
_wait.WaitOne();//After the event is completed WaitOne will wait untill the _wait is set with value