May 2007 - Posts
This is great news. The first beta came out in August so this has been a long time coming. Check it out here.
Update: Funnily enough, none of the links that seems to be available actually point to the Beta 2. Click on them and you get the old Beta 1 version. I did track down a valid Beta 2 link in their dev site (http://dev.live.com/writer/). You can download the Beta 2 from here until they fix the links everywhere else.
I encountered a bit of a curly one today with my workflows.
Generally, I am executing Windows Workflow Foundation workflows synchronously because I am using them as my business layer implementation for distributed services. This means that in order to return a value from a service call, the workflow needs to complete first. Because Windows Workflow Foundation executes asynchronously by default, I am using the ManualWorkflowSchedulerService to execute workflows on the same thread as the calling process.
This became a problem when I actually want a combination of synchronous and asynchronous workflow executions for a service call. With the DefaultWorkflowSchedulerService and ManualWorkflowSchedulerService in Windows Workflow Foundation, this wouldn't be supported in the one workflow runtime instance.
My first solution was to host two runtimes, one using the ManualWorkflowSchedulerService for executing workflows synchronously, and one using the DefaultWorkflowSchedulerService for executing the asynchronous workflows. The hitch is that I also need impersonation, but this doesn't appear to be possible when executing workflows using the DefaultWorkflowSchedulerService as the impersonated credentials get lost.
Second solution was to use just the one runtime that uses the ManualWorkflowSchedulerService, but execute the asynchronous workflow by calling the runtime from a new background thread. The problem here is that it doesn't appear to be possible to set up impersonation on the new thread.
Third solution was to use a delegate by calling BeginInvoke. This worked, but then I realised that I can use a thread and manually call for impersonation from inside its execution. To do this, I need to pass the WindowsIdentity along with my other parameter to a thread wrapper. My solution now looks like this:
using System;
using System.Collections.Generic;
using System.Security.Principal;
using System.Threading;
using Neovolve.Framework.Workflow;
using Neovolve.Jabiru.Sessions;
using Neovolve.Jabiru.Transfer.Service.BusinessWorkflows;
namespace Neovolve.Jabiru.Transfer.Service
{
/// <summary>
/// The <see cref="Neovolve.Jabiru.Transfer.Service.ServerItemSearcher"/>
/// class is used to search for items on the server.
/// </summary>
internal class ServerItemSearcher
{
#region Declarations
/// <summary>
/// Stores the session reference.
/// </summary>
private TransferSession _session;
/// <summary>
/// Stores the executing identity.
/// </summary>
private WindowsIdentity _identity;
/// <summary>
/// Stores the search thread.
/// </summary>
private Thread _searchThread;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the
/// <see cref="Neovolve.Jabiru.Transfer.Service.ServerItemSearcher"/> class.
/// </summary>
/// <param name="session">The session.</param>
/// <param name="identity">The identity.</param>
public ServerItemSearcher(TransferSession session, WindowsIdentity identity)
{
_session = session;
_identity = identity;
}
#endregion
#region Methods
/// <summary>
/// Runs the search.
/// </summary>
public void RunSearch()
{
// Create and start the thread
_searchThread = new Thread(new ThreadStart(RunSearchInternal));
_searchThread.IsBackground = true;
_searchThread.Start();
}
/// <summary>
/// Runs the search internal.
/// </summary>
private void RunSearchInternal()
{
using (WindowsImpersonationContext context = _identity.Impersonate())
{
Dictionary<String, Object> searchParameters = new Dictionary<String, Object>();
searchParameters.Add("Session", _session);
// Invoke the server item search workflow asynchronously
SynchronousWorkflowRuntime.Current.ExecuteWorkflow(typeof(SearchNewServerItemsWorkflow), searchParameters);
}
}
#endregion
}
}
For some bizarre reason (meaning I really don't know why), I have always built cache key values as strings when the key being represented is a set of values. On Friday, my eyes were opened to the fact that it is much better to create a rich object that represents the key values. The question then come down to equality testing of the reference type to make sure that the cache keys are correctly identified. Understanding Equality in C# on CodeProject is a concise article that was helpful for getting this right.
I have written some custom activities for Windows Workflow Foundation, but have recently found a bit of a problem with my implementation. I have wanted to persist information against the workflow instance that contains my custom activity (or many instances of the custom activity). I thought I was being very clever by resolving the owning workflow and then storing my information against the workflows UserData IDictionary property.
Even the description of the UserData property sounded appropriate according to my good intentions.
Gets an IDictionary that associates custom data with this class instance.
The problem that came up was that the data put into this property was persisted between multiple calls to execute the workflow type in the workflow runtime across any user that called it. I have had to change my implementation to store the data elsewhere to avoid this issue.
This one came around via email. I think "Oops" would be an appropriate word.

Ever come across a WorkflowValidationFailedException at runtime even though the project containing the workflow was successfully validated and compiled without any errors? The reason for this occurring is how the compiler manages references.
Lets look at a simple solution that contains ProjectA, ProjectB and ProjectC. ProjectA references ProjectB which then references ProjectC.
ProjectA contains a form that references ClassB in ProjectB like this:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using ProjectB;
namespace ProjectA
{
public partial class FormA : Form
{
public FormA()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ClassB TestB = new ClassB();
Debug.WriteLine(TestB.CreateValue());
}
}
}
ProjectB contains ClassB that references ClassC in ProjectC like this:
using System;
using ProjectC;
namespace ProjectB
{
public class ClassB
{
public String CreateValue()
{
ClassC TestC = new ClassC();
return TestC.RunTest();
}
}
}
ClassC in ProjectC looks like this:
using System;
namespace ProjectC
{
public class ClassC
{
public String RunTest()
{
return Guid.NewGuid() + " - " + DateTime.Now;
}
}
}
When ProjectA compiles, the build output in bin\Debug is the following:
ProjectA.exe
ProjectB.dll
ProjectC.dll
Everything is good here and ProjectA will execute successfully.
Now lets simulate a scenario that Windows Workflow Foundation can bring into the mix. Lets say that ProjectB contains a workflow. This workflow ends up executing a rule set, probably through a PolicyActivity. A rule in the rule set makes a reference to ClassC in ProjectC. Nowhere else in ProjectB references any type defined in ProjectC. What happens? The result can be simulated by making ClassB in ProjectB look like this:
using System;
using ProjectC;
namespace ProjectB
{
public class ClassB
{
public String CreateValue()
{
//ClassC TestC = new ClassC();
//return TestC.RunTest();
return "Break me";
}
}
}
When ProjectA compiles, the build output in bin\Debug is the following:
ProjectA.exe
ProjectB.dll
Traditionally, this is really great. The compiler is smart enough to know that even though ProjectB references ProjectC, it doesn't actually reference any types defined in ProjectC, so why pull across its build output. That would just be unnecessary bloat.
How does this relate to Windows Workflow Foundation? Well, rules are defined in XML and CodeDOM is used to interpret that XML into code that will be executed. This means that at compile time, the type references don't exist as far as the compiler is concerned. The more Windows Workflow Foundation is used, the more likely it will become that types and their projects are only referenced through rules therefore their build output will not be available at runtime. This results in the WorkflowValidationFailedException at runtime.
The solutions to this problem with VS2005 are to either make a reference of ProjectC in ProjectA (first level references are always pulled along), or to make a reference to a ProjectC type in code in somewhere in ProjectB. Hopefully Orcas will address this issue (I haven't checked yet).
Paul Stovell has posted some great points about the usage of code generation. This is of great interest to me because I am using code generation to produce a base service implementation as I develop an SOA application. I have a couple of thoughts to add to his list:
7. Code generation is not a license to avoid unit testing.
There is a tendency to not test generated code because the original unit testing of the templates was successful. Once you have generated code, it should now be considered alive in that it will be run in an environment, interact with other systems and will be required to work with data that didn't exist in the code generation templates or their original test scenarios. Anything could cause problems because specific circumstances weren't considered as the template was developed.
8. Code generation does not produce a product.
This point aligns with Paul's 5th and 6th points. Code generation being a tool, shouldn't produce a product. Use code generation to output common base level code that can then be customized and built upon. Code generation output can be the basis of a product, but shouldn't be the entire product. If you have done this, then either you have wasted too much time on your templates, or your product design needs some serious CPR.
On a side note, the code generator I decided to use SmartCode because it is the easiest to use and understand in the freeware market. It is also open source so I can deal with any issues or restrictions that I come across. I have since also started to contribute my changes to the project.
I want to change some values in my application config file at build time depending on the build type (Debug or Release for example). Web deployment projects added this functionality, but it is tightly coupled to that project type. I want to use this functionality in any .Net project type.
Is there a way to do this?
If you have some experience with refactoring or profiling tools (preferably with experience of multiple tools), I would be really interested to know what you think.
For refactoring tools, the pick seem to be either JetBRAINS ReSharper or DevExpress RefactorPro. ReSharper is $250 and seems to have similar functions to RefactorPro which weighs in at $99 with free updates for a year, or $250 if bundled with CodeRush. There is also JustCode and C# Refactory but these both seem to be less mature compared to ReSharper and RefactorPro.
As far as profiling tools go, I don't have much of an indication. There is the CLR Profiler, .Net Memory Profiler, ANTS Profiler and JetBRAINS dotTrace.
Are there any other contenders worthy of the calling that I have missed?
This is fantastic news. I've been eagerly awaiting a new GhostDoc version for a while. It has been a long time coming but after reading the change list it looks like it is well worth the wait. The change I've been wanting is the ability to document more items like classes and interfaces. Downloading now....