Visual Studio Solution dosyalarını ayrıştırma


109

.NET'te Visual Studio çözüm (SLN) dosyalarını nasıl ayrıştırabilirim? Göreceli derleme sırasını kaydederken birden çok çözümü tek çözümde birleştiren bir uygulama yazmak istiyorum.

Yanıtlar:


113

Microsoft.Build derlemesinin .NET 4.0 sürümü, Microsoft.Build.Construction ad alanında Visual Studio çözüm dosyalarını ayrıştıran bir SolutionParser sınıfı içerir.

Maalesef bu sınıf içseldir, ancak bu işlevselliğin bir kısmını, yararlı bulabileceğiniz bazı genel özelliklere ulaşmak için yansımayı kullanan bir sınıfa yerleştirdim.

public class Solution
{
    //internal class SolutionParser
    //Name: Microsoft.Build.Construction.SolutionParser
    //Assembly: Microsoft.Build, Version=4.0.0.0

    static readonly Type s_SolutionParser;
    static readonly PropertyInfo s_SolutionParser_solutionReader;
    static readonly MethodInfo s_SolutionParser_parseSolution;
    static readonly PropertyInfo s_SolutionParser_projects;

    static Solution()
    {
        s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if (s_SolutionParser != null)
        {
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
        }
    }

    public List<SolutionProject> Projects { get; private set; }

    public Solution(string solutionFileName)
    {
        if (s_SolutionParser == null)
        {
            throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
        }
        var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);
        using (var streamReader = new StreamReader(solutionFileName))
        {
            s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
            s_SolutionParser_parseSolution.Invoke(solutionParser, null);
        }
        var projects = new List<SolutionProject>();
        var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);
        for (int i = 0; i < array.Length; i++)
        {
            projects.Add(new SolutionProject(array.GetValue(i)));
        }
        this.Projects = projects;
    }
}

[DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
public class SolutionProject
{
    static readonly Type s_ProjectInSolution;
    static readonly PropertyInfo s_ProjectInSolution_ProjectName;
    static readonly PropertyInfo s_ProjectInSolution_RelativePath;
    static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
    static readonly PropertyInfo s_ProjectInSolution_ProjectType;

    static SolutionProject()
    {
        s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if (s_ProjectInSolution != null)
        {
            s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty("ProjectType", BindingFlags.NonPublic | BindingFlags.Instance);
        }
    }

    public string ProjectName { get; private set; }
    public string RelativePath { get; private set; }
    public string ProjectGuid { get; private set; }
    public string ProjectType { get; private set; }

    public SolutionProject(object solutionProject)
    {
        this.ProjectName = s_ProjectInSolution_ProjectName.GetValue(solutionProject, null) as string;
        this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(solutionProject, null) as string;
        this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(solutionProject, null) as string;
        this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(solutionProject, null).ToString();
    }
}

Microsoft.Build referansını projenize ekleyebilmek için hedef çerçevenizi ".NET Framework 4" (istemci profili değil) olarak değiştirmeniz gerektiğini unutmayın.


3
Bu sorun değil, ancak "Çözüm Öğeleri" gruplarını yanlış "Projeler" olarak gösteriyor.
Doug

3
Eklenecek "using" ifadeleri şunlardır: using System; System.Reflection kullanarak; System.Collections.Generic kullanarak; System.Diagnostics kullanarak; System.IO kullanarak; System.Linq kullanarak;
NealWalters

1
@Kiquenet - s_ProjectInSolution nesnesinin "ProjectType" özelliğini, sunulan diğer özelliklerle aynı şekilde inceleyebilirsiniz. Bu bir enum döndürür, ancak yalnızca ToString () ittir. Gönderiyi bunu iki kez içerecek şekilde düzenlemeye çalıştım, ancak her seferinde alevler içinde düştüm.
oasten

3
@oasten İyi niyetler olsa da, SO topluluğu bu tür düzenlemelere kaşlarını çatsa da, bunun hakkında daha fazla bilgi edinmek istiyorsanız meta tartışmalara katılmalısınız. Ben şahsen bunun bazen biraz çılgınca olduğunu düşünüyorum. Lütfen düzenlemelerinizin kapatılmasıyla hiçbir ilgim olmadığını unutmayın. Size düzenlemeler eklemeyi düşünmeme rağmen doğru yol, aslında her şeyi başka bir cevap olarak yeniden yayınlamaktır. Böylelikle, benim sağladığım her şeye ek olarak sizin katkıda bulunacağınız açıktır. Bu mantıklı ama denetleme araçları gerçekten iyi bir geri bildirim mekanizması sağlamıyor.
John Leidegren

18
SolutionFileMicrosoft.Build.dll'de Visual Studio 2015 ile yüklenen yeni bir genel sınıf var (bkz. Msdn.microsoft.com/en-us/library/… )
Phil

70

Visual Studio 2015 ile artık SolutionFileçözüm dosyalarını ayrıştırmak için kullanılabilen genel olarak erişilebilir bir sınıf var:

using Microsoft.Build.Construction;
var _solutionFile = SolutionFile.Parse(path);

Bu sınıf, Microsoft.Build.dll 14.0.0.0 derlemesinde bulunur. Benim durumumda şu adresteydi:

C:\Program Files (x86)\Reference Assemblies\Microsoft\MSBuild\v14.0\Microsoft.Build.dll

Sayesinde Phil için bu out işaret !


1
Çok kullanışlı ... powershell tüketimi için kullandığım şey bu ...Add-Type -Path "C:\Program Files (x86)\Reference Assemblies\Microsoft\MSBuild\v14.0\Microsoft.Build.dll" $slnFile = [Microsoft.Build.Construction.SolutionFile]::Parse($slnPath); $slnFile.ProjectsInOrder
SliverNinja - MSFT

2
Visual Studio 2017 ile birlikte gönderilen Microsoft.Build.dll v4.0.0.0'da böyle bir sınıf bulamadım.
Jeff G

@JeffG msbuild'i tek başına yüklemeyi deneyin.
Maciej Kucia

1
@JeffG Ayrıca VS 2017 kullanıyorum. Referans Ekle'deki Assemblies sekmesinden Mircosoft.Build'i eklersem, SolutionFile'a erişimim olmaz. Ancak, yukarıdaki klasörde bulunan dll'ye göz atarsam ve referans verirsem, işe yarıyor gibi görünüyor.
Inrego


16

Hala bu soruna çözüm arayan var mı bilmiyorum, ancak tam olarak gerekeni yapıyor gibi görünen bir projeyle karşılaştım. https://slntools.codeplex.com/ Bu aracın işlevlerinden biri, birden çok çözümü bir araya getirmektir.


Üzerinde test ettiğim çözüm dosyasında, bu slntools aslında ReSharper kitaplıklarından daha fazla ayrıntı verdi.
Răzvan Flavius ​​Panda

14

JetBrains (Resharper'ın yaratıcıları) meclislerinde herkese açık sln ayrıştırma yeteneklerine sahiptir (yansımaya gerek yoktur). Muhtemelen burada önerilen mevcut açık kaynaklı çözümlerden daha sağlamdır (ReGex hack'lerini bırakın). Yapmanız gereken tek şey:

  • İndir ReSharper Komut Satırı Araçları (ücretsiz).
  • Aşağıdakileri projenize referans olarak ekleyin
    • JetBrains.Platform.ProjectModel
    • JetBrains.Platform.Util
    • JetBrains.Platform.Interop.WinApi

Kitaplık belgelenmemiştir, ancak Reflector (veya aslında dotPeek) arkadaşınızdır. Örneğin:

public static void PrintProjects(string solutionPath)
{
    var slnFile = SolutionFileParser.ParseFile(FileSystemPath.Parse(solutionPath));
    foreach (var project in slnFile.Projects)
    {
        Console.WriteLine(project.ProjectName);
        Console.WriteLine(project.ProjectGuid);
        Console.WriteLine(project.ProjectTypeGuid);
        foreach (var kvp in project.ProjectSections)
        {
            Console.WriteLine(kvp.Key);
            foreach (var projectSection in kvp.Value) 
            {
                Console.WriteLine(projectSection.SectionName);
                Console.WriteLine(projectSection.SectionValue);
                foreach (var kvpp in projectSection.Properties)
                {
                    Console.WriteLine(kvpp.Key); 
                    Console.WriteLine(string.Join(",", kvpp.Value));
                }
            }
        }
    }
}

4
NOT: Bu gönderi itibariyle ad alanları biraz farklıdır [belki de JB kendi öğelerini yeniden
düzenledi

9

Size gerçekten bir kütüphane teklif edemem ve tahminimce orada bir tane yok mu? Ancak toplu düzenleme senaryolarında .sln dosyalarıyla uğraşmak için epey zaman harcadım ve Powershell'in bu görev için çok kullanışlı bir araç olduğunu gördüm. .SLN formatı oldukça basittir ve birkaç hızlı ve kirli ifadeyle neredeyse tamamen ayrıştırılabilir. Örneğin

Dahil edilen Proje dosyaları.

gc ConsoleApplication30.sln | 
  ? { $_ -match "^Project" } | 
  %{ $_ -match ".*=(.*)$" | out-null ; $matches[1] } | 
  %{ $_.Split(",")[1].Trim().Trim('"') }

Her zaman hoş değildir, ancak toplu işlem yapmanın etkili bir yoludur.


Evet, şimdiye kadar yaptığım şey bu
Filip Frącz 01.09

Çözüm klasörlerini dışlamak için bu işe yarıyor: (Get-Content MySolution.sln) | Nerede-Nesne {$ _ -match '(? = ^ Project (?! \ ("\ {2150E333-8FDC-42A3-9474-1A3956D46DE8 \}" \))) ^ (\ w +)'} | Her Nesne İçin {$ _ -match ". * = (. *) $" | geçersiz; $ [1]} ile eşleşir | Her Nesne İçin {$ _. Bölme (",") [1]. Trim (). Trim ('"')}
David Gardiner

6

Yeni bir çözüm oluşturan bir Visual Studio eklentisi yazarak benzer bir çözümü otomatik olarak birleştirme sorununu çözdük, ardından * .sln dosyasını aradık ve bunları kullanarak yeni bir dosyaya aktardık:

dte2.Solution.AddFromFile(solutionPath, false);

Bizim sorunumuz biraz farklıydı, çünkü VS'nin bizim için derleme sırasını düzenlemesini istiyorduk, bu yüzden mümkünse dll referanslarını proje referanslarına dönüştürdük.

Daha sonra VS'yi COM otomasyonu aracılığıyla çalıştırarak bunu bir derleme sürecine dönüştürdük.

Bu çözüm küçük bir Heath Robinson'dı, ancak VS'nin düzenlemeyi yapıyor olması avantajına sahipti, bu nedenle kodumuz sln dosyasının formatına bağlı değildi. Bu, VS 2005'ten 2008'e ve tekrar 2010'a geçtiğimizde yardımcı oldu.


DTE kullanırken bir performans probleminiz oldu mu ve eğer öyleyse bunu nasıl çözdünüz? stackoverflow.com/questions/1620199/…
Chris Moutray

@mouters DTE kullanmanın ve gui kullanmanın aynı performans açısından aynı olduğunu gördük. Yalnızca minimum VS seçeneklerini yüklemek biraz yardımcı oldu, ancak çok fazla değil. Bu otomatikleştirildiği ve bir gecede çalıştığı için, performans bizim ilgilendiğimiz bir şey değil.
Andy Lowry

Sln, projeyi içeren klasöre sahipse, klasörün içerdiği projeyi alamazsınız.
lindexi

5

Her şey harika, ancak aynı zamanda sln oluşturma yeteneğini de elde etmek istedim - yukarıdaki kod anlık görüntüsünde yalnızca .sln dosyalarını ayrıştırıyorsunuz - sln'yi yeniden .sln dosyasına küçük değişikliklerle yeniden oluşturabilmek dışında benzer bir şey yapmak istedim . Bu tür durumlar örneğin aynı projeyi farklı .NET platformu için taşımak olabilir. Şimdilik sadece yeniden oluşturma, ancak daha sonra onu projelere de genişleteceğim.

Sanırım normal ifadelerin ve yerel arayüzlerin gücünü de göstermek istedim. (Daha fazla işlevselliğe sahip daha az miktarda kod)

4.1.2017 Güncellemesi .sln çözümünü ayrıştırmak için ayrı bir svn deposu oluşturdum: https://sourceforge.net/p/syncproj/code/HEAD/tree/

Aşağıda kendi kod örnek parçam (önceki) var. Bunlardan herhangi birini kullanmakta özgürsünüz.

Gelecekte svn tabanlı çözüm ayrıştırma kodunun da üretim yetenekleriyle güncellenmesi mümkündür.

Güncelleme 4.2.2017 SVN'deki kaynak kodu .sln oluşturmayı da desteklemektedir.

using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Text;


public class Program
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class SolutionProject
    {
        public string ParentProjectGuid;
        public string ProjectName;
        public string RelativePath;
        public string ProjectGuid;

        public string AsSlnString()
        { 
            return "Project(\"" + ParentProjectGuid + "\") = \"" + ProjectName + "\", \"" + RelativePath + "\", \"" + ProjectGuid + "\"";
        }
    }

/// <summary>
/// .sln loaded into class.
/// </summary>
public class Solution
{
    public List<object> slnLines;       // List of either String (line format is not intresting to us), or SolutionProject.

    /// <summary>
    /// Loads visual studio .sln solution
    /// </summary>
    /// <param name="solutionFileName"></param>
    /// <exception cref="System.IO.FileNotFoundException">The file specified in path was not found.</exception>
    public Solution( string solutionFileName )
    {
        slnLines = new List<object>();
        String slnTxt = File.ReadAllText(solutionFileName);
        string[] lines = slnTxt.Split('\n');
        //Match string like: Project("{66666666-7777-8888-9999-AAAAAAAAAAAA}") = "ProjectName", "projectpath.csproj", "{11111111-2222-3333-4444-555555555555}"
        Regex projMatcher = new Regex("Project\\(\"(?<ParentProjectGuid>{[A-F0-9-]+})\"\\) = \"(?<ProjectName>.*?)\", \"(?<RelativePath>.*?)\", \"(?<ProjectGuid>{[A-F0-9-]+})");

        Regex.Replace(slnTxt, "^(.*?)[\n\r]*$", new MatchEvaluator(m =>
            {
                String line = m.Groups[1].Value;

                Match m2 = projMatcher.Match(line);
                if (m2.Groups.Count < 2)
                {
                    slnLines.Add(line);
                    return "";
                }

                SolutionProject s = new SolutionProject();
                foreach (String g in projMatcher.GetGroupNames().Where(x => x != "0")) /* "0" - RegEx special kind of group */
                    s.GetType().GetField(g).SetValue(s, m2.Groups[g].ToString());

                slnLines.Add(s);
                return "";
            }), 
            RegexOptions.Multiline
        );
    }

    /// <summary>
    /// Gets list of sub-projects in solution.
    /// </summary>
    /// <param name="bGetAlsoFolders">true if get also sub-folders.</param>
    public List<SolutionProject> GetProjects( bool bGetAlsoFolders = false )
    {
        var q = slnLines.Where( x => x is SolutionProject ).Select( i => i as SolutionProject );

        if( !bGetAlsoFolders )  // Filter away folder names in solution.
            q = q.Where( x => x.RelativePath != x.ProjectName );

        return q.ToList();
    }

    /// <summary>
    /// Saves solution as file.
    /// </summary>
    public void SaveAs( String asFilename )
    {
        StringBuilder s = new StringBuilder();

        for( int i = 0; i < slnLines.Count; i++ )
        {
            if( slnLines[i] is String ) 
                s.Append(slnLines[i]);
            else
                s.Append((slnLines[i] as SolutionProject).AsSlnString() );

            if( i != slnLines.Count )
                s.AppendLine();
        }

        File.WriteAllText(asFilename, s.ToString());
    }
}


    static void Main()
    {
        String projectFile = @"yourown.sln";

        try
        {
            String outProjectFile = Path.Combine(Path.GetDirectoryName(projectFile), Path.GetFileNameWithoutExtension(projectFile) + "_2.sln");
            Solution s = new Solution(projectFile);
            foreach( var proj in s.GetProjects() )
            {
                Console.WriteLine( proj.RelativePath );
            }

            SolutionProject p = s.GetProjects().Where( x => x.ProjectName.Contains("Plugin") ).First();
            p.RelativePath = Path.Combine( Path.GetDirectoryName(p.RelativePath) , Path.GetFileNameWithoutExtension(p.RelativePath) + "_Variation" + ".csproj");

            s.SaveAs(outProjectFile);

        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
}

3

MSBuild sınıflarının temel yapıları işlemek için kullanılabileceğini belirledim. Daha sonra web sitemde daha fazla kod alacağım.

// VSSolution

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using AbstractX.Contracts;

namespace VSProvider
{
    public class VSSolution : IVSSolution
    {
        //internal class SolutionParser 
        //Name: Microsoft.Build.Construction.SolutionParser 
        //Assembly: Microsoft.Build, Version=4.0.0.0 

        static readonly Type s_SolutionParser;
        static readonly PropertyInfo s_SolutionParser_solutionReader;
        static readonly MethodInfo s_SolutionParser_parseSolution;
        static readonly PropertyInfo s_SolutionParser_projects;
        private string solutionFileName;
        private List<VSProject> projects;

        public string Name
        {
            get
            {
                return Path.GetFileNameWithoutExtension(solutionFileName);
            }
        }

        public IEnumerable<IVSProject> Projects
        {
            get
            {
                return projects;
            }
        }

        static VSSolution()
        {
            s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        public string SolutionPath
        {
            get
            {
                var file = new FileInfo(solutionFileName);

                return file.DirectoryName;
            }
        }

        public VSSolution(string solutionFileName)
        {
            if (s_SolutionParser == null)
            {
                throw new InvalidOperationException("Can not find type 'Microsoft.Build.Construction.SolutionParser' are you missing a assembly reference to 'Microsoft.Build.dll'?");
            }

            var solutionParser = s_SolutionParser.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);

            using (var streamReader = new StreamReader(solutionFileName))
            {
                s_SolutionParser_solutionReader.SetValue(solutionParser, streamReader, null);
                s_SolutionParser_parseSolution.Invoke(solutionParser, null);
            }

            this.solutionFileName = solutionFileName;

            projects = new List<VSProject>();
            var array = (Array)s_SolutionParser_projects.GetValue(solutionParser, null);

            for (int i = 0; i < array.Length; i++)
            {
                projects.Add(new VSProject(this, array.GetValue(i)));
            }
        }

        public void Dispose()
        {
        }
    }
}

// VSProject

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Xml;
using AbstractX.Contracts;
using System.Collections;

namespace VSProvider
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class VSProject : IVSProject
    {
        static readonly Type s_ProjectInSolution;
        static readonly Type s_RootElement;
        static readonly Type s_ProjectRootElement;
        static readonly Type s_ProjectRootElementCache;
        static readonly PropertyInfo s_ProjectInSolution_ProjectName;
        static readonly PropertyInfo s_ProjectInSolution_ProjectType;
        static readonly PropertyInfo s_ProjectInSolution_RelativePath;
        static readonly PropertyInfo s_ProjectInSolution_ProjectGuid;
        static readonly PropertyInfo s_ProjectRootElement_Items;

        private VSSolution solution;
        private string projectFileName;
        private object internalSolutionProject;
        private List<VSProjectItem> items;
        public string Name { get; private set; }
        public string ProjectType { get; private set; }
        public string RelativePath { get; private set; }
        public string ProjectGuid { get; private set; }

        public string FileName
        {
            get
            {
                return projectFileName;
            }
        }

        static VSProject()
        {
            s_ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectInSolution_ProjectName = s_ProjectInSolution.GetProperty("ProjectName", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectType = s_ProjectInSolution.GetProperty("ProjectType", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_RelativePath = s_ProjectInSolution.GetProperty("RelativePath", BindingFlags.NonPublic | BindingFlags.Instance);
            s_ProjectInSolution_ProjectGuid = s_ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.NonPublic | BindingFlags.Instance);

            s_ProjectRootElement = Type.GetType("Microsoft.Build.Construction.ProjectRootElement, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
            s_ProjectRootElementCache = Type.GetType("Microsoft.Build.Evaluation.ProjectRootElementCache, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectRootElement_Items = s_ProjectRootElement.GetProperty("Items", BindingFlags.Public | BindingFlags.Instance);
        }

        public IEnumerable<IVSProjectItem> Items
        {
            get
            {
                return items;
            }
        }

        public VSProject(VSSolution solution, object internalSolutionProject)
        {
            this.Name = s_ProjectInSolution_ProjectName.GetValue(internalSolutionProject, null) as string;
            this.ProjectType = s_ProjectInSolution_ProjectType.GetValue(internalSolutionProject, null).ToString();
            this.RelativePath = s_ProjectInSolution_RelativePath.GetValue(internalSolutionProject, null) as string;
            this.ProjectGuid = s_ProjectInSolution_ProjectGuid.GetValue(internalSolutionProject, null) as string;

            this.solution = solution;
            this.internalSolutionProject = internalSolutionProject;

            this.projectFileName = Path.Combine(solution.SolutionPath, this.RelativePath);

            items = new List<VSProjectItem>();

            if (this.ProjectType == "KnownToBeMSBuildFormat")
            {
                this.Parse();
            }
        }

        private void Parse()
        {
            var stream = File.OpenRead(projectFileName);
            var reader = XmlReader.Create(stream);
            var cache = s_ProjectRootElementCache.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(new object[] { true });
            var rootElement = s_ProjectRootElement.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(new object[] { reader, cache });

            stream.Close();

            var collection = (ICollection)s_ProjectRootElement_Items.GetValue(rootElement, null);

            foreach (var item in collection)
            {
                items.Add(new VSProjectItem(this, item));
            }

        }

        public IEnumerable<IVSProjectItem> EDMXModels
        {
            get 
            {
                return this.items.Where(i => i.ItemType == "EntityDeploy");
            }
        }

        public void Dispose()
        {
        }
    }
}

// VSProjectItem

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Xml;
using AbstractX.Contracts;

namespace VSProvider
{
    [DebuggerDisplay("{ProjectName}, {RelativePath}, {ProjectGuid}")]
    public class VSProjectItem : IVSProjectItem
    {
        static readonly Type s_ProjectItemElement;
        static readonly PropertyInfo s_ProjectItemElement_ItemType;
        static readonly PropertyInfo s_ProjectItemElement_Include;

        private VSProject project;
        private object internalProjectItem;
        private string fileName;

        static VSProjectItem()
        {
            s_ProjectItemElement = Type.GetType("Microsoft.Build.Construction.ProjectItemElement, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);

            s_ProjectItemElement_ItemType = s_ProjectItemElement.GetProperty("ItemType", BindingFlags.Public | BindingFlags.Instance);
            s_ProjectItemElement_Include = s_ProjectItemElement.GetProperty("Include", BindingFlags.Public | BindingFlags.Instance);
        }

        public string ItemType { get; private set; }
        public string Include { get; private set; }

        public VSProjectItem(VSProject project, object internalProjectItem)
        {
            this.ItemType = s_ProjectItemElement_ItemType.GetValue(internalProjectItem, null) as string;
            this.Include = s_ProjectItemElement_Include.GetValue(internalProjectItem, null) as string;
            this.project = project;
            this.internalProjectItem = internalProjectItem;

            // todo - expand this

            if (this.ItemType == "Compile" || this.ItemType == "EntityDeploy")
            {
                var file = new FileInfo(project.FileName);

                fileName = Path.Combine(file.DirectoryName, this.Include);
            }
        }

        public byte[] FileContents
        {
            get 
            {
                return File.ReadAllBytes(fileName);
            }
        }

        public string Name
        {
            get 
            {
                if (fileName != null)
                {
                    var file = new FileInfo(fileName);

                    return file.Name;
                }
                else
                {
                    return this.Include;
                }
            }
        }
    }
}

AbstractX'in nereden geldiğine dair bir fikriniz var mı?
gunr2171

Bu, ASP.Net web sitelerini yanlış yorumluyor gibi görünüyor, burada relativepathsitenin IISExpress vb. Altında çalıştırması gereken URL.
Doug

1

Cevap @ john-leidegren tarafından harika. VS2015 öncesi için bu çok kullanışlı. Ancak yapılandırmaları alma kodu eksik olduğu için küçük bir hata vardı. Birisinin bu kodu kullanmakta zorlanması durumunda eklemek istedim.
Geliştirme çok basit:

    public class Solution
{
    //internal class SolutionParser
    //Name: Microsoft.Build.Construction.SolutionParser
    //Assembly: Microsoft.Build, Version=4.0.0.0

    static readonly Type s_SolutionParser;
    static readonly PropertyInfo s_SolutionParser_solutionReader;
    static readonly MethodInfo s_SolutionParser_parseSolution;
    static readonly PropertyInfo s_SolutionParser_projects;
    static readonly PropertyInfo s_SolutionParser_configurations;//this was missing in john's answer


    static Solution()
    {
        s_SolutionParser = Type.GetType("Microsoft.Build.Construction.SolutionParser, Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, false);
        if ( s_SolutionParser != null )
        {
            s_SolutionParser_solutionReader = s_SolutionParser.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_projects = s_SolutionParser.GetProperty("Projects", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_parseSolution = s_SolutionParser.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
            s_SolutionParser_configurations = s_SolutionParser.GetProperty("SolutionConfigurations", BindingFlags.NonPublic | BindingFlags.Instance); //this was missing in john's answer

            // additional info:
            var PropNameLst = GenHlp_PropBrowser.PropNamesOfType(s_SolutionParser);
            // the above call would yield something like this:
            // [ 0] "SolutionParserWarnings"        string
            // [ 1] "SolutionParserComments"        string
            // [ 2] "SolutionParserErrorCodes"      string
            // [ 3] "Version"                       string
            // [ 4] "ContainsWebProjects"           string
            // [ 5] "ContainsWebDeploymentProjects" string
            // [ 6] "ProjectsInOrder"               string
            // [ 7] "ProjectsByGuid"                string
            // [ 8] "SolutionFile"                  string
            // [ 9] "SolutionFileDirectory"         string
            // [10] "SolutionReader"                string
            // [11] "Projects"                      string
            // [12] "SolutionConfigurations"        string
        }
    }

    public List<SolutionProject> Projects { get; private set; }
    public List<SolutionConfiguration> Configurations { get; private set; }

   //...
   //...
   //... no change in the rest of the code
}

Ek yardım olarak, System.Type@oasten tarafından önerildiği gibi a'nın özelliklerine göz atmak için basit bir kod sağlamak .

public class GenHlp_PropBrowser
{
    public static List<string> PropNamesOfClass(object anObj)
    {
        return anObj == null ? null : PropNamesOfType(anObj.GetType());
    }
    public static List<String> PropNamesOfType(System.Type aTyp)
    {
        List<string> retLst = new List<string>();
        foreach ( var p in aTyp.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) )
        {
            retLst.Add(p.Name);
        }
        return retLst;
    }
}


0

Teşekkürler @John Leidegren, etkili bir yol sunuyor. Bir hlper sınıfı yazıyorum çünkü onu bulamayan kodunu kullanamıyorums_SolutionParser_configurationsFullName olmadan ve projeleri .

Kod github'da FullName ile projeleri alabilen içindedir.

Ve kod SolutionConfiguration'ı alamaz.

Ama bir vsx geliştirdiğinizde, vs bulamıyorum diyecek Microsoft.Build.dll , bu nedenle tüm projeleri almak için dte'yi kullanmayı deneyebilirsiniz.

Kullanım DTE tüm projeleri almak için bu kod ise github


@ NP83 Teşekkür ederim ve bağlantıyı sildim
lindexi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.