I want to use Stuart's messenger plugin to give instant user messages when a business process is done. eg. in my BL class I have the code:
var message = new UserMessages(this, "STARTING PROCESS");
_messenger.Publish<UserMessages>(message );
//PROCESS START
message = new UserMessages(this, "READING FILE 1");
_messenger.Publish<UserMessages>(message);
//READING FILE 1 PROCESS
message = new UserMessages(this, "ENDING PROCESS");
_messenger.Publish<UserMessages>(message);
//END PROCESS
I want my subscriber to show the message asynchronously (instantly in the gui). I have tried to use
_token = messenger.SubscribeOnThreadPoolThread<UserMessages>(OnImportMessage);
inside my viewmodel because I thought that this is what SubscribeOnThreadPoolThread is supposed to do but it didn't show me the expected outcome meaning:
1.The user clicks a button and based on my messaging service above the user must see inside the textedit control:
1.STARTING PROCESS
2.READING FILE1
3.ENDING PROCESS
What I finally displayed on the screen was the last message "ENDING PROCESS" because eventually the whole process was part of the Main Thread.
I want to understand how to do this asynchronously with the messenger plugin.
Do I need to use additional async/await operations?
I hope this makes sense to you.
Thanks in advance
Related
I've read about cancelling fetch requests by using AbortController.abort(). Is there a way to start a request again without aborting it after calling this command?
For example, in this demo from MDN, once Cancel download has been clicked, clicking Download video will trigger the fetch again, but immediately abort it.
Is there a way to allow this request again without aborting it? So, in this case, how could you click Download video to begin the download, click Cancel download to cancel the download, and then click Download video again to start the download again? For example, if the user clicked Cancel download on accident...
You can't.
An AbortController or its signal can not be reused nor reseted. If you need to "reset" it, you have to create a new AbortController instance and use that instead.
I think this is by design. Otherwise it could get messy e.g. if you hand over the controller or signal to some external library and suddenly they could remotely un-abort your internal state.
For example, in this demo from MDN, once Cancel download has been clicked, clicking Download video will trigger the fetch again, but immediately abort it.
They fixed the example. After you click Cancel download you will be able to start a new download and cancel it again, over and over. In order to achieve that the Download button instantiate a new AbortController every time, so you get a fresh signal to abort every time:
downloadBtn.addEventListener('click', fetchVideo);
function fetchVideo() {
controller = new AbortController();
signal = controller.signal;
// ...
So it's ok to instantiate new AbortControllers for each request that you may wish to cancel.
I know this might be kind of late, but I'm leaving this answer anyways in case someone needs it.
I don't know if this is the most optimal approach, but in order to keep doing fetch requests (with 'the same' signal) I had to create a new AbortController instance for each request.
In my case (all code being contained inside a class declaration), I deleted and created a new instance every time, like so:
class Foo Extends Bar {
abort_controller_instance = false;
constructor(params){
super(params);
this.resetOrStartAbortController();
}
resetOrStartAbortController(){
if(this.abort_controller_instance){
delete this.abort_controller_instance;
}
this.abort_controller_instance = new AbortController();
}
abortFetchRequest(){
if(this.abort_controller_instance){
this.abort_controller_instance.abort();
this.resetOrStartAbortController();
}
}
...
}
Probably it's not the most elegant solution, but it works.
Regards!
Hello I'm trying to learn Meteor Js and i started building a simple task manager app.
I want to add a notification (using the notifications api), when a user adds a task from an input. My problem is that I cant find a way to send the notifications between users from the server side.
What i have so far :
Template.listPage.events({
'submit #newItem':function(e){
e.preventDefault();
//variables to insert here here. i dont post for space issues.
// Call server method for insert into db
Meteor.call('addItem',item,d,user,datestring,currentList,listName,assign);
// This is what i m trying to implement
var items = todos.find({name:item}).observe({
added:function() {
var n = new Notification("hello new task added")
}
})
},
The above works as :
The notification is shown only to the user that adds the task (not really useful).
How can I use this in server side, In order to:
Show the notification to all users using the app? Is this possible or I have to use a push notification package?
PS: I ask for users permition to receive notifications on Meteor.startup.
The problem is that you specify the observe within the click event. Therefore, only users who have triggered the event (i.e. clicked the button) will get the notification.
In order to activate the observer for everyone do the following:
Template.listPage.rendered = function(){
todos.find().observe({
added: function() {
... do whatever you want to do here
}
})
};
To add notifications, you could use a package such as yogiben:notifications:
https://atmospherejs.com/yogiben/notifications
(There might be better packages for this nowadays. Search on Atmosphere.)
Alternatively, you can roll your own solution. The basic idea would be add create a collection called Notifications. Then add notifications whenever you feel like it and publish the relevant notifications to whichever user(s) you'd like.
The code in your question will also work as long as you're publishing the relevant todos to different users.
i use windows Workflow fundation for handle many step of wizard, and after per step completed, workflow persisted and control back to user for new step, in some case may be user not completed all steps of wizard, in this case i want terminated uncompleted wizard, for this i want use a timeout time, but i do not know how do this with workflow.
another problem is i want set userId or username of current user per instance of workflow but i do not know how do this, plz guide me, tnx;
You Cancel or Terminate workflows from outside of the workflow. You do the work at the level where you created the WorkflowApplication.
Assuming you start your workflow as an application like this:
WorkflowApplication _wfApp = new WorkflowApplication(new YourWorkFlow(), inParams);
_wfApp.Run();
Then you have a reference to the WorkflowApplication as wfApp.
So you can set up a timer and then use the reference when the timer fires to terminate the workflow.
Thread.Sleep(TimeSpan.FromSeconds(1));
wfApp.Terminate(new ApplicationException("Terminating the workflow."));
You can detect the termination by capturing the workflow completed event.
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{ Do your clean up code here }
See http://msdn.microsoft.com/en-us/library/dd781832(v=vs.110).aspx
As regards your second question, are you asking how you pass the userId or username of the current user into a workflow when it starts?
If so then you create a dictionary holding the parameters you want to use and you pass it into the WorkflowApplication object before you run the workflow.
IDictionary<string, object> inParams = new Dictionary<string, string>
{
{"UserID", "12345678" },
{"UserName", "Bob" }
};
WorkflowApplication _wfApp = new WorkflowApplication(new YourWorkFlow(), inParams);
_wfApp.Run();
You must set up your workflow so that it has In Arguments called UserID and UserName of type string. You don't need to always use string. You can pass in any Type you want.
Can I create a new conference room (Asterisk ConfBridge) through Asterisk Manager Interface (AMI)? Help me please!
This response is for anyone who has struggled as me to do this, even if the first response and the comments to it may be enough.
So, you can originate a conference call, with the action Originate and the application ConfBridge (as far as i know, it comes with Asterisk, not independent).
You can see all the available fields here http://www.voip-info.org/wiki/view/Asterisk+Manager+API+Action+Originate
I will throw an example without every field, but the ones I know and needed on my app.
This is what you throw at the Asterisk Manager Interface, if you want to call someone into a conference, then add someone else (without the comments ofc.)
Action: Originate // The action type
ActionID: CreateConf-1 // This id will be linked to further events about the action
Channel: SIP/1001 // The sipId of the peer u wanna call
Timeout: 30000 // If he doesnt respons in 30000ms, drop it
CallerID: Asterisk // The id of the caller (will be seen on target phone)
Application: ConfBridge // The application
Async: true // (NOT SURE, MAYBE BULLSHIT) If false, i think you can no longer originate while he hasn't answered
Data: 1234 // Very important, this is like the conference id, will detail above
Action: Originate
ActionID: CreateConf
Channel: SIP/1000
Timeout: 30000
CallerID: Asterisk
Application: ConfBridge
Async: true
Data: 1234
So with this, one block at time, two guys will be called into a conference.
As you saw the Data field represents the identifier of the call, so if you wanna give your conference an id, use it. This way you could create and manage different conferences.
Since i work with NAMI (the nodejs library for Asterisk Manager Interface) (https://github.com/marcelog/Nami), let me also drop you how to do thanks to the lib.
var namiLib = require('nami');
var namiInstance = new (namiLib.Nami)(config); // See more about config (and everything else about nami) in their docs
namiInstance.open();
var action = new namiLib.Actions.Originate();
action.channel = 'SIP/1000';
action.data = '12345'; // my conferenceId
action.timeout = 30000;
action.callerID = 'Metisse\'s king';
action.application = 'ConfBridge';
action.async = true;
namiInstance.send(action, function (response) {
// deal with the response
});
Obviously, if you need to use NAMI to have control other Asterisk, you have to do something more generic to handle sending your actions and validating them, also watching for errors.
You can use dynamic conference(without room exist) feature and create calls using Originate command to application Confbridge.
No. You can use an AMI redirect to transfer your call to a piece of dialplan code that would read a channel variable, database look up or some other mechanism to set up a new conference, however.
For a full list of AMI actions for ConfBridge, please see: https://wiki.asterisk.org/wiki/display/AST/ConfBridge+10#ConfBridge10-ConfBridgeAsteriskManagerInterface(AMI)Actions
Created a workflow with basic as below.
Created a calss library, used ProgId, set comvisible true and registerd the assembly in the Tridion server.
This is the way i have tested:
Created a component
Finished the activity from the work list.
Navigated to the "Global Work list" and finished the Reviewer activity by myself by choosing the "Back to Author" step and clicked the "Finish" button.
The item is not moved to the author. but when i finish the activity again from the global work list, the item moved to author.
It seems that my code is not performing the activity because i tried removed the below VB script code and tried with the default automatic script code.
' Script for Automatic Activity Content Manager Workflow
FinishActivity "Automatic Activity Finished"
It behaves the same as above. so i decided my code is not worked. Can any one please help on this?
Below is the VBScript I used in the script box of "Back to Author":
Option Explicit
Dim workflowHandler
Set workflowHandler = CreateObject("CoreComponentWorkflow.WorkflowHandler");
If Not workflowHandler Is Nothing Then
Call workflowHandler.MoveBackToActivity(Cstr(CurrentWorkItem.ID, "Create or Edit Component")
End If
Set workflowHandler = Nothing
Below is the C# Code:
public void MoveBackToActivity(string workitemid, string strActivitytoMove)
{
try
{
Session session = new Session();
WorkItem workitem = new WorkItem(new TcmUri("workitemid"), session);
ActivityInstance currentactivity = workitem.Activity as ActivityInstance;
ProcessInstance procInstance = currentactivity.Process as ProcessInstance;
IEnumerable<ActivityInstance> ieActivities = procInstance.Activities
.Select (s => s)
.Where (w => w.Title.IndexOf(strActivitytoMove) !=-1)
.OrderByDescending(w =>w.StartDate);
if (ieActivities != null && ieActivities.Count<ActivityInstance>() > 0)
{
ActivityInstance targetactivity = ieActivities.ElementAt(0);
User lastperformuser = targetactivity.Performers.ElementAt(targetactivity.Performers.Count<User>() - 1);
ActivityFinish finish = new ActivityFinish(targetactivity.FinishMessage, lastperformuser, workitem.Session);
currentactivity.Finish(finish);
}
}
catch (Exception ex)
{
throw ex;
}
}
Be aware that you are using an API that is NOT supported in Automatic Activities. The only processes where you are allowed to use TOM.NET are Event System handlers and Template Building Blocks as documented here.
Automatic Workflow Activities - if not developed with VBScript - must use the CoreService interface.
The good news is that I know for a fact this works - plenty of people got it to work in many implementations. The bad news (for you) is that the error is in your code. Have you tried debugging/step-by-step through your code yet? You can attach to to the workflow process (cm_wf_svc.exe) and figure out what's wrong with the code much faster than we can.
Here's a really simple snippet to finish an activity with CoreService:
ActivityFinishData activityFinish = new ActivityFinishData
{
Message = "Automatically Finished from Expiration Workflow Extension"
};
ActivityInstanceData activityInstance =
(ActivityInstanceData)processInstance.Activities[0];
client.FinishActivity(activityInstance.Id, activityFinish, readOptions);
BTW - If you intended to use TOM.NET anyway, why did you bother asking which API to use?
Following the Nuno's answer, yes you should change the code to use TOM or Core Services. TOM .Net is not supported because it is using a different thread apartment than the underlying technology we use for workflow (COM).
About the issue I have checked that you are calling the activity like this.
Call workflowHandler.MoveBackToActivity(Cstr(CurrentWorkItem.ID, "Create or Edit Component")
It looks like the activity name is not matching. there are some strange characters between "Edit" and "Component"
I hope this helps.
Automatic activities are executed by the Workflow agent service. An Assigned state may indicate that it's just not being picked up by the service. Is your service running correctly, and are things like queue notifications set up properly?