WF6 Workflow Foundation resume without applying changes to PersistentStore - c#

I need to simulate an existing WF process "on dry", meaning it was persisted to db and now I resume it to collect various "what-if" data.
After it completes, I Abort() it, but it leaves WF instance void.
app = new WorkflowApplication(flowChart);
app.Load("guid");
app.InstanceStore = CreateInstanceStore();
var evt = new AutoResetEvent(false);
app.PersistableIdle = e =>
{
evt.Set();
return PersistableIdleAction.None;
};
app.ResumeBookmark("bookmark");
evt.WaitOne();
app.Abort();
private SqlWorkflowInstanceStore CreateInstanceStore()
{
SqlWorkflowInstanceStore instanceStore = new SqlWorkflowInstanceStore(connectionString)
{
InstanceCompletionAction = InstanceCompletionAction.DeleteNothing
};
var instanceHandle = instanceStore.CreateInstanceHandle();
var view = instanceStore.Execute(instanceHandle,
new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(10));
instanceHandle.Free();
instanceStore.DefaultInstanceOwner = view.InstanceOwner;
return instanceStore;
}
I need to "undo" any changes the wf state may have done to persistent store.
Any suggestions?

Related

How do I use UI Automation with ChromiumWebBrowser?

I'm trying to use UI automation with ChromiumWebBrowser, so I managed to make it work by passing force-renderer-accessibility command line option to settings. It got available on inspect.exe tool but I still couldn't find it by code. Could anyone just give me a code sample?
Here's how I initialize the ChromiumWebBrowser:
void InitializeChromiumWebBrowser()
{
var settings = new CefSettings()
{
CefCommandLineArgs = {
new KeyValuePair<string, string>("force-renderer-accessibility", "true")
},
MultiThreadedMessageLoop = false
};
Cef.Initialize(settings);
m_chromeBrowser = new ChromiumWebBrowser("http://127.0.0.1/calc.html");
m_chromeBrowser.Name = "chromiumWebBrowser";
var t = new Timer { Interval = 5 };
t.Start();
t.Tick += (s, e) => BeginInvoke((Action)(() => Cef.DoMessageLoopWork()));
m_chromeBrowser.LoadingStateChanged += M_chromeBrowser_LoadingStateChanged;
browser_tabPage.Controls.Add(m_chromeBrowser);
}
I'm trying to manipulate them with UI Automation, but I couldn't find even the top window:
using (var proc = Process.GetCurrentProcess())
{
var root = AutomationElement.FromHandle(proc.MainWindowHandle);
var browser = root.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.ClassNameProperty, "CefBrowserWindow")); // Always null
}
But browser always is null. What am I missing?

Make Async function run completely in the background

I have a timer that calls a method every 15 seconds and that method takes some time to finish.
I have converted it to async as much as possible for me but it still freezes the UI for almost 1 sec when it runs and since it runs every 15 seconds, it becomes annoying.
Any idea how to make this async method run completely off the grid?
This is the timer method:
public static DispatcherTimer UpdateList = new DispatcherTimer();
//GlobalVars.MainList = new List<string>(); //saved list from previous declaration
public MainFunction()
{
this.InitializeComponent();
UpdateList.Tick += UpdateList_Tick; ;
UpdateList.Interval = new TimeSpan(0, 0, 0, 0, 15000);
UpdateList.Start();
//...
}
private async void UpdateList_Tick(object sender, object e)
{
using (var client = new ImapClient())
{
using (var cancel = new CancellationTokenSource())
{
await client.ConnectAsync("imap.gmail.com", 993, true, cancel.Token);
client.AuthenticationMechanisms.Remove("XOAUTH");
await client.AuthenticateAsync("email.com", "mail12345", cancel.Token);
var inbox = client.Inbox;
await inbox.OpenAsync(FolderAccess.ReadOnly, cancel.Token);
// let's try searching for some messages...
DateTime date = DateTime.Now;
DateTime mondayOfLastWeek = date.AddDays(-(int)date.DayOfWeek - 6);
var query = SearchQuery.DeliveredAfter(mondayOfLastWeek)
.And(SearchQuery.SubjectContains("search"))
.And(SearchQuery.All);
List<string> newList = new List<string>();
foreach (var uid in inbox.Search(query, cancel.Token))
{
var message = inbox.GetMessage(uid, cancel.Token);
string trimmedMSGEmtyLines = Regex.Replace(message.TextBody, #"^\s+$[\r\n]*", "", RegexOptions.Multiline);
newList.Add(message.Date.LocalDateTime + Environment.NewLine + trimmedMSGEmtyLines);
}
await client.DisconnectAsync(true, cancel.Token);
if (!GlobalVars.MainList.SequenceEqual(newList))
{
GlobalVars.MainList = newList;
}
}
}
}
Update:
MailKit, Portable.Text.Encoding, MimeKit
async / await is useful when executing long running operations, which are decoupled from the UI, while running on a UI thread. This is exactly what you are doing - but it seems you have no business being on the UI thread in the first place. Really, you could await the entire contents of your event handler as it's wholly decoupled from the UI. So it's not the right tool for the job.
BackgroundWorker was suggested, which would be a great option. I chose to provide a solution using System.Threading.Timer because there is not much code to change vs. your existing code. If you add any code which updates the UI, you will need to invoke it back to the dispatcher thread.
And all those async methods could probably run synchronously. I would remove async / await then choose synchronous methods, for example client.ConnectAsync() >> client.Connect()
public System.Threading.Timer UpdateTimer;
public MainFunction()
{
this.InitializeComponent();
UpdateTimer = new System.Threading.Timer(UpdateList_Tick);
UpdateTimer.Change(0, 15000);
//...
}
private async void UpdateList_Tick(object state)
{
using (var client = new ImapClient())
{
using (var cancel = new CancellationTokenSource())
{
await client.ConnectAsync("imap.gmail.com", 993, true, cancel.Token);
client.AuthenticationMechanisms.Remove("XOAUTH");
await client.AuthenticateAsync("email.com", "mail12345", cancel.Token);
var inbox = client.Inbox;
await inbox.OpenAsync(FolderAccess.ReadOnly, cancel.Token);
// let's try searching for some messages...
DateTime date = DateTime.Now;
DateTime mondayOfLastWeek = date.AddDays(-(int)date.DayOfWeek - 6);
var query = SearchQuery.DeliveredAfter(mondayOfLastWeek)
.And(SearchQuery.SubjectContains("search"))
.And(SearchQuery.All);
List<string> newList = new List<string>();
foreach (var uid in inbox.Search(query, cancel.Token))
{
var message = inbox.GetMessage(uid, cancel.Token);
string trimmedMSGEmtyLines = Regex.Replace(message.TextBody, #"^\s+$[\r\n]*", "", RegexOptions.Multiline);
newList.Add(message.Date.LocalDateTime + Environment.NewLine + trimmedMSGEmtyLines);
}
await client.DisconnectAsync(true, cancel.Token);
if (!GlobalVars.MainList.SequenceEqual(newList))
{
GlobalVars.MainList = newList;
}
}
}
}

SSDP (UDP) on Windows Store applications (.NET)

I am trying to implement a basic SSDP (UDP) broadcast/listener for a Windows Store application using C#.
I have found that Windows.Networking.Sockets contains the DatagramSocket class which is what I need to use for UDP networking.
However, my current attempts seem to execute just fine but have no results via Wireshark and do not get a response back from the devices on the network.
Here is the code I am currently using (and running through the RT Simulator):
public async static Task<IEnumerable<HueBridge>> DiscoverAsync(TimeSpan timeout)
{
if (timeout <= TimeSpan.Zero)
throw new ArgumentException("Timeout value must be greater than zero.", "timeout");
var discoveredBridges = new List<HueBridge>();
using (var socket = new DatagramSocket())
{
while (true)
{
var bridgeWasFound = false;
socket.MessageReceived += (sender, e) =>
{
var bpx = true; // breakpoint here for success
};
var multicastIP = new HostName("239.255.255.250");
await socket.BindServiceNameAsync("1900");
socket.JoinMulticastGroup(multicastIP);
using (var writer = new DataWriter(socket.OutputStream))
{
var request = new StringBuilder();
request.AppendLine("M-SEARCH * HTTP/1.1");
request.AppendLine("HOST: 239.255.255.250:1900");
request.AppendLine("MAN: ssdp:discover");
request.AppendLine("MX: 5");
request.AppendLine("ST: ssdp:all");
writer.WriteString(request.ToString());
await writer.FlushAsync();
}
if (timeout > TimeSpan.Zero)
await Task.Delay(timeout);
if (!bridgeWasFound)
break; // breakpoint here for failure check
}
}
return discoveredBridges;
}
Any ideas on what I may be doing incorrectly? I don't get an exception and I have the proper Capabilities set in the manifest. My breakpoint at the break always gets hit and I am using a timeout of 10 seconds.
Seems I have found the problem(s).
First, I should use socket.BindEndpointAsync(null, string.Empty) instead of socket.BindServiceNameAsync("1900"), which will properly listen for broadcast packets.
Secondly, writer.FlushAsync() does not write to the socket; however, writer.StoreAsync() does.
Here is the final result, which does work (almost) perfectly:
public async static Task<IEnumerable<HueBridge>> DiscoverAsync(TimeSpan timeout)
{
if (timeout <= TimeSpan.Zero)
throw new ArgumentException("Timeout value must be greater than zero.", "timeout");
var discoveredBridges = new List<HueBridge>();
var multicastIP = new HostName("239.255.255.250");
var bridgeWasFound = false;
using (var socket = new DatagramSocket())
{
socket.MessageReceived += (sender, e) =>
{
var reader = e.GetDataReader();
var bytesRemaining = reader.UnconsumedBufferLength;
var receivedString = reader.ReadString(bytesRemaining);
// TODO: Check for existing bridges, only add new ones to prevent infinite loop.
// TODO: Create new bridge and add to the list.
bridgeWasFound = true;
};
await socket.BindEndpointAsync(null, string.Empty);
socket.JoinMulticastGroup(multicastIP);
while (true)
{
bridgeWasFound = false;
using (var stream = await socket.GetOutputStreamAsync(multicastIP, "1900"))
using (var writer = new DataWriter(stream))
{
var request = new StringBuilder();
request.AppendLine("M-SEARCH * HTTP/1.1");
request.AppendLine("HOST: 239.255.255.250:1900");
request.AppendLine("MAN: ssdp:discover");
request.AppendLine("MX: 3");
request.AppendLine("ST: ssdp:all");
writer.WriteString(request.ToString());
await writer.StoreAsync();
if (timeout > TimeSpan.Zero)
await Task.Delay(timeout);
if (!bridgeWasFound)
break;
}
}
}
return discoveredBridges;
}
According Specifications :
MAN REQUIRED by HTTP Extension Framework. Unlike the NTS and ST field
values, the field value of the MAN header field is enclosed in double
quotes; it defines the scope (namespace) of the extension. MUST be
"ssdp:discover".
then your code
request.AppendLine("MAN: ssdp:discover");
must be
request.AppendLine("MAN: \"ssdp:discover\"");
Hope this help.

return after Dispatcher.invoke method

I have a Dispatcher that I must use to update my bitmap, however the return line is executed before the code inside dispatcher finishes, so the result isn't as expected.
How can I return a value after the dispatcher has completed? I can't leave the return inside dispatcher.
Below is my code:
public ObservableCollection<FavoriteStruct> LoadMobion()
{
List<FavoriteMobion> results;
using (FavoriteDataContext context = new FavoriteDataContext(connectionString))
{
IQueryable<FavoriteMobion> query = from c in context.TbFavoriteMobion
select c;
results = query.ToList();
}
ObservableCollection<FavoriteStruct> lstFavStr = new ObservableCollection<FavoriteStruct>();
if (results != null)
{
Thread load = new Thread(new ThreadStart(() =>
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
foreach (var rst in results)
{
BitmapImage bi;
bi = new BitmapImage();
bi.UriSource = new Uri("../Images/default_avatar_small.jpg", UriKind.Relative);
lstFavStr.Add(new FavoriteStruct()
{
Opacity = 0.8f,
Status = "../Images/offline.png",
RealID = rst.RealID,
GroupType = rst.GroupType,
MsgStatus = rst.MsgStatus == "" ? "offline" : rst.Path,
Name = rst.Name,
Path = rst.Path == "" ? "" : rst.Path,
Phone = rst.Phone,
Picture = bi
});
}
});
}));
load.Start();
load.Join();
}
return lstFavStr;
}
You are calling a new thread and BeginInvoke is also done asynchronously, you can't prevent return statement from executing when you want if you use threads. You should consider reformatting your code structure. I suggest you separate your UI update code, with the code you populate the collection. Take out populating the collection out of the thread.
Is your method supposed to load and display the data, or only return it? I would stop after getting the result, return that, and use another method or code block to update the UI with that data. Simply separate the two tasks.

Best way to run multiple workflows concurrently in WF 4.0

I have a routine that creates n instances of a particular workflow and runs them each serially. How could I fire them off async?
Current p-code:
forloop
// Create
var syncEvent = new AutoResetEvent(false);
WorkflowInstance myInstance = new WorkflowInstance(new SomeWorkflow(), parameters);
// Events
// Completed
myInstance.OnCompleted = delegate(WorkflowCompletedEventArgs e) { syncEvent.Set(); };
// Unhandled Exception
myInstance.OnUnhandledException = delegate(WorkflowUnhandledExceptionEventArgs e)
{
// Message
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
};
// Aborted
myInstance.OnAborted = delegate(WorkflowAbortedEventArgs e)
{
// Message
Console.WriteLine(e.Reason);
syncEvent.Set();
};
// Run
myInstance.Run();
// Wait
syncEvent.WaitOne();
I think the easiest way to get from here to there would be just to create multiple wait handles and end with a WaitAll(). Not the most elegant solution, but it will work for you. BTW, I would recommend using a real class that holds reference to the associated wait handle and avoiding the anon methods.
List<ManualResetEvent> items = new List<ManualResetEvent>();
foreach (Type job in queue)
{
WorkflowInstance myInstance = new WorkflowInstance(job, parameters);
ManualResetEvent syncEvent = new ManualResetEvent(false);
items.Add(syncEvent);
// Completed
myInstance.OnCompleted = delegate(WorkflowCompletedEventArgs e)
{
syncEvent.Set();
};
// Unhandled Exception
myInstance.OnUnhandledException = delegate(WorkflowUnhandledExceptionEventArgs e)
{
// Message
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
};
// Aborted
myInstance.OnAborted = delegate(WorkflowAbortedEventArgs e)
{
// Message
Console.WriteLine(e.Reason);
syncEvent.Set();
};
// Run
myInstance.Run();
}
// Wait
WaitHandle.WaitAll(items.ToArray());
Use parallel framework, it will be easier.
Do you really need them running on separate threads? I'm thinking since you are using Workflow already it should be easiest to solve the problem by using workflow to 'organize your work'.
{
var ArgsToProcess = new List<string> { "arg_one", "arg_two", "arg_three" };
var delegateArg = new DelegateInArgument<string> { Name = "s" };
Activity toRun = new ParallelForEach<string>
{
Body = new ActivityAction<string>
{
Argument = delegateArg,
Handler = new Workflow1() //Plug your workflow here
{
Arg = delegateArg
}
}
};
WorkflowInvoker.Invoke(toRun, new Dictionary<string, object>
{
{"Values", ArgsToProcess}
});
}

Categories

Resources