How to allow users to cancel a time consuming WCF service call from Silverlight application? - wcf

In a Silverlight 4.0 (with Prism) application I am maintaining, a page has a Search button which makes WCF service call asynchronously to fetch some data from database, based on the search criteria entered by the user. During the search operation (i.e. from the time Search button is clicked till the time search results are displayed on page), a progress bar window (Silverlight child window) is shown on top of the page (I know it blocks the user for the duration, but this is how all the pages of the application were designed and I cannot change it). Sometimes the Search operation takes long time (several minutes) to return and show the data, and sometimes it shows the results really fast, depending on the search criteria. Now the users want the flexibility to be able to cancel any Search operation if they feel it is taking too much time to show the results.
To address this requirement, I tried the following:
1) Added a Cancel Search button on the Progress-bar window.
2) Added a public static boolean variable (Cancel Search flag, with default value false) in the Progress bar's ViewModel.
3) In the Cancel Search button's click command handler in the same viewmodel, set the Cancel Search flag to true and then closed the Progress bar window.
4) In the asynchronous WCF Serach Service's callback method, first checked if the Progress bar's Cancel Search flag is true. If yes, ignore the results (don't do anything). Otherwise, bound the returned result to the UI as usual.
However, when testing the Cancel Search button, I found that the WCF callback method is getting called before the Cancel button's click command handler, hence the search results are getting displayed even when Cancel Search button is clicked. Obviously this will happen for short running WCF calls which gets executed and completed before the user can click the Cancel button. For long running WCF calls (which gets several minutes to get the results), the above solution may work fine. But while hitting the search button, I do not have any way to know if it is going to be a short-running async call or long running, do I? So is it at all possible to fulfill the requirement in this way or using some other way? Making synchronous WCF call perhaps (but again I gathered it's a big no-no for Silverlight?

When you subscribe to any asynchronous operation from the WCF the WCf sends back the response to the handler with the results.
In your case you have a search button which talks to WCF for result but in case where the wait time is more you want a mechanism to break the operation.
When you click on the cancel button you try to unsubscribe from the event so that you instruct not to listen the callback resulting no results. This can be achieve by using -= operator with yout callback handler.
Hope this helps.

Add a CanExecuteCancelCommand for the Cancel command that checks a boolean variable. When you initiate the call to the WCF service, set this variable to true and call the RaiseCanExecuteChanged method of the command. Equally, as soon as the WCF service returns, set the property to false and call the RaiseCanExecuteChanged method again.
This allows the user to click the button only while you are waiting for the service to return its result.
Something like this:
private bool _canCancelWCFService = false;
DelegateCommand _WCFCommand;
void Method()
{
_WCFCommand = new DelegateCommand(ExecuteWCFService, CanExecuteWCFService);
}
private bool CanExecuteWCFService()
{
return _canCancelWCFService;
}
private void ExecuteWCFService()
{
_canCancelWCFService = true;
_WCFCommand.RaiseCanExecuteChanged();
_wcfService.Completed += new EventHandler<CompletedEventArgs>(CompletedCallback);
//make WCF call here
_wcfService.DoSomething();
}
static void CompletedCallback(object sender, CompletedEventArgs e)
{
_canCancelWCFServiceCall = false;
_WCFCommand.RaiseCanExecuteChanged();
//Process results here...
}

Related

Vue server side events and showing components

How can I use server side events(sse) in vue? I'm receiving sse from backend and I need to implement that when I receive first event, I will show ringing panel on screen. Then I can accept that call and then show different panel and when I click on hang up I will show again screen like before events. It will be a call centrum.
I created method for receieving and handling event.
setupStream(){
let evtSource = new EventSource('/hzs/events.sse')
evtSource.addEventListener('call_status', event => {
let data = JSON.parse(event.data)
this.channels.push(data);
}, false)
}
Now, when I call I get something like this:
Where first curly brackets are incoming call, second are after I pick up phone and last are after I hang up.
How can I use this in app and show for example green ringing bar on screen based on events? So for every event I need different UI components.
Do I need to use vuex?
Thanks

How to get the user's new page selection in a Notebook control under Windows?

In my app, when a user has made changes to the data on one page of my notebook control, I want to prompt them to save or discard their changes when they switch to a different page. I have bound the EVT_BOOKCTRL_PAGE_CHANGING event for this, and have created a handler method.
However, I can't tell what page the user is switching to. According to the wxBookCtrlEvent docs,
under Windows, GetSelection() will return the same value as GetOldSelection() when called from the EVT_BOOKCTRL_PAGE_CHANGING handler and not the page which is going to be selected.
Is there a workaround?
I guess as a workaround, you could use a mouse handler checking for when the left button is clicked. In a handler for that event you could do a hit test to see where the click was made and store the value of the tab that was clicked. Something like this:
void MyFrame::OnLeftDown( wxMouseEvent& event )
{
long flags;
int ht = m_notebook1->HitTest( wxPoint(event.GetX(),event.GetY()), &flags);
if( (flags & wxBK_HITTEST_NOWHERE) == 0 )
{
//store the value of ht somewhere
}
event.Skip();
}
void MyFrame::OnNotebookPageChanging( wxNotebookEvent& event )
{
//use the stored value of ht here
}
under Windows, GetSelection() will return the same value as
GetOldSelection() when called from the EVT_BOOKCTRL_PAGE_CHANGING
handler and not the page which is going to be selected.
So, call GetSelection from EVT_BOOKCTRL_PAGE_CHANGED to get the new page.
No, there is no workaround (if there were a reliable way to do it, wxWidgets would have been already doing it), the underlying native control simply doesn't provide this information.
You can either ask whatever you need to ask the user about in any case, independently of the page they're switching to, or ask them after they will have already switched -- which is, of course, going to look weird if you then decide to switch back.
If you really, really need this functionality, you might use non-native wxAuiNotebook instead.

End conversation when leave page in Seam

I have a wizard in my Seam project which has four pages. When user starts the wizard by coming to the first page (wizard1.xhtml) I start a conversation. To do that in my pages.xml I have following code.
<page view-id="/pages/wizard1.xhtml">
<begin-conversation join="true"/>
</page>
At the final page of the wizard (wizard4.xhtml) I have a save button and I end the conversation by using #End annotation.
#End
public String save() {}
However while moving through the wizard, the user can redirect to a page outside the wizard by clicking a link. Note that if this happens the conversation is not yet ended.
What I want is to immediately end the conversation as soon as the user is no longer on a wizard page (wizard1.xhtml,wizard2.xhtml,wizard3.xhtml or wizard4.xhtml). I found this post but a timeout is not a good choise in my case since I want to end the conversation immediately.
I think the most straight forward and natural solution of your problem is to make your click-able link like this:
<s:link value="here is the link" view="/expectedView.xhtml"
action ="#{targetBean.endingConversation()}"/>
And your endingConversation() method can be like this:
#End
public void endingConversation(){
//do cleanup code
}
The idea is simple, you should employ a guard in every possible exiting points.
Not sure if it will work, just a thought.
Create some javascript function using a4j:jsFunction that calls a method that's annotated with #End.
You then add this jsFunction as an onClick handler to all Your links. (Not sure if onClick is the best handler though).
When the user navigates away from Your wizard the method is called and the conversation should be ended.
If you are using pages.xml (or the per-page page.xml files) to implement page navigation in your application, then you have to specify redirect behavior, for each page, based on the action string. In the navigation rule for each redirect that is not continuing your wizard conversation, you can add <end-conversation />. This is similar to other suggestions, but the result would be navigation rules files which illustrate your applications page flow including the demarcation of your long-running conversations.

Data into classes, timing, procedure

I have a style/good code question. It's one of those "not that important because it's working" things but still, I'd like some insight from the community. I'm in C# but the methodology could apply to anything OOP
So I have a class, it's essentially a container for data. I pass the class to the database instead of passing 10 parameters. The database writing class drops each data member into it's respective SQL parameter and executes the stored procedure in my database.
My question is, when I am collecting data into the class I have all of them attached to Change events. Like
private void chkIce_CheckedChanged(object sender, EventArgs e)
{
CheckBox chk = (CheckBox)sender;
if (chk.CheckState == CheckState.Checked)
outTruck.setWeather(2, true);
else
outTruck.setWeather(2, false);
}
and
private void txtTrailer_TextChanged(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
newRecord.TrailerNumber = txt.Text.ToString();
}
This goes in and sets the ice value of my class to true/false based on what the user selects. Or sets the text. It's pretty straightforward, but there is a bit of code overhead as in each control has it's own event (also the cast on sender line might be overkill). The other way would be to collect all the data at submit. Drop it all into the class then. There was something else called entity framework and ORM, but I am at the moment stuck in .NET 3.5(we are with the times) and I've read that does not apply until you get to 4.0. I've not really read if there is a standard, it seems to be more preference than anything. So, fellow stack overlowieans...what are your thoughts?
Since it looks like you're in a web page with post back, I think it's easier to have that submit button handler functions where you instantiate your object, and manually set each property to the value of its corresponding UI element. Doing the data setting on every event handler (selection changed, focus out, etc.) would require the entire page to reload. (Then, you would have to persist that object across those post backs - a tedious and error prone feat, though doable.)
Even in a desktop project, I would collect all of the values from all UI elements to build my object, in that submit button's event handler.
You would want to implement event handlers on certain UI elements if the change of state in that UI element will affect something other than the object itself. For example, a checkbox may determine whether or not the user will be able to submit - because checking it so might add a feature that costs more where the total price of their order might exceed their current balance. This is when you would check to see whether the submit button should remain enabled or become disabled.

How can I block based on URL (from address bar) in a safari extension

I'm trying to write an extension that will block access to (configurable) list of URLs if they are accessed more than N times per hour. From what I understand, I need to have a start script pass a "should I load this" message to a global HTML page (who can access the settings object to get the list of URLs), who will give a thumbs up/thumbs down message back to the start script to deny/allow loading.
That works out fine for me, but when I use the usual beforeLoad/canLoad handlers, I get messages for all the sub-items that need to be loaded (images/etc..), which screws up the #accesses/hour limit I'm trying to make.
Is there a way to synchronously pass messages back and forth between the two sandboxes so I can tell the global HTML page, "this is the URL in the window bar and the timestamp for when this request came in", so I can limit duplicate requests?
Thanks!
You could use a different message for the function that checks whether to allow the page to load, rather than using the same message as for your beforeLoad handler. For example, in the injected script (which must be a "start" script), put:
safari.self.tab.dispatchMessage('pageIsLoading');
And in the global script:
function handleMessage(event) {
if (event.name == 'pageIsLoading') {
if (event.target.url.indexOf('forbidden.site.com') > -1) {
console.log(event.timeStamp);
event.target.url = 'about:blank';
}
}
}