Below is the handler method in the CefSharp Example (link) for OnBeforeUnloadDialog. What does it mean by execute callback once user has responded?
bool IJsDialogHandler.OnBeforeUnloadDialog(IWebBrowser browserControl, IBrowser browser, string message, bool isReload, IJsDialogCallback callback)
{
//Custom implementation would look something like
// - Create/Show dialog on UI Thread
// - execute callback once user has responded
// - callback.Continue(true);
// - return true
//NOTE: Returning false will trigger the default behaviour, no need to execute the callback if you return false.
return false;
}
Related
I have a WPF application that uses MVVM pattern. I have controls in the window that are bound to properties in the ViewModel. I have a Play button that is bound to the Play() method via an ICommand interface implementation. As the Play() method steps through, I first change some properties to alter the UI to show the user that the app is working:
IsPlaying = true;
IsNotPlaying = false;
DurationTimer.Start();
Status = $"Playing: {_playingUrl}";
FilePreview?.FileNameSet(_playingUrl, "");
FilePreview?.FilePlayStart();
When the Play button is pressed it should disable the Play button via the IsPlaying property and enable the Stop button via the IsNotPlaying property. Also, the DurationTimer should start (which displays a timer) and the Status property. These are intended, as said, to show the user that things are happening since FilePreview?.FilePlayStart(); is a blocking method and the UI locks up while processing.
However, when the Play button is pressed the UI immediately locks and, then, once the FilePlayStart() method finishes its processing, it releases and the other items become effective.
Am I missing something?
WPF, like most of UI frameworks, updates the UI only from one single Thread (any attempt to update the UI from another Thread will raise a System.InvalidOperationException).
Now, since the UI Thread is busy executing your method, it cannot update the UI at the same time.
WPF works with "bulks" of code. Once a bulk is executed, the UI takes care of all the updates. AT THE END of the execution, not in the middle.
So, if in the Execute method (or any other method executed on the UI Thread) you set 40 times "can execute = true", "can execute = false", "can execute = true", "can execute = false", actually you won't see the Button being unabled and disabled 40 times. Instead, when the method exits, THEN the UI is updated with the last value.
So, how to solve this? The Execute method should be asynchronous.
Something like:
public class Command : ICommand
{
//ICommad implementation and other stuffs
//...
public async void Execute(object parameter)
{
await DoExecute(parameter);
}
private async Task DoExecute(object parameter)
{
//do something asynchronously...
}
}
In your specific case, FilePreview?.FilePlayStart(); should be asynchronous, and you should pass this method to the Command.
You can write a general Command:
public class Command : ICommand
{
//ICommad implementation and other stuffs
//...
//pass the execution in the constructor
public Command(Func<object, Task> execution)
{
_execution = execution;
}
private Func<object, Task> _execution;
public async void Execute(object parameter)
{
await _execution(parameter);
}
private async Task DoExecute(object parameter)
{
//do something asynchronously... like await Task.Delay(2000);
}
}
You can then use it this way in the owner of the Command:
MyCommand = new Command(async parameter =>
{
IsPlaying = true;
IsNotPlaying = false;
await FilePreview?.FilePlayStartAsync();
});
As soon as the await part is entered, the execution pass to another Thread, and the current Thread (that is the UI Thread) is free to update the UI, and you will see that the Buttons are enabled/disabled as you want.
If an async version of the method is not available, you can write:
MyCommand = new Command(async parameter =>
{
IsPlaying = true;
IsNotPlaying = false;
await Task.Run(() => FilePreview?.FilePlayStart());
});
You can't perform long running operations on the UI thread, as it will block the dispatcher until it is done processing.
In cases like this, just use async/await to free the dispatcher and allow message pumping to continue.
private async void PlayCommand()
{
IsPlaying = true;
IsNotPlaying = false;
DurationTimer.Start();
Status = $"Playing: {_playingUrl}";
await Task.Run(()=>
{
FilePreview?.FileNameSet(_playingUrl, "");
FilePreview?.FilePlayStart();
});
}
I have a following class:
public class SessionStore {
Subject<Session, Session> subject;
public SessionStore() {
subject = new SerializedSubject<>(BehaviorSubject.create(new Session());
}
public void set(Session session) {
subject.onNext(session);
}
public Observable<UserSession> observe() {
return subject.distinctUntilChanged();
}
}
In activity I observe the session and perform network operation on each change:
private Subscription init() {
return sessionStore
.observe()
.flatMap(new Func1<Session, Observable<Object>>() {
#Override
public Observable<Object> call(Session session) {
return (session.isValid()
? retrofitService.getThingForValid()
: retrofitService.getThingForInalid())
.subscribeOn(Schedulers.io());
}
})
.subscribe(...);
}
Now I have an Okhttp request interceptor, in which I set the session instance from valid to invalid when network response is non 200 code.
This is what happens:
On initial subscription to session store the getThingForValid() is executed, and fails.
OkHttp intercepts the fail and sets new session.
Session store emits a new, now invalid session.
The new emission executes a getThingForInvalid() method.
What is important to know is that this execution happens in the middle of the previous Retrofit call. This is because OkHttp client is wrapped by Retrofit and all interceptors are executed before Retrofit returns.
Having this in mind, you realize that the second call is being executed and processed by Retrofit already, while the first one hasn't finished yet.
As the first call finishes, it throws HttpException because response was non 200 code.
The xception kills the rx stream and with it the second call.
I have tried to ignore this exception in stream but the second call is cancelled by Retrofit anyways.
Do you have any ideas how to make my concept work please?
if you get response code 401 in case of token expiration:
you need to add Authenticator in to OkHttpClient.Builder
builder.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
final LoginResponse newLoginResponse = refreshTokenClient.refreshToken();
//save new token locally, if needed
return response
.request()
.newBuilder()
.removeHeader("Api-Auth-Token") // removing old header
.addHeader("Api-Auth-Token", newLoginResponse.getAuthToken())
.build();
}
});
where
public interface RefreshTokenService {
#PUT("/api/v1/tokens")
LoginResponse refreshToken();
}
But pay attention: this Authenticator will run each time when response code is 401.
My demo application implements the MVVM pattern in a WPF project. The ViewModel calls a remote webservice via a service agent (proxy) like this:
proxy.GetProjectList((sender, e) => this.ProjectList, username, password);
ProjectList is a property defined in the ViewModel. It holds an array of CProject objects. The view binds to this property to display the project names. Basically this works fine.
However I get a NullReferenceException if I add the following if-statement:
proxy.GetProjectList((sender, e) => this.ProjectList = e.Result, username, password);
if (ProjectList.Length > 0) doSomething();
Debugging the application shows that the ProjectList property is null after the webservice has been called. And I just dont't know why.
The webservice call above is implemented as follows:
public void GetProjectList(EventHandler<getProjectListCompletedEventArgs> callback, string username, string password) {
proxy.getProjectListCompleted += callback;
proxy.getProjectListAsync(username, password);
}
You're using the Async version of the method. That's why the ProjectList property does not immediately get populated after your method call.
I suggest you research a little bit about sync and async.
Also, to make this work, place your if code inside the lambda expression (or otherwise in a separate callback method to be called when the service call is completed)
Following the hint from HighCore I changed my implementation to the following.
Calling the operation from the client:
proxy.GetProjectList(GetProjectListCallback, Username, SecurePassword);
Adding the callback method before:
private void GetProjectListCallback(object sender, getProjectListCompletedEventArgs e) {
ProjectList = e.Result;
if (ProjectList != null) {
if (ProjectList.Length > 0) doSomething();
}
}
Calling the actual webservice operation in a seperate service agent:
public void GetProjectList(getProjectListCompletedEventArgs callback, string username, SecureString password) {
proxy.getProjectListCompleted += callback;
proxy.getProjectListAsync(username, password);
}
I don't know if this is a good programming style but it works :-)
I have a WPF application in PRISM architecture.
I have a 'Login View' that is shown in the 'Main Region' when the app loads.
When the user presses 'Login' - I connect to a WCF service, authenticate the user, and get a list of roles for that user from the service.
Then - according to the user's roles - I load different modules, using the 'Module Manager'.
Problem is - I want all the work after the 'Login' button is pressed to be done in a separate thread, because it might take time to connect to the service etc, and I don't want the UI to be frozen.
But - if I put the code to 'connect, authenticate, get roles, load modules' in a separate thread - I get an exception when I call '_moduleManager.LoadModule' that says:
The calling thread must be STA, because many UI components require this.
How can I solve this ?
I have tried different solutions.
I have tried to set the new thread's 'Apartment State = STA' and it didn't help.
I thought about saving the 'Dispatcher' object in the constructor of the View-Model, and then do 'dispatcher.Invoke' when I call 'LoadModule', but that is bad design (View-Model should not use Dispatcher, and also it is bad for testing).
Any ideas how I can solve this ??
Only the 'LoadModule' gives me grief, all the other stuff works fine.
.
[Update] - Added Code Sample :
[Export]
public class LoginViewModel : NotificationObject
{
[ImportingConstructor]
public LoginViewModel(IRegionManager regionManager, IModuleManager moduleManager)
{
this.LoginCommand = new DelegateCommand(LoginExecute, LoginCanExecute);
this._regionManager = regionManager;
this._moduleManager = moduleManager;
}
private void LoginExecute()
{
IsBusy = true; // Set this to 'true' so controls go disabled
LoginStatus = ""; // Clear the 'login status' string
Thread loginThread = new Thread(new ThreadStart(LoginWork));
loginThread.SetApartmentState(ApartmentState.STA);
loginThread.Start();
}
private void LoginWork()
{
ParamsToGetRoles param = new ParamsToGetRoles
{
Username = Username,
InputtedPassword = Password
};
try
{
// Connect to the secure service, and request the user's roles
_clientSecure = new AuthenticationServiceClient("WSHttpBinding_MyService");
_clientSecure.ClientCredentials.UserName.UserName = param.Username;
_clientSecure.ClientCredentials.UserName.Password = param.InputtedPassword;
_clientSecure.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted);
var local = _clientSecure.ChannelFactory.CreateChannel();
_clientSecure.GetRolesCompleted += new EventHandler<GetRolesCompletedEventArgs>(clientSecure_GetRolesCompleted);
_clientSecure.GetRolesAsync(param);
}
catch (Exception ex)
{
Console.WriteLine("Exception : " + ex.Message.ToString());
}
}
void clientSecure_GetRolesCompleted(object sender, GetRolesCompletedEventArgs e)
{
if (e.Error == null)
{
_clientSecure.Close();
LoginSuccess(e.Result.UserRoles);
}
else
{
LoginFailure("Unable to authenticate");
}
_clientSecure = null;
}
private void LoginSuccess(List<UserTypeEnum> rolesOfAuthenticatedUser)
{
LoginStatus = "Success";
if (rolesOfAuthenticatedUser.Contains(UserTypeEnum.Administrator))
{
// This is what throws the exception !
// This is called by the 'EndInvoke' of the 'GetRoles' operation,
// Which was called in the 'LoginWork' function which was run on a separate thread !
_moduleManager.LoadModule(WellKnownModuleNames.ModuleAdmin);
}
NavigateToMainMenu();
this.IsBusy = false;
}
}
You should attach the debugger and inspect the threads window with a breakpoint set at clientSecure_GetRolesCompleted. I'm pretty sure it is not being called from the loginThread: while LoginWork does run in the loginThread, it then adds an eventhandler to the completion event of an async operation. Async = runs in yet another thread.
So what probably happens:
LoginExecute executes in the UI thread
starts a seperate thread B to run LoginWork
calls GetRolesAsync so start a thread C (which is not STA) to get the roles
thread C eventually calls 'clientSecure_GetRolesCompleted', not thread B
So, you do not need a seperate thread for LoginWork since the actual work is already done as an async operation. To get around the loading issue, either try to make the 'get roles' thread STA, or better, use a dispatcher so LoginSuccess gets invoked on the UI thread.
I have a typical Silverlight application with a WCF service and I am using slsvcutil.exe to generate the standard client proxy to communicate with the web service. I am trying to write unit tests and I'm attempting to use the Silverlight Unit Testing framework and Moq to mock the proxy and remove the service dependency for testing.
I am very new to Moq and having a lot of trouble automatically raising the various Completed events on the mocked proxy automatically when service calls are made to simulate the async calls.
In order to make the proxy "mockable" I've created my own simple interface for the generated proxy calls and their completed events:
public interface IServiceProxy
{
void TestAsync(TestRequest request);
void TestAsync(TestRequest request, object userState);
event EventHandler<TestCompletedEventArgs> TestCompleted;
}
I also subclassed the generated proxy object to implement that interface:
public class MyServiceProxy : GeneratedServiceClient, IServiceProxy, ICommunicationObject
{
// ... overloaded proxy constructors
}
After looking at the Moq documentation, this is how I am attempting to set up the mock to expect the TestAsync() call and immediately raise the TestCompleted event with the result in the EventArgs:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var result = new TestResponse() { Value = true };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
// rest of the test to actually use the mock and assert things
}
Everything builds fine, but when I attempt to run any kind of test using the mock and set break points the TestCompleted event is never being raised when I call TestAsync().
Is there anything obvious that I am missing or any better ideas about mocking these types of async service proxies in Silverlight?
Thanks!
EDIT:
To be more clear what I am actually trying to test is a helper class I made which takes an instance of IServiceProxy and provides a cleaner service interface for my ViewModel to use by accepting Action<TResponse, Exception> callback parameters rather than dealing with callback events in my ViewModel. I understand how I could mock this as well to directly test my ViewModel but I figured it would be nice to test the helper class by itself first.
Here is an example of what I am talking about:
public class HelperClient : IServiceHelper
{
private IServiceProxy proxy;
public HelperClient(IServiceProxy proxy)
{
this.proxy = proxy;
// register to handle all async callback events
this.proxy.TestCompleted += new EventHandler<TestCompletedEventArgs>(TestCompleted);
}
public void Test(TestRequest request, Action<TestResponse, Exception> response)
{
this.proxy.TestAsync(request, response);
}
private void TestCompleted(object sender, TestCompletedEventArgs e)
{
var response = e.UserState as Action<TestResponse, Exception>;
if (response != null)
{
var ex = GetServiceException(e);
if (ex == null)
{
response(e.Result, null);
}
else
{
response(null, ex);
}
}
}
}
So in my test what I am really doing is mocking ISerivceProxy and passing it in and just attempting to test a service call to make sure the wrapper it invoking the Action correctly:
[TestMethod]
[Asynchronous]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null));
helper.Test(new TestRequest(), (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
EnqueueTestComplete();
});
}
The problem is that the mocked proxy object is never raising the TestCompleted event so my response action is never getting invoked to finish the test (even though the test appears to complete successfully the Assert is never actually run). Sorry for such a long post, just trying to show you as much code as possible.
EDIT 2
Added [Asynchronous] and call to EnqueueTestComplete() which I realized I may need to make the test wait for the event to be raised. This did not really help, the event is still never raised so the test just hangs and never completes.
EDIT 3
Aliostad's answer was correct that my setup expectation's signature did not match the actual Test() signature allowing me to pass in a response Action as the second param. Stupid mistake, but that is what was preventing Moq from raising the Completed event. I was also forgetting to pass the Action in as the userState object in the TestCompletedEventArgs so that it would actually be invoked when the Completed event was raised. Also, the [Asynchronous] and EnqueueTestCompleted did not seem to be necessary in this case.
Here is updated test code for anyone interested:
[TestMethod]
public void Test_Returns_Expected()
{
var mockProxy = new Mock<IServiceProxy>();
var helper = new HelperClient(mockProxy.Object);
bool expectedResult = true;
var result = new TestResponse() { Value = expectedResult };
Action<TestResponse, Exception> responseAction = (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
};
this.mockProxy.Setup(
p => p.TestAsync(It.IsAny<TestRequest>(), It.IsAny<Action<TestResponse, Exception>>()))
.Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, responseAction));
helper.Test(new TestRequest(), responseAction);
}
Mocking events is quite a pain and unit tests become brittle. But as you said there is no way around it. But normally you would make the call you are trying to test and block the current thread (using Sleep or other methods) until event is raised (or a time-out).
It is actually not clear what you are testing. I can see a mock and a response, where is the actual real object?
I will update my answer accordingly.
UPDATE
I can see a problem here:
helper.Test(new TestRequest(), (response, ex) =>
{
Assert.AreEqual(expectedResult, response.Value);
EnqueueTestComplete();
});
in the last statement, you are putting EnqueueTestComplete(); and you assert but this action will never be used because it is passed to the moq object.
Also you are setting the expectation for TestAsync(It.IsAny<TestRequest>())) (one argument) while you are calling it with two arguments in the HelperClient (this.proxy.TestAsync(request, response);) and that is why it never gets fired since expectation is not met.
just searched for mock asynchronous WCF client and found this question.
to prevent this situation Moq can .Verify() that p.TestAsync() has been invoked.
//will throw MockException if p.TestAsync() has never been called.
this.mockProxy.Verify(p => p.TestAsync(It.IsAny<TestRequest>()), Times.Once());