Thursday, February 14, 2008

Just ran into a little bug in Visual Studio/msbuild and could not find any answers in the forums, so I thought I'd put it up here for reference:

When you want to use both workflow classes and wpf classes in one project, you will run into some strange behaviour. Let's do it together.
If you want to skip the newbie stuff, jump to step 11 and see the bug.

  1. create a WPF project.
  2. unload the project and choose to edit the project file
  3. somewhere in the beginning of the file, you will find the following line:
    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    That is a way for visual studio to identify this as a WPF application project, and when you add an item, you will be able to choose a wpf item.
  4. You wish to be able to compile WF items, so add to the bottom of the file the correct import for the WF tasks:
    <Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.5\Workflow.Targets" />
  5. Note that WPF in the past needed the import of winfx, but with framework 3.5 you don't need that anymore!
  6. At this point you are able to copy a workflow or activity to your project and compile, but you want to be able to add WF items to your project, so scroll to the top of the file again.
  7. Add the Guid that identifies a WF project ({14822709-B5A1-4724-98CA-57A101D1B079};)  to your projecttypeguids tag. The complete tag should be on one line (!) and look like this:

    <ProjectTypeGuids>{14822709-B5A1-4724-98CA-57A101D1B079};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
  8. Save the file and reload the project.
  9. Before adding a the first workflow to the project, first add references to System.Workflow.Runtime, Activities and Componentmodel.
  10. Add your first glorious workflow to the project.
  11. Be prepared to be disappointed: the project will not compile. Mine gave this error:

    Error    1    Error reading resource file 'j:\Users\Ruurd\Documents\Visual Studio 2008\Projects\WF_and_WPF_combined\WpfApplication1\obj\Debug\WpfApplication1.obj.Debug.WpfApplication1.g.resources' -- 'The system cannot find the file specified. '    J:\Users\Ruurd\Documents\Visual Studio 2008\Projects\WF_and_WPF_combined\WpfApplication1
  12. Notice the weird path of the resource file. It is looking for something with dots instead of path dividers. Strange.
    In regular windows explorer, go to the obj/Debug folder, and create a copy of the .g.resources file and use that weird name. I wanted to automate it though, so go to the properties of your project and use this as your pre-build script:
    IF EXIST "$(ProjectDir)obj\$(ConfigurationName)\$(TargetName).g.resources" (copy /-Y "$(ProjectDir)obj\$(ConfigurationName)\$(TargetName).g.resources" "$(ProjectDir)obj\$(ConfigurationName)\$(TargetName).obj.$(ConfigurationName).$(TargetName).g.resources") ELSE (echo "placeholder" > "$(ProjectDir)obj\$(ConfigurationName)\$(TargetName).obj.$(ConfigurationName).$(TargetName).g.resources")

    This checks to see if you already have a g.resources file and if so, copies it. Otherwise it will generate a placeholder file with the correct name. Atleast the project will build without problems.

I have not tested it a lot yet. It seems to me that when the placeholder is created, there are resources that can not be found. During some quick and dirty tests, I've not had any problem yet and everything works just fine.

Hope this helps someone out there.

update: weird stuff. I have this running just fine in a couple of projects, but I have one project that gives an exception during a rebuild (not a build) in the compileworkflowtask. In other 'combined' projects, I can happily build and rebuild using the steps above.

This is probably caused by wpf renaming the file to tmp_proj and the compileworkflow task is validating it's parameters like so:

        if ((string.Compare(this.ProjectExtension, ".csproj", StringComparison.OrdinalIgnoreCase) != 0) && (string.Compare(this.ProjectExtension, ".vbproj", StringComparison.OrdinalIgnoreCase) != 0))
        {
            base.Log.LogErrorFromResources("UnsupportedProjectType", new object[0]);
            return false;
        }

The logging statement is the one giving the pain.

 

Sunday, April 06, 2008 9:19:53 AM (Romance Standard Time, UTC+01:00)
Have you ever solved the problem with combining WPF & WF projects? I have the same trouble with " .g.resources ". Using pre-build script sometimes helps, sometimes not (not sure when and why though). Also, Resharper goes very mad when it encounters such combined projects (most of XAML lines became red - very annoying...). I believe that somehow XAML namespaces (http://schemas.microsoft.com/winfx/2006/xaml/presentation and http://schemas.microsoft.com/winfx/2006/xaml) have disappeared from ReSharper's sight completely. Worst of all, it makes Visual Studio offer me to include references to needed namespaces (System.Windows, System.Windows.Control and so on) - and XAML goes very ugly (Windows:Window instead of Window - that kind if ugliness).
Vladimir
Sunday, April 06, 2008 1:51:59 PM (Romance Standard Time, UTC+01:00)
it did work for me in some occasions, but in the end it's more trouble than it's worth. It always broke down after a certain amount of time.
I would suggest altering the msbuild script in csproj to react to a build configuration and change the project type accordingly. That way, you could easily switch between wpf and wf.
I refactored the projects so that I was able to use separate projects and never looked back!
Sorry
Ruurd
Tuesday, April 08, 2008 2:35:58 PM (Romance Standard Time, UTC+01:00)
Well, actually, in the end I did just the same - used two separate projects (with workflow in class library). All worked great, with one exception - breakpoints on workflow activities never hitted in debug...

Thanks nonetheless, I liked your idea of using state machine workflow as a controller in MVC. (I was thinking about something like that when encountered problems with wpf+wf project).
Vladimir
Tuesday, April 08, 2008 9:22:40 PM (Romance Standard Time, UTC+01:00)
thanks, actually, I've been quite succesful with using workflows as controllers. There is no need at all to combine them in the same project. I think it is a good way to manage complexity
Ruurd
Friday, April 11, 2008 10:25:18 AM (Romance Standard Time, UTC+01:00)
Can anyone tell me where to find some more information about the tmp_proj projects ?
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):