Как создавать файлы Visual Studio Solution (.sln) программным способом, включая проекты веб-сайтов? - PullRequest
9 голосов
/ 05 января 2012

Я работаю над проектом генератора кода, который создает решение с настраиваемыми слоями. сейчас я могу создать файл .sln, написав все элементы в коде. но файлы проекта не нуждаются в этом, их можно редактировать с помощью класса MSBuild Project.

Я хочу добавить поддержку шаблонов проектов веб-сайта и т. Д., Поэтому этот способ редактирования файла .sln не клевый, я хотел знать, есть ли лучший способ сделать это, например, MSBuild или что-то еще?

Я видел Программно сгенерированный Visual Studio Solution , который говорит об использовании Visual Studio SDK (который предназначен для расширения Visual Studio, написания плагинов ...), но там нет примера кода.

заранее спасибо

Ответы [ 3 ]

6 голосов
/ 14 сентября 2012

Вот как использовать SLNTools для создания файла sln в коде.Код это беспорядок!Но это работает!

Проект SLN Tools может создать файл sln из файлов проекта.Это открытый исходный код и предоставляет пользовательский интерфейс для редактирования и объединения файлов sln.В этом случае вы можете использовать основной проект и, ссылаясь на «CWDev.SLNTools.Core.dll» в своем проекте, вы можете написать грязный (!) Код, подобный этому:

NOTE : Некоторые части класса здесь не показаны, а также есть некоторые пользовательские объекты моего собственного проекта, такие как Sln, Project и ..., которые не следует путать с объектами SLNTools с тем же именем.Я прокомментировал все, что нужно!

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;
    }
}

Надеюсь, это поможет.

1 голос
/ 06 января 2012

Вы можете использовать интерфейс IVsSolution для создания решений и добавления к ним проектов.Вы передаете тип SVsSolution методу GetService () , чтобы получить экземпляр этого интерфейса следующим образом:

var solution = (IVsSolution)GetService(typeof(SVsSolution));
0 голосов
/ 06 января 2012

В моих файлах решений проекты веб-сайтов хранятся в разделе проекта WebsiteProperties.Эти свойства передаются в aspnet_compiler в качестве входных параметров в зависимости от конфигурации сборки.Попробуйте выполнить поиск идентификатора проекта (GUID) (в данном случае C9683FA5-AABA-497F-B780-80EFC3EB81F2) в ваших файлах sln, содержащих проект веб-сайта, какие части файла sln должны быть обновлены / сгенерированы генератором кода.

Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "MasterData.Host", "..\..\Customs.Framework\Services\MasterDataService\Tests\MasterData.Host", "{C9683FA5-AABA-497F-B780-80EFC3EB81F2}"
    ProjectSection(WebsiteProperties) = preProject
        SccProjectName = "SAK"
        SccAuxPath = "SAK"
        SccLocalPath = "SAK"
        SccProvider = "SAK"
        TargetFrameworkMoniker = ".NETFramework,Version%3Dv3.5"
        ProjectReferences = "{C7C785E8-89E6-459A-969C-BFC2BC7E8ED2}|Porthus.Customs.Framework.Services.MasterData.ServiceImplementation.dll;{ADFA3898-854C-4058-8726-523EA8802FFD}|Porthus.Customs.Framework.Services.MasterData.FaultContracts.dll;{9A565742-4843-40A6-A2E3-2B432573D12B}|Porthus.Customs.Framework.Services.MasterData.MessageContracts.dll;{E8B5D2A1-E934-4C85-AB71-A2148050913A}|Porthus.Customs.Framework.Services.MasterData.ServiceContracts.dll;{3C752087-CED2-499F-AF3B-84E1548229CB}|Porthus.Customs.Services.MasterData.BusinessEntities.dll;{437C651C-3C8D-4B3D-B967-E58DBCD83EE4}|Porthus.Customs.Services.MasterData.BusinessLogic.dll;{59BBDE80-6F20-4FB6-A65B-68BC584AD2CB}|Porthus.Customs.Services.MasterData.DataAccess.dll;"
        Debug.AspNetCompiler.VirtualPath = "/MasterData.Host"
        Debug.AspNetCompiler.PhysicalPath = "..\..\Customs.Framework\Services\MasterDataService\Tests\MasterData.Host\"
        Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\MasterData.Host\"
        Debug.AspNetCompiler.Updateable = "true"
        Debug.AspNetCompiler.ForceOverwrite = "true"
        Debug.AspNetCompiler.FixedNames = "false"
        Debug.AspNetCompiler.Debug = "True"
        Release.AspNetCompiler.VirtualPath = "/MasterData.Host"
        Release.AspNetCompiler.PhysicalPath = "..\..\Customs.Framework\Services\MasterDataService\Tests\MasterData.Host\"
        Release.AspNetCompiler.TargetPath = "PrecompiledWeb\MasterData.Host\"
        Release.AspNetCompiler.Updateable = "true"
        Release.AspNetCompiler.ForceOverwrite = "true"
        Release.AspNetCompiler.FixedNames = "false"
        Release.AspNetCompiler.Debug = "False"
        VWDPort = "1333"
        DefaultWebSiteLanguage = "Visual C#"
    EndProjectSection
EndProject

Необходимо обновить (как минимум) глобальные разделы ProjectConfigurationPlatforms & NestedProjects.Это было необходимо в моем случае.

Я реализовал задачу объединения MsBuild.Он поддерживает объединение нескольких файлов решений в один файл MergedSolution.sln.Он работает с нашими 20+ файлами решений, содержащими более 500 проектов (c # & website & sql db project files / section).Размер выходного файла решения составляет 1,3 МБ :)

РЕДАКТИРОВАТЬ: Проект SLN Tools может создавать файл SLN из файлов проекта.

Как создать файл SLN с помощью специального MSBuildtask:

  • Здесь - хорошая информация о решении и формате файлов проекта.
  • Если у вас есть набор файлов проекта, вы можете сгенерировать файл решения с помощью пользовательской задачи MSBuild (внутри метода Execute)
  • Для чтения файлов проекта MSBuild используйте Microsoft.Build.BuildEngine.Project class (он устарел, но я все еще использую его) или Microsoft.Build.Evaluation.Project class
...