New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with IDispatcherService after update to version 5.0 #1112

Closed
szogun1987 opened this Issue Aug 22, 2017 · 14 comments

Comments

Projects
None yet
2 participants
@szogun1987
Contributor

szogun1987 commented Aug 22, 2017

It is only placeholder for issue. Issue occurred while regression testing of our app, after upgrade to version 5.0 of Catel. I haven't yet fully analyzed issue, and I'm not sure if it caused by Catel but it is highly probable.

Steps to reproduce

TBD

Platform:
.NET version: 4.5

Expected behaviour

App shouldn't crash

Actual behaviour

App crashes with stacktrace:

Exception have occurred
Exception: System.InvalidOperationException: Dispatcher processing has been suspended, but messages are still being processed.
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Aug 22, 2017

Member

This could be related to the implementation of the UIVisualizerService in 5.0. Can you please try 5.1?

Member

GeertvanHorrik commented Aug 22, 2017

This could be related to the implementation of the UIVisualizerService in 5.0. Can you please try 5.1?

@GeertvanHorrik GeertvanHorrik added this to the 5.2.0 milestone Aug 22, 2017

@GeertvanHorrik GeertvanHorrik added the bug label Aug 22, 2017

@GeertvanHorrik GeertvanHorrik self-assigned this Aug 22, 2017

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Aug 30, 2017

Member

Please provide more info if you can reproduce.

Member

GeertvanHorrik commented Aug 30, 2017

Please provide more info if you can reproduce.

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Sep 5, 2017

Contributor

Sorry for delay. Our management changed priorities and currently I'm don't work on Catel update, I will prepare branch with 5.1 build and ask tester privately for reproduction tomorrow.

Contributor

szogun1987 commented Sep 5, 2017

Sorry for delay. Our management changed priorities and currently I'm don't work on Catel update, I will prepare branch with 5.1 build and ask tester privately for reproduction tomorrow.

@GeertvanHorrik GeertvanHorrik modified the milestones: 5.3.0, 5.2.0 Sep 12, 2017

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Sep 29, 2017

Contributor

Sorry for delay again. Crash still occurs on 5.1 version downloaded from nuget today :(

Contributor

szogun1987 commented Sep 29, 2017

Sorry for delay again. Crash still occurs on 5.1 version downloaded from nuget today :(

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Sep 29, 2017

Member

Too bad :-(

Is this problem isolatable? We have quite some large WPF apps written on Catel and all the Orc components, and we don't have this issue.

Member

GeertvanHorrik commented Sep 29, 2017

Too bad :-(

Is this problem isolatable? We have quite some large WPF apps written on Catel and all the Orc components, and we don't have this issue.

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Oct 2, 2017

Contributor

Some changes in Catel interacts with ActiveX component we are using in our project. It is pretty hard to detect where the problem is (Probably it last issue that stop us for update Catel).

Contributor

szogun1987 commented Oct 2, 2017

Some changes in Catel interacts with ActiveX component we are using in our project. It is pretty hard to detect where the problem is (Probably it last issue that stop us for update Catel).

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Oct 19, 2017

Contributor

I have found reason. We have used BeginInvoke to delay execution of action on main thread (like SetTimeout(0 in javascript). Hack have been added because some operation cannot be perform at time when action is executed. Changes in Catel 5.x makes dispatcher service to execute action immediately if is called from main thread. I suppose that similar hacks are present in many projects. The question is: should we restore previous implementation for backward capability or should we create article how migrate hack to newer version?

Contributor

szogun1987 commented Oct 19, 2017

I have found reason. We have used BeginInvoke to delay execution of action on main thread (like SetTimeout(0 in javascript). Hack have been added because some operation cannot be perform at time when action is executed. Changes in Catel 5.x makes dispatcher service to execute action immediately if is called from main thread. I suppose that similar hacks are present in many projects. The question is: should we restore previous implementation for backward capability or should we create article how migrate hack to newer version?

@GeertvanHorrik GeertvanHorrik modified the milestones: 5.3.0, 5.4.0 Jan 19, 2018

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Mar 22, 2018

Member

@szogun1987 sorry for the late reply, must have missed this one. I think it's because of the "onlyDispatcherWhenRequired". I think we can add that to the method as a non-breaking change. Would that solve the issue for you?

Member

GeertvanHorrik commented Mar 22, 2018

@szogun1987 sorry for the late reply, must have missed this one. I think it's because of the "onlyDispatcherWhenRequired". I think we can add that to the method as a non-breaking change. Would that solve the issue for you?

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Mar 22, 2018

Contributor

I have solved it with schedulerService - schedule(0 s). It seems to be more proper solution of the problem

Contributor

szogun1987 commented Mar 22, 2018

I have solved it with schedulerService - schedule(0 s). It seems to be more proper solution of the problem

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Mar 22, 2018

Member

Excellent, then I will close this ticket. Thanks for the feedback.

Member

GeertvanHorrik commented Mar 22, 2018

Excellent, then I will close this ticket. Thanks for the feedback.

@GeertvanHorrik GeertvanHorrik removed this from the 5.4.0 milestone Mar 22, 2018

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Mar 22, 2018

Contributor

I thinks it is something worth to mention in release notes.
Usage of dispatcher to delay a little bit execution of operation is well known pseudo-pattern used in many applications (just like setTimeout(0) in javascript :-) ).

Contributor

szogun1987 commented Mar 22, 2018

I thinks it is something worth to mention in release notes.
Usage of dispatcher to delay a little bit execution of operation is well known pseudo-pattern used in many applications (just like setTimeout(0) in javascript :-) ).

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Mar 26, 2018

Member

That's an excellent point so I did some digging into this. The IDispatcherService provides these methods:

        /// <summary>
        /// Executes the specified action with the specified arguments synchronously on the thread the Dispatcher is associated with.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="onlyInvokeWhenNoAccess">If set to <c>true</c>, the action will be executed directly if possible. Otherwise, 
        /// <c>Dispatcher.BeginInvoke</c> will be used.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="action"/> is <c>null</c>.</exception>
        void Invoke(Action action, bool onlyInvokeWhenNoAccess = true);

        /// <summary>
        /// Executes the specified delegate asynchronously with the specified arguments on the thread that the Dispatcher was created on.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="onlyBeginInvokeWhenNoAccess">If set to <c>true</c>, the action will be executed directly if possible. Otherwise, 
        /// <c>Dispatcher.BeginInvoke</c> will be used.</param>
        void BeginInvoke(Action action, bool onlyBeginInvokeWhenNoAccess = true);

Did you try passing in false for the last parameter?

Member

GeertvanHorrik commented Mar 26, 2018

That's an excellent point so I did some digging into this. The IDispatcherService provides these methods:

        /// <summary>
        /// Executes the specified action with the specified arguments synchronously on the thread the Dispatcher is associated with.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="onlyInvokeWhenNoAccess">If set to <c>true</c>, the action will be executed directly if possible. Otherwise, 
        /// <c>Dispatcher.BeginInvoke</c> will be used.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="action"/> is <c>null</c>.</exception>
        void Invoke(Action action, bool onlyInvokeWhenNoAccess = true);

        /// <summary>
        /// Executes the specified delegate asynchronously with the specified arguments on the thread that the Dispatcher was created on.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <param name="onlyBeginInvokeWhenNoAccess">If set to <c>true</c>, the action will be executed directly if possible. Otherwise, 
        /// <c>Dispatcher.BeginInvoke</c> will be used.</param>
        void BeginInvoke(Action action, bool onlyBeginInvokeWhenNoAccess = true);

Did you try passing in false for the last parameter?

@szogun1987

This comment has been minimized.

Show comment
Hide comment
@szogun1987

szogun1987 Mar 27, 2018

Contributor

No I haven't.
Are you sure that this parameter makes sense for sync version of method? Waiting for code execution may cause deadlock: dispatcher would wait for operation calls Invoke method to complete, Invoke method would wait for dispatcher to execute action. It is possible that dispatcher itself solves this problem by calling action inline.

Contributor

szogun1987 commented Mar 27, 2018

No I haven't.
Are you sure that this parameter makes sense for sync version of method? Waiting for code execution may cause deadlock: dispatcher would wait for operation calls Invoke method to complete, Invoke method would wait for dispatcher to execute action. It is possible that dispatcher itself solves this problem by calling action inline.

@GeertvanHorrik

This comment has been minimized.

Show comment
Hide comment
@GeertvanHorrik

GeertvanHorrik Mar 27, 2018

Member

Yes, you either execute the method via the dispatcher or not, it shouldn't matter if it's sync or not (but we recommend using the new BeginInvokeAsync if you want to await it).

Member

GeertvanHorrik commented Mar 27, 2018

Yes, you either execute the method via the dispatcher or not, it shouldn't matter if it's sync or not (but we recommend using the new BeginInvokeAsync if you want to await it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment