Re: When is WF worth using
If you have an application that is very complicated in terms of process and business logic, then WF becomes useful for you. The points attributed to it are
a) You represent the complicated logic in a diagram
b) The clients get to see and verify and ask you to change the logic
c) Add, remove, disable portions of the logic when you need to
d) The forced reusability allows you to create more complicated logic easily
As you can see from those points, it's meant for an enterprise environment.
The above applies to sequential workflows. State machine workflows are another area - that does all of the above and also allows you to perform processes which can span any amount of time (days, weeks, years) because the workflow's processing depends on the state of the information it contains. For example, if you have a troubleshooting ticket system, the user can go through the forms initially and get help. Later, as part of the workflow process, you can send out an email asking them to fill in a feedback form. The user could click on the feedback form link days later but your workflow will still know where in the entire business process the user is and act accordingly.
There's also the benefit of storing the state, so when the application is recycled (again for example) you can store the current state in a database and wait for the app to come back before proceeding so that you don't lose information.
Again, very enterprise environment friendly. I host WFs in WCF services when they're very complicated. No performance hit.
Re: When is WF worth using
Well from the first part of your explanation it does sound very much like it is too high level and too 'enterprisy' to be of use to someone like me... but this bit:
Quote:
Originally Posted by mendhak
For example, if you have a troubleshooting ticket system, the user can go through the forms initially and get help. Later, as part of the workflow process, you can send out an email asking them to fill in a feedback form. The user could click on the feedback form link days later but your workflow will still know where in the entire business process the user is and act accordingly.
sounds exactly like the kind of thing I want to do - I dont know if you used that troubleshooting ticket system as an example because you knew I was making such a program or not, but if not then its a good coincidence :)
Whilst I'm not working in an enterprise, the helpdesk system I am making is going to be quite complicated and will have a lot of different parts to it (I'm not expecting to have it anywhere near finished for another few months and I work on it every day) so it sounds like WF might be able to help me out there?
Re: When is WF worth using
To be honest reading up about it WF seems to be enterprise only as opposed to enterprise friendly.
Re: When is WF worth using
but surely it would help simplify any program? Being able to see it in a workflow diagram rather than just seeing loads of code that can sometimes be hard to follow. That book I ordered should arrive in a couple of days so I'll have a good read of that and see if I think it could be of any use to me, but from reading a sample chapter (the introduction) I saw a part that said something like "no matter what you are doing, WF can provide the following advantages.." , it then went on to list a load of things which I have since forgotten :)
Re: When is WF worth using
Don't belive the introduction. go read beginning C#/VB from apress and tell me you7 can follow it after the nice well written introduction.
Its all lies....
Re: When is WF worth using
haha well we will see! :)
Re: When is WF worth using
Quote:
Originally Posted by chris128
Well from the first part of your explanation it does sound very much like it is too high level and too 'enterprisy' to be of use to someone like me... but this bit:
sounds exactly like the kind of thing I want to do - I dont know if you used that troubleshooting ticket system as an example because you knew I was making such a program or not, but if not then its a good coincidence :)
Whilst I'm not working in an enterprise, the helpdesk system I am making is going to be quite complicated and will have a lot of different parts to it (I'm not expecting to have it anywhere near finished for another few months and I work on it every day) so it sounds like WF might be able to help me out there?
I just based that on a system we have here (which I'm not working on but I've looked at and studied), so it's a good coincidence.
Don't believe the book right off the bat, make your own decision. Everyone who is a tech evangelist will push their technology as the solution for everything. What you should do is try it out by building a very simple system that covers the most fundamental concepts in your upcoming system. If it works out, then by that time you will also have determined whether this will simplify your task for you. You will also have learned a bit of WF.
Re: When is WF worth using
Yeah I will do that before I commit to using it in my application dont worry, but at the moment I dont know enough about WF to do that, hence the ordering of that book so that I can get a good understanding of it and then make an informed decision :)
Re: When is WF worth using
Also, to point out... if you bought the Apress book, there's a very nice management class in there. Look around page 141 for a workflowruntimemanager class. You can copy it (type it?) straight in and use it in your apps.
Re: When is WF worth using
Ah, here it is
Code:
public class WorkflowRuntimeManager : IDisposable
{
public WorkflowRuntimeManager(WorkflowRuntime workflowRuntime)
{
if (workflowRuntime == null)
{
throw new ArgumentNullException("workflowRuntime", "WorkflowRuntime cannot be null");
}
WorkflowRuntime = workflowRuntime;
Workflows = new Dictionary<Guid, WorkflowInstanceWrapper>();
SubscribeToEvents(workflowRuntime);
}
public WorkflowRuntime WorkflowRuntime { get; private set; }
public Dictionary<Guid, WorkflowInstanceWrapper> Workflows { get; private set; }
#region IDisposable Members
public void Dispose()
{
if (WorkflowRuntime != null)
{
WorkflowRuntime.StopRuntime();
WorkflowRuntime.Dispose();
}
ClearAllWorkflows();
}
#endregion
public event EventHandler<WorkflowLogEventArgs> MessageEvent;
public WorkflowInstanceWrapper StartWorkflow(Type workflowType, Dictionary<string, object> parameters)
{
WorkflowInstance instance = WorkflowRuntime.CreateWorkflow(workflowType, parameters);
WorkflowInstanceWrapper wrapper = AddWorkflowInstance(instance);
instance.Start();
return wrapper;
}
public void ClearWorkflow(Guid workflowId)
{
if (Workflows.ContainsKey(workflowId))
{
Workflows.Remove(workflowId);
}
}
public void ClearAllWorkflows()
{
Workflows.Clear();
}
private WorkflowInstanceWrapper AddWorkflowInstance(WorkflowInstance workflowInstance)
{
if (!Workflows.ContainsKey(workflowInstance.InstanceId))
{
var wrapper = new WorkflowInstanceWrapper(workflowInstance);
Workflows.Add(workflowInstance.InstanceId, wrapper);
return wrapper;
}
return null;
}
public WorkflowInstanceWrapper FindWorkflowInstance(Guid workflowId)
{
if (Workflows.ContainsKey(workflowId))
{
return Workflows[workflowId];
}
return null;
}
public bool WaitAll(int timeout)
{
if (Workflows.Count > 0)
{
var handles = new List<WaitHandle>();
foreach (WorkflowInstanceWrapper wrapper in Workflows.Values)
{
handles.Add(wrapper.WaitHandle);
}
return WaitHandle.WaitAll(handles.ToArray(), timeout, false);
}
return true;
}
private void SubscribeToEvents(WorkflowRuntime runtime)
{
runtime.Started
+= Runtime_Started;
runtime.Stopped
+= Runtime_Stopped;
runtime.WorkflowAborted
+= Runtime_WorkflowAborted;
runtime.WorkflowCompleted
+= Runtime_WorkflowCompleted;
runtime.WorkflowCreated
+= Runtime_WorkflowCreated;
runtime.WorkflowIdled
+= Runtime_WorkflowIdled;
runtime.WorkflowLoaded
+= Runtime_WorkflowLoaded;
runtime.WorkflowPersisted
+= Runtime_WorkflowPersisted;
runtime.WorkflowResumed
+= Runtime_WorkflowResumed;
runtime.WorkflowStarted
+= Runtime_WorkflowStarted;
runtime.WorkflowSuspended
+= Runtime_WorkflowSuspended;
runtime.WorkflowTerminated
+= Runtime_WorkflowTerminated;
runtime.WorkflowUnloaded
+= Runtime_WorkflowUnloaded;
}
private void Runtime_Started(object sender, WorkflowRuntimeEventArgs e)
{
LogStatus(Guid.Empty, "Started");
}
private void Runtime_Stopped(object sender, WorkflowRuntimeEventArgs e)
{
LogStatus(Guid.Empty, "Stopped");
}
private void Runtime_WorkflowCreated(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowCreated");
}
private void Runtime_WorkflowStarted(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowStarted");
}
private void Runtime_WorkflowIdled(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowIdled");
}
private void Runtime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowCompleted");
WorkflowInstanceWrapper wrapper
= FindWorkflowInstance(e.WorkflowInstance.InstanceId);
if (wrapper != null)
{
wrapper.OutputParameters = e.OutputParameters;
wrapper.StopWaiting();
}
}
private void Runtime_WorkflowTerminated(object sender,
WorkflowTerminatedEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowTerminated");
WorkflowInstanceWrapper wrapper
= FindWorkflowInstance(e.WorkflowInstance.InstanceId);
if (wrapper != null)
{
wrapper.Exception = e.Exception;
wrapper.StopWaiting();
}
}
private void Runtime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowSuspended");
WorkflowInstanceWrapper wrapper
= FindWorkflowInstance(e.WorkflowInstance.InstanceId);
if (wrapper != null)
{
wrapper.ReasonSuspended = e.Error;
}
}
private void Runtime_WorkflowResumed(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowResumed");
}
private void Runtime_WorkflowPersisted(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowPersisted");
}
private void Runtime_WorkflowLoaded(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowLoaded");
}
private void Runtime_WorkflowAborted(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowAborted");
WorkflowInstanceWrapper wrapper
= FindWorkflowInstance(e.WorkflowInstance.InstanceId);
if (wrapper != null)
{
wrapper.StopWaiting();
}
}
private void Runtime_WorkflowUnloaded(object sender, WorkflowEventArgs e)
{
LogStatus(e.WorkflowInstance.InstanceId, "WorkflowUnloaded");
}
private void LogStatus(Guid instanceId, string message)
{
if (MessageEvent != null)
{
string formattedMessage;
if (instanceId == Guid.Empty)
{
formattedMessage = String.Format(CultureInfo.CurrentCulture, "Runtime - {0}", message);
}
else
{
formattedMessage = String.Format(CultureInfo.CurrentCulture, "{0} - {1}", instanceId, message);
}
//raise the event
MessageEvent(this, new WorkflowLogEventArgs(formattedMessage));
}
}
}
Re: When is WF worth using
I'm only about 1/10 of the way through the book at the moment (concentrating on the WCF book at the mo) so dont really have a clue what that class is for but I'm sure it will come in handy so thank you :D