views:

79

answers:

2

I'm using CodeSmith on my current project and I'm trying to figure out an issue. For my CodeSmith project (.csp) I can select an option to have it automatically add all generated files to the current project (.csproj). But I want to be able to add the output to multiple projects (.csproj). Is there an option inside of CodeSmith to allow this? Or is there a good way to programmatically do that?

Thanks.

A: 

Have you thought about just compiling into a shared assembly (DLL) that can then be referenced by all your projects?

I know this may not suit your requirements but I would assume this would be one of the best ways of achieving a single source that all your projects can use and also only one code base to maintain as needed.

Wayne
Unfortunately this doesn't work for my case, but not a bad potential solution.
Dugan
A: 

I was unable to figure out a way to make CodeSmith handle this issue automatically, so I ended up writing a custom method in the Code Behind file to handle this.

A few notes: - The proj files are XML, and as thus fairly easy to edit, but the actual "ItemGroup" node that holds the list of files that are included in the project isn't actually labeled in any special way. I ended up picking the "ItemGroup" node that has "Contains" child nodes, but there might be a better way to determine which you should use. - I recommend doing all the proj file changes at once, instead of as each file is created/updated. Otherwise if you launch the generation from Visual Studio, you might get a flood of "This item has changed, would you like to reload" - If your files are under source control (they are, right?!), you're going to need to handle checking files out and adding them to source control along with editing the proj files.

Here is (more or less) the code I used to add a file to the project:

/// <summary>
/// Adds the given file to the indicated project
/// </summary>
/// <param name="project">The path of the proj file</param>
/// <param name="projectSubDir">The subdirectory of the project that the 
/// file is located in, otherwise an empty string if it is at the project root</param>
/// <param name="file">The name of the file to be added to the project</param>
/// <param name="parent">The name of the parent to group the file to, an 
/// empty string if there is no parent file</param>
public static void AddFileToProject(string project, string projectSubDir, 
        string file, string parent)
{
    XDocument proj = XDocument.Load(project);

    XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
    var itemGroup = proj.Descendants(ns + "ItemGroup").FirstOrDefault(x => x.Descendants(ns + "Compile").Count() > 0);

    if (itemGroup == null)
        throw new Exception(string.Format("Unable to find an ItemGroup to add the file {1} to the {0} project", project, file));

    //If the file is already listed, don't bother adding it again
    if(itemGroup.Descendants(ns + "Compile").Where(x=>x.Attribute("Include").Value.ToString() == file).Count() > 0)
        return; 

    XElement item = new XElement(ns + "Compile", 
                    new XAttribute("Include", Path.Combine(projectSubDir,file)));

    //This is used to group files together, in this case the file that is 
    //regenerated is grouped as a dependent of the user-editable file that
    //is not changed by the code generator
    if (string.IsNullOrEmpty(parent) == false)
        item.Add(new XElement(ns + "DependentUpon", parent));

    itemGroup.Add(item);

    proj.Save(project); 

}
Dugan
Hello,We have been thinking about possibly adding functionality like this into CodeSmith. How are you executing this code in your template?Thanks-Blake Niemyjski
Blake Niemyjski
In my template I call into my helper class, it looks like this: if(created == false){Helper.AddFileToProject(ModelProject, string.Empty, fileName, parentName); }
Dugan