Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Visual Studio Solution (.sln) files programmatically, including Website projects?

I am working on a code generator project that creates solution with customizable layers. for now I am able to create the .sln file by writing all the elements in code. but the project files don't need this, they can be edited using MSBuild Project class.

I want to add a Website project template support and etc, so this way I edit the .sln file is not cool, I wanted to know that is there a better way to do this, like MSBuild or something else ?

I saw Programmatically generate Visual Studio Solution that says to use Visual Studio SDK (which is for extending visual studio, writing plugins ...), but there isn't any code sample.

thanks in advance

like image 816
Ashkan Avatar asked Jan 05 '12 12:01

Ashkan


People also ask

How do I create an .sln file in Visual Studio?

From the Visual Studio menu choose "File | New | Project..." Solutions" and create a blank solution. point it to your web site to add it to your new solution.

Can a Visual Studio solution contain multiple projects?

When you create a new project, Visual Studio creates a solution to contain the project. You can then add other new or existing projects to the solution if you want.


2 Answers

Here is how to use SLNTools to create sln file in code. The code is a mess! But it works!

SLN Tools project is able to create sln file from project files. It's open source and it provides UI for editing and merging sln files. In this case you can use the core project and by referencing the 'CWDev.SLNTools.Core.dll' in your project you can write a messy(!) code like this:

NOTE: Some parts of class are not shown here and also There's some custom objects of my own project like Sln, Project and ... that should not be mistaken with SLNTools Objects with same name. I commented whereever needed!

using CWDev.SLNTools.Core;
using SlnFile = CWDev.SLNTools.Core.SolutionFile;
using SlnProject = CWDev.SLNTools.Core.Project;
using SeptaCodeGenerator.Core.IO;

public class SlnFileManager
{
    // * Note: Sln is of my own type.
    Sln _sln;
    // * SolutionFile is the type in SLNTools project that we use
    SlnFile _slnFile;

    public void WriteNewSlnFile(Sln slnObject)
    {
        _sln = slnObject;
        _slnFile = new SlnFile(); // or you can read sln file like below
        using (SolutionFileReader reader = new SolutionFileReader(_sln.ObjectFullPath))
            _slnFile = reader.ReadSolutionFile();
        AddHeaders();
        AddGlobalSections();
        // add projects
        List<SolutionNode> sns = _sln.GetAllSubItemsOf(typeof(SolutionFolder), typeof(ProjectNode));
        foreach (SolutionNode sn in sns)
            _slnFile.Projects.Add(CreateProject(sn));

        using (SolutionFileWriter writer = new SolutionFileWriter(_sln.ObjectFullPath))
            writer.WriteSolutionFile(_slnFile);
    }

    // this is how I create and add project sections, using Section and PropertyLine
    private SlnProject CreateProject(SolutionNode sn)
    {
        List<Section> projectSections = CreateProjectSections(sn);
        List<PropertyLine> versionControlLines = CreateVersionControlLines(sn);
        List<PropertyLine> projectConfigurationPlatformsLines = CreateProjectConfigurationPlatformsLines(sn);

        string parentGuid = (sn.Parent is Sln ? null : sn.Parent.InstanceGuidSt);
        string relativePath = (sn is Project) ? (sn as Project).ProjFile.ObjectRelativePath : sn.ObjectRelativePath;
        return new CWDev.SLNTools.Core.Project(_slnFile, sn.InstanceGuidSt, sn.TypeGuidSt, sn.Name, relativePath, parentGuid,
            projectSections, versionControlLines, projectConfigurationPlatformsLines);
    }

    // this method creates ProjectSections(WebsiteProperties)
    private List<Section> CreateProjectSections(SolutionNode project)
    {
        Section sec = null;
        var lines = new List<PropertyLine>();
        if (project is SolutionFolder)
        {
            List<SolutionNode> files = project.GetAllSubItemsOf(typeof(SolutionFile));
            foreach (SolutionNode item in files)
            {
                // * consideration required
                lines.Add(new PropertyLine(item.ObjectRelativePath, item.ObjectRelativePath));
            }
            if (lines.Count > 0)
                sec = new Section("SolutionItems", "ProjectSection", "preProject", lines);
        }
        // *** here is the code that I wrote to add website projects ***
        else if (project is WebSiteProject)
        {
            var website = project as WebSiteProject;
            if (_sln.IsUnderSourceControl)
            {
                    lines.AddRange(new PropertyLine[]
                    {
                        new PropertyLine("SccProjectName", "\"SAK\""),
                        new PropertyLine("SccAuxPath", "\"SAK\""),
                        new PropertyLine("SccLocalPath", "\"SAK\""),
                        new PropertyLine("SccProvider", "\"SAK\"")
                    });

            }
            if (_sln.SolutionVersion == SolutionFileVersion.V11VS2010)
                lines.Add(new PropertyLine("TargetFrameworkMoniker", "\".NETFramework,Version%3Dv4.0\""));
            else
                lines.Add(new PropertyLine("TargetFramework", "\"3.5\""));
            // add project references
            string projectReferences = "";
            foreach (Project proj in website.ReferencedProjects)
                projectReferences += proj.InstanceGuidSt + "|" + proj.ClassName + ".dll;";
            lines.Add(new PropertyLine("ProjectReferences", "\"" + projectReferences + "\""));

            string debugConf = "Debug.AspNetCompiler.";
            string releaseConf = "Release.AspNetCompiler.";
            string str = debugConf;
            int k = 0;
            while (k < 2)
            {
                // other properties
                lines.AddRange(new PropertyLine[]
                {
                    new PropertyLine(str + "VirtualPath", "\"/" + website.Name + "\""),
                    new PropertyLine(str + "PhysicalPath", "\"" + website.ObjectRelativePath + "\\\""),
                    new PropertyLine(str + "TargetPath", ("\"PrecompiledWeb\\" + website.Name + "\\\"")),
                    new PropertyLine(str + "Updateable", "\"true\""),
                    new PropertyLine(str + "ForceOverwrite", "\"true\""),
                    new PropertyLine(str + "FixedNames", "\"false\""),
                    new PropertyLine(str + "Debug", (k == 0 ? "\"True\"" : "\"False\""))
                });

                if (k++ == 0)
                    str = releaseConf;
            }
            Random rand = new Random();
            lines.Add(new PropertyLine("VWDPort", "\"" + rand.Next(1111, 65000).ToString() + "\""));
            lines.Add(new PropertyLine("DefaultWebSiteLanguage",
                website.Language == SeptaCodeGenerator.Core.Language.CodeLanguage.CSharp ? "\"Visual C#\"" : "\"Visual Basic\""));

            sec = new Section("WebsiteProperties", "ProjectSection", "preProject", lines);
        }
        var sections = new List<Section>();
        if (sec != null)
            sections.Add(sec);
        return sections;
    }
}

Hope it helps.

like image 162
Ashkan Avatar answered Oct 25 '22 05:10

Ashkan


You can use the IVsSolution interface to create solutions and add projects to them. You pass in the SVsSolution type to the GetService() method to get an instance of that interface like so:

var solution = (IVsSolution)GetService(typeof(SVsSolution));
like image 40
Charles Lambert Avatar answered Oct 25 '22 04:10

Charles Lambert