पार्सिंग विज़ुअल स्टूडियो सॉल्यूशन फाइलें


109

मैं .NET में Visual Studio समाधान (SLN) फ़ाइलों को पार्स कैसे कर सकता हूं? मैं एक ऐप लिखना चाहूंगा जो सापेक्ष निर्माण क्रम को बचाते हुए कई समाधानों को एक में मिला देता है।

जवाबों:


113

Microsoft.Build असेंबली के .NET 4.0 संस्करण में Microsoft में एक SolutionParser वर्ग होता है। Bild.Construction नामस्थान जो Visual Studio समाधान फ़ाइलों को पार्स करता है।

दुर्भाग्य से यह वर्ग आंतरिक है, लेकिन मैंने उस कार्यक्षमता में से कुछ को एक वर्ग में लपेट दिया है जो कि कुछ सामान्य गुणों को प्राप्त करने के लिए परावर्तन का उपयोग करता है जो आपको उपयोगी लग सकते हैं।

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 संदर्भ जोड़ने में सक्षम होने के लिए अपना लक्ष्य ढाँचा ".NET Framework 4" (क्लाइंट प्रोफ़ाइल नहीं) बदलना होगा।


3
यह ठीक है, हालांकि यह "समाधान आइटम" समूहों को "प्रोजेक्ट" के रूप में दिखाता है जो गलत है।
डग

3
यहाँ जोड़ने के लिए "उपयोग" कथन हैं: सिस्टम का उपयोग करना; System.Reflection का उपयोग करना; System.Collections.Generic का उपयोग कर; System.Diagnostics का उपयोग करना; System.IO का उपयोग कर; System.Linq का उपयोग करना;
नीलवैल्ट्स

1
@Kiquenet - आप s_ProjectInSolution ऑब्जेक्ट की "ProjectType" संपत्ति की उसी तरह से जांच कर सकते हैं, जिस तरह से अन्य गुण उजागर होते हैं। यह एक एनम लौटाता है लेकिन सिर्फ ToString ()। मैंने इसे दो बार शामिल करने के लिए पोस्ट को संपादित करने की कोशिश की, लेकिन हर बार आग की लपटों में फंस गया।
oasten

3
@oasten जब अच्छे इरादे हैं तो एसओ समुदाय ऐसे संपादनों पर ध्यान केंद्रित करता है जो आपको मेटा चर्चाओं में संलग्न करना चाहिए यदि आप इस बारे में अधिक जानना चाहते हैं। मुझे व्यक्तिगत रूप से लगता है कि यह कभी-कभी थोड़ा पागल होता है। कृपया ध्यान दें कि आपके संपादन बंद होने से मेरा कोई लेना-देना नहीं था। उचित तरीका है कि मुझे लगता है कि आप संपादन जोड़ने के लिए वास्तव में एक और जवाब के रूप में सब कुछ repost है। इस तरह यह स्पष्ट है कि आप मूल रूप से मेरे द्वारा प्रदान किए गए शीर्ष पर योगदानकर्ता हैं। यह समझ में आता है, लेकिन मॉडरेशन उपकरण वास्तव में एक अच्छा प्रतिक्रिया तंत्र प्रदान नहीं करते हैं।
जॉन लीडग्रेन

18
SolutionFileMicrosoft में एक नया सार्वजनिक वर्ग प्रस्तुत किया गया है। Bild.dll जो Visual Studio 2015 के साथ स्थापित है (देखें msdn.microsoft.com/en-us/library/… )
Phil

70

विजुअल स्टूडियो 2015 के साथ अब एक सार्वजनिक रूप से सुलभ SolutionFileवर्ग है जिसका उपयोग समाधान फ़ाइलों को पार्स करने के लिए किया जा सकता है:

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

यह वर्ग Microsoft.Build.dll 14.0.0.0 असेंबली में पाया जाता है । मेरे मामले में यह यहां स्थित था:

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

यह इंगित करने के लिए फिल के लिए धन्यवाद !


1
बहुत उपयोगी ... यह वही है जो मैंने 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
पॉवरशेल

2
मुझे Microsoft में ऐसा कोई वर्ग नहीं मिला। Visual Studio 2017 के साथ Build.dll v4.0.0.0 को भेज दिया गया।
Jeff G

@JeffG अकेले msbuild स्थापित करने का प्रयास करें।
मैकीज कुसिया

1
@ जेफ मैं भी वीएस 2017 का उपयोग कर रहा हूं। अगर मैं ऐड संदर्भ में असेंबली टैब से Mircosoft.Bild जोड़ता हूं, तो मेरे पास SolutionFile तक पहुंच नहीं है। हालांकि, अगर मैं ऊपर दिए गए फ़ोल्डर में स्थित dll को ब्राउज़ और संदर्भ देता हूं, तो यह काम करने लगता है।
inrego

3
@JeffG यह पैकेज अब NuGet nuget.org/packages/Microsoft.Build
रॉबर्ट

16

मुझे नहीं पता कि अगर कोई अभी भी इस समस्या का समाधान ढूंढ रहा है, लेकिन मैं एक ऐसी परियोजना के लिए दौड़ा, जो सिर्फ जरूरत के मुताबिक काम करती है। https://slntools.codeplex.com/ इस उपकरण का एक कार्य कई समाधानों को एक साथ मिलाना है।


मैंने जिस समाधान फ़ाइल का परीक्षण किया, उस पर इस स्लेंटूल ने वास्तव में रीशर लीवर्स की तुलना में अधिक विवरण दिया था।
रेज़वान फ्लेवियस पांडा

14

JetBrains (Resharper के रचनाकारों) की सार्वजनिक असेंबली में उनकी विधानसभाओं में पार्स करने की क्षमता है (कोई प्रतिबिंब आवश्यक नहीं)। यह संभवतः यहां सुझाए गए मौजूदा ओपन सोर्स समाधानों से अधिक मजबूत है (अकेले रेग्क्स हैक्स को छोड़ दें)। आपको बस इतना करना है:

  • ReSharper कमांड लाइन टूल डाउनलोड करें (मुफ्त) करें।
  • अपनी परियोजना के संदर्भ में निम्नलिखित जोड़ें
    • JetBrains.Platform.ProjectModel
    • JetBrains.Platform.Util
    • JetBrains.Platform.Interop.WinApi

पुस्तकालय प्रलेखित नहीं है, लेकिन रिफ्लेक्टर (या वास्तव में, डॉटपेक) आपका मित्र है। उदाहरण के लिए:

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
~ JetBrains.Platform.ProjectModel ~ JetBrains.Platform.Util ~ JetBrains.Platform.Interop.WinApi: नोट: इस पोस्ट नामस्थान कुछ भिन्न होते हैं के रूप में [शायद जेबी उनके सामान :) पुनर्संशोधित]
lewiSnort

9

मैं वास्तव में आपको एक पुस्तकालय की पेशकश नहीं कर सकता और मेरा अनुमान है कि वहां कोई भी मौजूद नहीं है। लेकिन मैंने बैच संपादन परिदृश्यों में .sln फ़ाइलों के साथ खिलवाड़ करते हुए समय बिताया है और मैंने पॉवर्स को इस कार्य के लिए एक बहुत उपयोगी उपकरण पाया है। .SLN प्रारूप बहुत सरल है और कुछ त्वरित और गंदे भावों के साथ लगभग पूरी तरह से पार्स किया जा सकता है। उदाहरण के लिए

प्रोजेक्ट फ़ाइलें शामिल हैं।

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

यह हमेशा सुंदर नहीं होता है, लेकिन यह बैच प्रोसेसिंग करने का एक प्रभावी तरीका है।


हाँ, यह है कि मैं अब तक क्या कर रहा हूँ
Filip Fr'cz

समाधान फ़ोल्डरों को बाहर करने के लिए यह मेरे लिए काम करता है: (Get-Content MySolution.sln) | जहाँ-जहाँ {$ _ -match ’(; = ^ प्रोजेक्ट! (! \" (\ {2150E333-8FDC-42A3-9474-1A3956D46DE8 \} "\ _)) ^ (\ w +) '}} | ForEach-Object {$ _ -match "। * = (। *।) $" | अशक्त; $ मैच [1]} | ForEach-Object {$ _। स्प्लिट (",") [1] .Trim ()। ट्रिम ('' ')}
डेविड गार्डिनर

6

हमने विज़ुअल स्टूडियो प्लगइन लिखकर स्वचालित रूप से समाधान विलय की एक समान समस्या को हल किया जिसने एक नया समाधान बनाया फिर * .Sln फ़ाइल के लिए खोज की और उन्हें नए प्रयोग में आयात किया:

dte2.Solution.AddFromFile(solutionPath, false);

हमारी समस्या थोड़ी अलग थी कि हम चाहते थे कि वीएस हमारे लिए बिल्ड ऑर्डर को छांटे, इसलिए हमने प्रोजेक्ट संदर्भों के लिए किसी भी dll संदर्भ को जहां संभव हो, रूपांतरित किया।

हम तो COM स्वचालन के माध्यम से वी.एस.

यह समाधान थोड़ा हीथ रॉबिन्सन था, लेकिन इसका लाभ यह था कि वीएस संपादन कर रहा था, इसलिए हमारा कोड स्लैब फ़ाइल के प्रारूप पर निर्भर नहीं था। जब हम वीएस 2005 से 2008 और फिर 2010 तक चले गए तो यह मददगार था।


क्या आपको DTE का उपयोग करने में कोई प्रदर्शन समस्या है और यदि ऐसा है तो आपने इसे कैसे हल किया? stackoverflow.com/questions/1620199/…
क्रिस Moutray

@mouters हमने पाया कि DTE का उपयोग करना और gui का उपयोग करना समान प्रदर्शन के बारे में था। केवल न्यूनतम वीएस विकल्पों को स्थापित करने से थोड़ी मदद मिली, लेकिन ज्यादा नहीं। जैसा कि यह स्वचालित है और रात भर चल रहा है, प्रदर्शन कुछ ऐसा नहीं है जिससे हम चिंतित हैं।
एंडी लोरी

यदि sln में वह फ़ोल्डर है जिसमें प्रोजेक्ट शामिल है, तो आप उस प्रोजेक्ट को प्राप्त नहीं कर सकते हैं जो फ़ोल्डर में शामिल है।
lindexi

5

सब कुछ बहुत अच्छा है, लेकिन मैं भी sln पीढ़ी की क्षमता प्राप्त करना चाहता था - ऊपर कोड स्नैपशॉट में आप केवल पार्सिंग कर रहे हैं। फाइलें - मैं मामूली संशोधन के साथ एसएलएन को फिर से उत्पन्न करने में सक्षम होने के अलावा इसी तरह की चीज बनाना चाहता था। । इस तरह के मामले विभिन्न .NET प्लेटफॉर्म के लिए एक ही प्रोजेक्ट को पोर्ट करने के लिए हो सकते हैं। अभी के लिए यह केवल पुन: उत्पादन करने वाली है, लेकिन बाद में मैं इसे परियोजनाओं तक भी विस्तारित करूँगा।

मुझे लगता है कि मैं नियमित अभिव्यक्तियों और देशी इंटरफेस की शक्ति का प्रदर्शन करना चाहता था। (अधिक कार्यक्षमता के साथ कोड की छोटी मात्रा)

अद्यतन 4.1.2017 मैंने पार्स करने के लिए अलग svn रिपॉजिटरी बनाई है। एसएलएन समाधान: https://sourceforge.net/p/syncproj/code/HEAD/tree/

नीचे मेरा अपना कोड नमूना स्निपेट (पूर्ववर्ती) है। आप उनमें से किसी का उपयोग करने के लिए स्वतंत्र हैं।

यह संभव है कि भविष्य में svn आधारित समाधान पार्सिंग कोड पीढ़ी की क्षमताओं के साथ भी अपडेट होगा।

अद्यतन 4.2.2017 SVN में स्रोत कोड .sl पीढ़ी का भी समर्थन कर रहा है।

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 वर्गों का उपयोग किया जा सकता है। मेरे पास बाद में मेरी वेब साइट पर आगे कोड होगा।

// 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 कहाँ से आता है?
गन्र

यह ASP.Net वेबसाइटों की गलत व्याख्या करता relativepathहै, जहाँ URL वह साइट है जिसे IISExpress आदि के अंतर्गत चलना चाहिए।
डग

1

@ John-leidegren द्वारा उत्तर महान है। पूर्व VS2015 के लिए, यह बहुत काम का है। लेकिन एक छोटी सी गलती थी, क्योंकि कॉन्फ़िगरेशन पुनर्प्राप्त करने का कोड गायब था। इसलिए इसे जोड़ना चाहते हैं, यदि कोई इस कोड का उपयोग करने के लिए संघर्ष कर रहा है।
वृद्धि बहुत सरल है:

    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
}

अतिरिक्त मदद के रूप में, System.Type@oasten द्वारा सुझाए गए के गुणों के माध्यम से ब्राउज़ करने के लिए सरल कोड प्रदान करना ।

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

धन्यवाद @ जॉन लीडग्रेन वह एक प्रभावी तरीका प्रदान करता है। मैं Il के लिए एक hlper वर्ग लिखता हूं जो अपने कोड का उपयोग नहीं करता है जो कि नहीं ढूँढ सकता हैs_SolutionParser_configurations बिना और परियोजनाओं को ।

कोड जीथब में है जो FullName के साथ प्रोजेक्ट प्राप्त कर सकता है।

और कोड कठबोली SolutionConfiguration मिलता है।

लेकिन जब आप एक बनाम एक देव बनाम खिचड़ी भाषा खोजने के लिए कहेंगे Microsoft.Build.dll देवता को , तो आप सभी परियोजनाओं को प्राप्त करने के लिए dte का उपयोग करने का प्रयास कर सकते हैं।

सभी परियोजनाओं को प्राप्त करने के लिए dte का उपयोग करने वाला कोड github में है


@ NP83 धन्यवाद और मैंने लिंक को डिलीट कर दिया
lindexi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.