C# Workflow ManualWorkflowSchedulerService Multithreading Question - c#

Hey guys, I just wanted to verify what I'm doing is correct. It came to our attention that a Windows Service had a pretty serious memory leak. I was able to track it down to how Workflow was being called. I reworked it a bit to stop the memory leak, but I wanted to validate that the code is doing what I think it is. Note I do not know the first thing about Workflow, so I'm coming to you.
Basically, the code was executing the Workflow on a thread, but was not removing the handler to WorkflowRuntime.Terminated. I am trying to ensure that the Workflow is executed asynchronously. Here are the relevant portions of code:
Checking to ensure there is only once instance of the WorkflowRuntime:
private static void _CheckRuntimeInstance()
{
lock (_padlock)
{
if (_wfRuntime == null)
{
_wfRuntime = new WorkflowRuntime();
ManualWorkflowSchedulerService schedulerService = new ManualWorkflowSchedulerService();
_wfRuntime.AddService(schedulerService);
_wfRuntime.StartRuntime();
}
}
}
Inside a static method, creating the specific WorkflowInstance to run:
_CheckRuntimeInstance();
// create the instance
WorkflowInstance instance = _wfRuntime.CreateWorkflow(typeof(WorkflowType),parameters);
instance.Start();
Guid instanceId = instance.InstanceId;
ThreadPool.QueueUserWorkItem(CallbackMethod, instanceId);
Thread callback method:
private static void DeviceLocationAssignmentCallback(Object state)
{
Guid instanceId = (Guid)state;
EventHandler<WorkflowTerminatedEventArgs> workflowTerminatedHandler = null;
EventHandler<WorkflowCompletedEventArgs> workflowCompletedHandler = null;
workflowTerminatedHandler = delegate(object sender, WorkflowTerminatedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registration.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
if (e.Exception != null)
{
// Log error.
}
}
};
_wfRuntime.WorkflowTerminated += workflowTerminatedHandler;
workflowCompletedHandler = delegate(object sender, WorkflowCompletedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registrations.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
}
};
_wfRuntime.WorkflowCompleted += workflowCompletedHandler;
_wfRuntime.GetService<ManualWorkflowSchedulerService>().RunWorkflow(instanceId);
}
EDIT: Changed the title of the post to get more views.

Related

Atapi CallInfoChangeEvent not fired

I am using the TAPI 2.0 wrapper from JulMar (https://atapi.codeplex.com/) and I'm having trouble with it.
The Initialization
void initTAPI()
{
myTAPI = new TapiManager("GetCaller");
if (!myTAPI.Initialize())
{
MessageBox.Show("FAILED!");
}else
{
name = myTAPI.Lines[0].Name;
lineName = (myTAPI != null && myTAPI.Lines.Length > 0 ? name : string.Empty);
foreach(TapiLine line in myTAPI.Lines)
{
line.NewCall += this.OnNewCall;
line.Ringing += this.OnRinging;
line.CallStateChanged += this.OnCallState;
line.CallInfoChanged += this.OnCallInfo;
}
MessageBox.Show(lineName);
}
}
So I get the lineName. When I now dial a number through the program, it fires
OnCallState
private void OnCallState(object sender, CallStateEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallStateEventArgs>(this.OnCallState), new object[] { sender, e });
return;
}
label1.Text = "Outgoing Call...";
}
But what I actually want to do is to get the number of an incoming call, but OnCallInfo does not get fired.
OnCallInfo
private void OnCallInfo(object sender, CallInfoChangeEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallInfoChangeEventArgs>(this.OnCallInfo), new object[] { sender, e });
return;
}
label1.Text = "Incoming Call...";
}
It says somehwere, that it only works with x86, so I changed the target but still no success.
PS: I have a call manager (ProCall) installed on the same machine, that tells me when someone calls, so I should be able to get the info in c# as well?
Here is the whole code if someone is interested: http://pastebin.com/Q5W5iGun
Depending on TSP, you may get call info messages, but TAPI does not force the driver to do this. So some TSP make you get the info yourself. In the Win32 API this is done via lineGetCallInfo.
After a quick look in this atapi wrapper, this happens in the GatherCallInfo method of the TapiCall class. However I can see no way to trigger this manually in this wrapper. You would need to modify the atapi source to make this a public method.
You can use example from TAPI which do the same. The only difference is new line.Monitor() method
foreach (TapiLine line in tapiManager.Lines)
{
try
{
line.NewCall += OnNewCall;
line.CallStateChanged += OnCallStateChanged;
line.CallInfoChanged += OnCallInfoChanged;
line.Monitor();
}
catch (TapiException ex)
{
LogError(ex.Message);
}
}
For further reading read this https://atapi.codeplex.com/SourceControl/latest#Atapi/trunk/source/test/TcMon/TapiMonitorForm.cs

wcf call completed event is not fired in correct order

In my Silverlight application, I put the WCF call in my ViewModel class.
DateTime CurrentDateTime;
internal void GetDateTime()
{
var client = new WcfClient();
client.GetCurrentDateTimeCompleted += GetCurrentDateTimeCompleted;
client.GetCurrentDateTimeAsync();
}
private void GetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
try
{
CurrentDateTime = args.Result;
}
Then in my code behind code some.xaml.cs file. I have a checkbox clicked event.
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var msgBoxControl = new MessageBoxControl();
msgBoxControl.Closed -= MessageBoxYesNo_Closed;
msgBoxControl.Closed += MessageBoxYesNo_Closed;
Inside the method MessageBoxYesNo_Closed, I call the method in the ViewModel class.
private void MessageBoxYesNo_Closed(object sender, EventArgs e)
{
try
{
this.ViewModel.GetDateTime();
curDateTime = this.ViewModel.CurrentDateTime;
My question is that sometimes the line curDateTime = this.ViewModel.CurrentDateTime; is executed before wcf call completed method, so I can't get the right value.
I guess that it may be there are two threads, one is in UI, the other one is in service call? Please don't use async/await as I have to use Visual Studio 2010.
Thanks
Get the solution, just add a while loop:
this.ViewModel.GetDateTime();
while (true)
{
this.ViewModel.CurrentDateTime = DateTime.Now;
if (this.ViewModel.CurrentDateTime != DateTime.MinValue)
break;
}
curDateTime = this.ViewModel.CurrentDateTime;

IHTMLChangeSink UnregisterForDirtyRange throwing ComException HRESULT E_FAIL

We have a WPF with a tab control being the primary UI for displaying customer details, each open customer gets its own tab.
Within the customer tabs we have another tab control that allows switching between various subsets of information, 2 of these use the Webbrowser control with IHTMLChangeSink functionality to monitor for hidden divs meant to trigger logic in the app.
Previously we were experiencing a very large memory leak when a Customer tab was closed, the cause of this was found to be the event handler created by RegisterForDirtyRange. To resolve the memory leak the Dispose methods were modified to call UnregisterForDirtyRange, using AutoIT to rapidly open and close customer tabs we were able to prove that the memory leak was fixed; this was done on a developer class machine.
Once this change was rolled out to testers we started seeing the application crash, in the event log we saw that the call to UnregisterForDirtyRange was throwing a ComException with HRESULT E_FAIL. Since we never saw this come up on the developer hardware and on the testers machines there was no guaranteed way to produce the crash I am thinking that there is some kind of race condition that is amplified when run on less powerful hardware.
Given this information my question is with regards to the internal workings of the Unregister call, can anyone think of what might be causing this exception?
My initial thought was that maybe the Notify method was running at the time of dispose so I tried introducing a lock between the dispose and notify but this didn't change anything.
Here is a stripped down version of the tab control that wraps the Web Browser:
public partial class BrowserTabWidget : BrowserWidget, IHTMLChangeSink
{
private static Guid _markupContainer2Guid = typeof(IMarkupContainer2).GUID;
private IMarkupContainer2 _container;
private uint _cookie;
public BrowserTabWidget()
{
InitializeComponent();
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
Loaded += OnLoaded;
}
}
protected override void DisposeControls()
{
if (_container != null)
{
_container.UnRegisterForDirtyRange(_cookie);
Marshal.ReleaseComObject(_container);
}
WebBrowser.LoadCompleted -= OnWebBrowserLoadCompleted;
WebBrowser.Dispose();
}
public override string CurrentUri
{
get { return (string)GetValue(CurrentUriProperty); }
set
{
NavigateTo(value);
SetValue(CurrentUriProperty, value);
}
}
private void NavigateTo(string value)
{
WebBrowser.Navigate(new Uri(value));
}
public static readonly DependencyProperty CurrentUriProperty = DependencyProperty.Register("CurrentUri", typeof(string), typeof(BrowserTabWidget), new FrameworkPropertyMetadata(CurrentUriChanged));
public static void CurrentUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var widget = (BrowserTabWidget)d;
d.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action(() => widget.NavigateTo(e.NewValue.ToString())));
}
private void InitializeWebBrowser()
{
WebBrowser.LoadCompleted += OnWebBrowserLoadCompleted;
WebBrowser.Navigate(new Uri(viewModel.InitialUrl));
}
void OnWebBrowserLoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
_container = GetMarkupContainer();
_container.RegisterForDirtyRange(this, out _cookie);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
Load();
}
private void Load()
{
InitializeWebBrowser();
}
private IMarkupContainer2 GetMarkupContainer()
{
var oDocument = WebBrowser.Document as IHTMLDocument2;
var pDocument = Marshal.GetIUnknownForObject(oDocument);
IntPtr pMarkupContainer;
Marshal.QueryInterface(pDocument, ref _markupContainer2Guid, out pMarkupContainer);
var oMarkupContainer = Marshal.GetUniqueObjectForIUnknown(pMarkupContainer);
Marshal.Release(pDocument);
Marshal.Release(pMarkupContainer);
return (IMarkupContainer2)oMarkupContainer;
}
public void Notify()
{
var document = WebBrowser.Document as HTMLDocument;
if (document != null)
{
//Parse Dom for hidden elements and trigger appropriate event handler
}
}
}
Hmya, E_FAIL, the curse of COM. Useless to ever diagnose anything, it is just a teacher's grade for the quality of the error reporting. I wrote the same code in Winforms to get something to testable, no repro. It is nevertheless very easy to force a repro. Given that the method takes only one argument, there's only one thing that can go wrong:
if (_container != null)
{
_container.UnRegisterForDirtyRange(_cookie);
_container.UnRegisterForDirtyRange(_cookie); // Kaboom!!!
Marshal.ReleaseComObject(_container);
}
Bad cookie. Criminal that they don't return E_INVALIDARG btw.
I could not test your exact code of course, it does have problems. Most severe one I see and the repro case is that there is no protection against calling DisposeControls() more than once. In general it is never wrong to dispose objects more than once, I have no insight if that's a realistic failure mode in your project. Otherwise very simple to protect yourself against this. Including catch-and-swallow code:
protected override void DisposeControls()
{
if (_container == null) return;
try {
_container.UnRegisterForDirtyRange(_cookie);
}
catch (System.Runtime.InteropServices.COMException ex) {
if (ex.ErrorCode != unchecked((int)0x80004005)) throw;
// Log mishap...
}
finally {
Marshal.ReleaseComObject(_container);
_container = null;
_cookie = 0;
WebBrowser.LoadCompleted -= OnWebBrowserLoadCompleted;
WebBrowser.Dispose();
}
}
Another thing I noticed in my test version of your code is that you don't appear to have any protection against the browser navigating to another page by any other means than WebBrowser.Navigate(). Or the LoadCompleted event firing more than once, it does for the stackoverflow.com home page for example. Or any web page that uses frames. That's a leak. Make it resilient by having your OnWebBrowserLoadCompleted() event handler also unregister the cookie if it is set.

Disposed Forms with a Base and threading returns null for progress bar

I have a base form that I use when calling 2 forms. Previously when calling the forms I didn't dispose of them, but I have found that reusing them, they would stay in memory and not get collected. So I have instead used a using statement instead to clear the memory, and all my problem are fixed.
But now a new problem arises, one that I had previously when testing my app with mono on Linux. I though it might be a mono specific problem, but since adding the using statement the same thing happens on my Windows machine. So it might just be that the Garbage Collector on Mono is different and was disposing properly of my forms.
Here is my problem I have a thread that I start to extract files in the background And I have progress bar telling me the progress, before using the dispose if I closed the form and reopened it my files extracted correctly and the progress bar was working fine. But now they work fine the first time, but if I reopen the form or the other one that has the same base, the extraction is not working, no files are extracted because I have a null exception when reporting the progress.
private void ExtractFiles()
{
Zip.ExtractProgress += new EventHandler<ExtractProgressArgs>(Utils_ExtractProgress);
Thread t = new Thread(new ThreadStart(Zip.ExtractZip));
t.IsBackground = true;
t.Start();
FilesExtracted = true;
}
void Utils_ExtractProgress(object sender, ExtractProgressArgs e)
{
UpdateProgress(e.Pourcentage);
}
private delegate void UpdateProgressDelegate(int Pourc);
private void UpdateProgress(int Pourc)
{
lock (this)
{
if (Progress.ProgressBar.InvokeRequired)
{
UpdateProgressDelegate del = new UpdateProgressDelegate(UpdateProgress);
Progress.ProgressBar.BeginInvoke(del, Pourc);
} else
{
Progress.Value = Pourc;
}
}
}
This code is in my BaseForm, the Progress control isn't null, but all of it's properties have null exceptions. So when checking if Invoked is required it raises an Null exception.
Here is my Zip.Extract method
public static event EventHandler<ExtractProgressArgs> ExtractProgress;
static ExtractProgressArgs Progress;
internal static void ExtractZip()
{
try
{
using (ZipFile zip = ZipFile.Read(Variables.Filename))
{
Progress = new ExtractProgressArgs();
Progress.TotalToTransfer = Convert.ToInt32(zip.Sum(e => e.UncompressedSize));
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
Old = 0; New = 0;
foreach (ZipEntry item in zip)
{
item.Extract(Variables.TempFolder, ExtractExistingFileAction.OverwriteSilently);
}
}
} catch (Exception)
{
}
}
static long Old;
static long New;
static void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
{
New = e.BytesTransferred;
Progress.Transferred += New - Old;
Old = e.BytesTransferred;
if (ExtractProgress != null)
{
ExtractProgress(e.CurrentEntry, Progress);
}
} else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
{
Old = 0;
}
}
Might be because my Zip.Extract is static? I have almost no knowledge of multi-threading, like synchronization, etc.
The short answer is yes, some of your problems are due to the static nature of those operations.
You should be able to resolve the problem by removing the static declarations from your Zip class and then creating an instance of it as needed.

How do I unsubscribe all handlers from an event for a particular class in C#?

Basic premise:
I have a Room which publishes an event when an Avatar "enters" to all Avatars within the Room. When an Avatar leaves the Room I want it to remove all subscriptions for that room.
How can I best unsubscribe the Avatar from all events in the room before I add the Avatar to a new Room and subscribe to the new Room's events?
The code goes something like this:
class Room
{
public event EventHandler<EnterRoomEventArgs> AvatarEntersRoom;
public event EvnetHandler<LeaveRoomEventArgs> AvatarLeavesRoom;
public event EventHandler<AnotherOfManyEventArgs> AnotherOfManayAvatarEvents;
public void AddPlayer(Avatar theAvatar)
{
AvatarEntersRoom(this, new EnterRoomEventArgs());
AvatarEntersRoom += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);
AvatarLeavesRoom += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);
AnotherOfManayAvatarEvents += new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);
}
}
class Avatar
{
public void HandleAvatarEntersRoom(object sender, EnterRoomEventArgs e)
{
Log.Write("avatar has entered the room");
}
public void HandleAvatarLeaveRoom(object sender, LeaveRoomEventArgs e)
{
Log.Write("avatar has left room");
}
public void HandleAnotherOfManayAvatarEvents(object sender, AnotherOfManyEventArgs e)
{
Log.Write("another avatar event has occurred");
}
}
Each delegate has a method named GetInvocationList() that returns all the actual delegates that have been registered. So, assuming the delegate Type (or event) is named say MyDelegate, and the handler instance variable is named myDlgHandler, you can write:
Delegate[] clientList = myDlgHandler.GetInvocationList();
foreach (var d in clientList)
myDlgHandler -= (d as MyDelegate);
to cover the case where it might be null,
if(myDlgHandler != null)
foreach (var d in myDlgHandler.GetInvocationList())
myDlgHandler -= (d as MyDelegate);
Probably the simplest way to accomplish this would be to store all of your subscribed events for an avatar in an ArrayList of delegates to the events.
When the avatar leaves the room, simply loop through the list of delegates performing a standard remove (-=).
Is there anything wrong with a standard remove?
public void RemovePlayer(Avatar theAvatar) {
AvatarEntersRoom -= new EventHandler<EnterRoomEventArgs>(theAvatar.HandleAvatarEntersRoom);
}
EDIT
Based on your update it appears that you want code that will remove a particular object from all events on a particular class. There is no realistic way to accomplish this goal. It's often a bit verbose but the best way is to individually add/remove a particular object method combo from every event.
The only way to get close to this functionality is to use reflection. You could reflectively grab all events on your class and then do some magic to find all instances of a class within the event chain. This will only be a partial solution though because it will ignore such things as a lambda expression event handlers.
you can run on all the event subscribers with:
_Event.GetInvocationList()
and remove each event handler.
Delegate[] subscribers = myEvent.GetInvocationList();
for(int i = 0; i < subscribers.Length; i++)
{
myEvent -= subscribers[i] as yourDelegateType;
}
What I'd like to do is in debug (do not think that this is good performance wise for release and one should catch it during development) throw exceptions when a class's events are not unsubscribed, this is the method that I use:
#if DEBUG
private void CheckEventHasNoSubscribers(Delegate eventDelegate)
{
if (eventDelegate != null)
if (eventDelegate.GetInvocationList().Length != 0)
{
var subscriberCount = eventDelegate.GetInvocationList().Length;
// determine the consumers of this event
var subscribers = new StringBuilder();
foreach (var del in eventDelegate.GetInvocationList())
subscribers.AppendLine((subscribers.Length != 0 ? ", " : "") + del.Target);
// throw an exception listing all current subscription that would hinder GC on them!
throw new Exception(
$"Event:{eventDelegate.Method.Name} still has {subscriberCount} subscribers, with the following targets [{subscribers}]");
}
}
#endif
The in my Dispose of the item that owns the delegate, or any other location where you're workflow supposed to release the object I would call it like this.
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (_orderCacheLock != null)
_orderCacheLock.Dispose();
if(_SettingTradeTimeOut!=null)
_SettingTradeTimeOut.Dispose();
_orderCacheLock = null;
#if DEBUG
CheckEventHasNoSubscribers(OnIsProfitable);
CheckEventHasNoSubscribers(OnPropertyChanged);
#endif
disposedValue = true;
}
}
It's then super easy to find the subscribers to these "orphaned" events and fix the code
ps:
An Extension of this "practice pattern" looks like this.
public static void CheckEventHasNoSubscribers(this Delegate eventDelegate)
{
if (eventDelegate != null)
if (eventDelegate.GetInvocationList().Length != 0)
{
var subscriberCount = eventDelegate.GetInvocationList().Length;
// determine the consumers of this event
var subscribers = new StringBuilder();
foreach (var del in eventDelegate.GetInvocationList())
subscribers.AppendLine((subscribers.Length != 0 ? ", " : "") + del.Target);
// point to the missing un-subscribed events
throw new Exception( $"Event:{eventDelegate.Method.Name} still has {subscriberCount} subscribers, with the following targets [{subscribers}]");
}
}

Categories

Resources