I am calling Policy.Execute(action) from a UI application which uses web browser control .
I am creating a predicate func
I am compiling it and creating an action to check if it returns true ..
I am using timeout on this action .
And calling Policy.Execute method .
But it throws me error .. specified cast is not valid ...
This is because anything which is not build on UI thread will cause cast issue .
Can you help how do I set timeout on document.getelement in UI application
@Dhakate I haven't used Windows Forms (and WebBrowserControl) for a while, so my guidance may be off the mark. Community input welcome from anyone closer! That said:
Can you post some of the actual code? That may help us/anyone help. A minimal, complete verifable example is best, but any actual code could be useful.
Are you using TimeoutPolicy in pessimistic mode, TimeoutStrategy.Pessimistic? TimeoutStrategy.Pessimistic does execute the passed delegate on a ThreadPool thread (the only way to 'walk away' from an execution that doesn't honour co-operative cancellation, is to execute it on another thread). So TimeoutStrategy.Pessimistic is likely incompatible with the Windows Forms requirement that UI elements are accessed on the UI thread.
If you were not using TimeoutStrategy.Pessimistic, then TimeoutPolicy _would_ execute the code on the calling thread, so I wouldn't expect TimeoutPolicy to cause any cross-thread-access concerns. But TimeoutStrategy.Optimistic cannot successfully time out a call to HtmlDocument.GetElementById(...) (EDIT: _if_ that's long-running; or any code that doesn't honour a CancellationToken), so I would expect the timeout to have no effect.
Are we sure the InvalidCastException is being caused by accessing UI elements from other than the UI thread? Memory (and this documentation?) suggests we might expect InvalidOperationException for that (but NB I am not close to Windows Forms, could be wrong).
What is the overall scenario, the overall goal of your code? What is taking a long time that you wish to apply a timeout to? Perhaps the timeout can be applied at a different level - to the underlying 'slow' operation? (if there is one)
Hope some of this is useful - comment welcome from anyone with other ideas!
Public static void until(Expression
{
Var compiledPredicate = predicate.Compile();
Action action = () =>{
While (compiledPredicate () == false)
{}
};
Var policy = Policy.Timeout(timeout, TimeoutStrategy.Pessimistic,ontimeout:(CTX,to,tsk)=>{
Var message = " timeout before completing predicate";
Throw new TimeoutException (message);
});
Policy.execute(action);
}
Policy.execute is throwing me exception ..specified cast is not valid at system.windows forms.unsafeNativeMethods.IHtMLDocument.GetLocation()
At System.window.Forms.webBrowser.get_Document()
At lambda_method(Closure )
M calling this method from my code where I am simulating using web browser control
For eg
:
Expression
Wait.Until(predicate,Timespan.FromSeconds(3));
timeoutStrategy.Optimistic is not successfully timing out .
@Dhakate Thanks for posting the code. I suspected there might be a loop waiting on the results of HtmlDocument.GetElementById(...), since I hadn't expected HtmlDocument.GetElementById(...) itself would take any significant time to return.
TimeoutStrategy.Optimistic operates via CancellationToken and assumes delegates you execute support co-operative cancellation. With optimistic timeout, you must use Execute(...) overloads taking a CancellationToken, and the executed delegate must honor that CancellationToken. You can read more about this in both the Polly readme and wiki for TimeoutPolicy.
TimeoutStrategy.Optimistic would not time out the code you have posted since that code takes no CancellationToken. For completeness, a version of the Until(...) method you posted using a CancellationToken could look something like this:
public static void Until(Expression<Func>predicate,Timespan timeout)
{
var compiledPredicate = predicate.Compile();
Action action = cancellationToken => {
while (compiledPredicate () == false) cancellationToken.ThrowIfCancellationRequested();
};
var policy = Policy.Timeout(timeout, ontimeout:(CTX,to,tsk)=>{
var message = " timeout before completing predicate";
throw new TimeoutException (message);
});
policy.Execute(action, CancellationToken.None); // CancellationToken.None here indicates you do not want to add any additional cancellation to the timing out provided by TimeoutPolicy.
}
There could be concern about that tight loop burning CPU cycles, however. And there could be many ways to simplify this.
For your specific Use Case, however: rather than polling for completeness in a loop, can you attach to an event like DocumentCompleted ? Or, if a specific element is being populated after the main document has loaded, is there any event / callback that can be attached to the code populating that element?
Ya right... Timeout.Optimistic requires cancellation token for timeout to work ..I would look into if I can reduce CPU cycles .
For now the issue is resolved. Thanks a lot for your help