2017-01-23 5 views
3

Ich möchte ein NuGet-Paket programmgesteuert in ein Projekt installieren und die .csproj-Datei und die packages.config-Datei aktualisieren.Wie programmiere ich ein NuGet-Paket?

ich den offiziellen Nuget.core Rahmen bin mit der Source-Code verfügbar ist hier: https://github.com/NuGet/NuGet2

Ich bin nicht das NuGet Paket mit: https://www.nuget.org/packages/NuGet.Core/ Aber der Quellcode auf GitHub gefunden Lage sein, einige Debug zu tun.

Anmerkung: Ich bin mit der Version 2.11 und nicht die 2.13

ich in der Lage bin ein Paket in einem gewünschten Verzeichnis zum Herunterladen und Aktualisieren der packages.config Datei:

// ---- Download and install a package at a desired path ---- 
string packageID = "Newtonsoft.json"; 
var sourceUri = new Uri("https://packages.nuget.org/api/v2"); 

// Return an IPackage 
var package = GetNugetPackage(packageID, sourceUri); 

IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository(sourceUri.ToString()); 

string packagesPath = "../../TestFiles/packages"; 
PackageManager packageManager = new PackageManager(sourceRepository, packagesPath); 

packageManager.InstallPackage(packageID, SemanticVersion.Parse(package.Version.ToFullString())); 

// ---- Update the ‘packages.config’ file ---- 
var packageReferenceFile = new PackageReferenceFile("../../TestFiles/packages.config"); 

// Get the target framework of the current project to add --> targetframework="net452" attribute in the package.config file 
var currentTargetFw = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(TargetFrameworkAttribute), false); 
var targetFrameworkAttribute = ((TargetFrameworkAttribute[])currentTargetFw).FirstOrDefault(); 

// Update the packages.config file  
packageReferenceFile.AddEntry(package.GetFullName(), SemanticVersion.Parse(package.Version.ToFullString()), false, new FrameworkName(targetFrameworkAttribute.FrameworkName)); 

Jetzt Ich muss die .csproj aktualisieren und hier ist der knifflige Teil ...

Hier ist, was ich bisher versucht:

string csprojFilePath = "../../TestFiles/test.csproj"; 
var project = new MSBuildProjectSystem(csprojFilePath); 

string pathToAnExistingNugetPackageDll = "../../TestFiles/packages/Newtonsoft.json/lib/net45/Newtonsoft.json.dll" 

project.AddReference(pathToAnExistingNugetPackageDll, Stream.Null); 
project.Save(); 

Dieses Stück Code-Update die .csproj Datei, eine neue reference Knoten wie folgt hinzu:

<Reference Include="Newtonsoft.json"> 
    <HintPath>..\packages\Newtonsoft.json\lib\net45\Newtonsoft.json.dll</HintPath>  
</Reference> 

Aber ich brauche eine komplettereference Knoten wie folgt:

<Reference Include="Newtonsoft.json, Version=9.0.8, Culture=neutral, PublicKeyToken=b03f4f7d11d50a3a, processorArchitecture=MSIL"> 
    <HintPath>..\packages\Newtonsoft.json\lib\net45\Newtonsoft.json.dll</HintPath> 
    <Private>True</Private> 
</Reference> 

Wie kann ich das tun?

+1

Sie müssen die Referenz selbst mit Ihrem eigenen Code generieren. Dieser spezielle Referenzstil wird von Visual Studio und nicht von NuGet generiert. NuGet generiert den Verweis mit einem Include-Attribut, das nicht den vollständigen Assemblynamen verwendet. –

+0

Ich habe eine Klasse gefunden, die den Trick in der Core-Assembly zu tun scheint: 'RemoteAssembly' scheint meine benötigten Attribute zu laden ... Ich werde es versuchen – Thomas

Antwort

5

Dank @MattWard und @bashis, ich meinen eigenen Code-Generator geschrieben habe:

So hinzuzufügen richtig einen Verweis in eine gegebenen .csproj hier ist, was ich tue:

var CsprojDoc = new XmlDocument(); 
CsprojDoc.LoadXml("*your_csproj_content*"); 
var Nsmgr = new XmlNamespaceManager(CsprojDoc.NameTable); 
Nsmgr.AddNamespace("x", "http://schemas.microsoft.com/developer/msbuild/2003"); 

IPackage packageInfos = GetNugetPackage(packageId, packageRepositoryUri); 

XmlNode referenceNode = CsprojDoc.CreateNode(XmlNodeType.Element, "Reference", XmlNamespaceValue); 
XmlAttribute includeAttribute = CsprojDoc.CreateAttribute("Include"); 

var targetFwProfile = CsprojDoc.SelectSingleNode("//x:TargetFrameworkProfile", Nsmgr); 
string targetFrameworkProfile = string.Empty; 
if (!string.IsNullOrEmpty(targetFwProfile?.InnerXml)) 
{ 
    targetFrameworkProfile = targetFwProfile.InnerXml; 
} 

var targetFwAttribute = GetTargetFrameworkFromCsproj(); 
Regex p = new Regex(@"\d+(\.\d+)+"); 
Match m = p.Match(targetFwAttribute.FrameworkName); 
Version targetFwVersion = Version.Parse(m.Value); 

// Get the package's assembly reference matching the target framework from the given '.csproj'. 
var assemblyReference = 
    packageInfos.AssemblyReferences 
     .Where(a => a.TargetFramework.Identifier.Equals(targetFwAttribute.FrameworkName.Split(',').First())) 
     .Where(a => a.TargetFramework.Profile.Equals(targetFrameworkProfile)) 
     .Last(a => (a.TargetFramework.Version.Major.Equals(targetFwVersion.Major) && a.TargetFramework.Version.Minor.Equals(targetFwVersion.Minor)) || 
     a.TargetFramework.Version.Major.Equals(targetFwVersion.Major)); 

DownloadNugetPackage(packageInfos.Id, packageRepositoryUri, packagesFolderPath, packageInfos.Version.ToFullString()); 

string dllAbsolutePath = Path.GetFullPath($"{packagesFolderPath}\\{packageInfos.GetFullName().Replace(' ', '.')}\\{assemblyReference.Path}"); 
var assemblyInfos = Assembly.LoadFile(dllAbsolutePath); 

includeAttribute.Value = $"{assemblyInfos.FullName}, processorArchitecture=MSIL"; 

referenceNode.Attributes.Append(includeAttribute); 

XmlNode hintPathNode = CsprojDoc.CreateNode(XmlNodeType.Element, "HintPath", XmlNamespaceValue); 
XmlNode privateNode = CsprojDoc.CreateNode(XmlNodeType.Element, "Private", XmlNamespaceValue); 

hintPathNode.InnerXml = $"$(SolutionDir)\\packages\\{assemblyReference.Path}"; 
privateNode.InnerXml = "True"; 

referenceNode.AppendChild(hintPathNode); 
referenceNode.AppendChild(privateNode); 
var itemGroupNode = CsprojDoc.SelectSingleNode("//x:Project/x:ItemGroup/x:Reference", Nsmgr).ParentNode; 
itemGroupNode.AppendChild(referenceNode); 

Hier ist meine DownloadNugetPackage Methode:

private static void DownloadNugetPackage(string packageId, Uri repoUri, string packagesFolderPath, string version) 
{ 
    IPackageRepository packageRepository = PackageRepositoryFactory.Default.CreateRepository(repoUri.ToString()); 
    PackageManager packageManager = new PackageManager(packageRepository, packagesFolderPath); 

    packageManager.InstallPackage(packageId, SemanticVersion.Parse(version)); 
} 

M y GetTargetFrameworkFromCsproj

public static TargetFrameworkAttribute GetTargetFrameworkFromCsproj() 
    { 
     XmlNode targetFrameworkNode = CsprojDoc.SelectSingleNode("//x:TargetFrameworkVersion", Nsmgr); 
     return new TargetFrameworkAttribute($".NETFramework, Version={targetFrameworkNode.InnerXml}"); 
    } 

Und meine GetNugetPackage Methode:

public static IPackage GetNugetPackage(string packageId, Uri repoUri, string version = null) 
{ 
    IPackageRepository packageRepository = PackageRepositoryFactory.Default.CreateRepository(repoUri.ToString()); 
    IPackage package; 

    if (!string.IsNullOrEmpty(version)) 
    { 
     package = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.Version.ToFullString().Equals(version)); 
    } 
    else 
    { 
     package = packageRepository.FindPackagesById(packageId).SingleOrDefault(p => p.IsLatestVersion); 
    } 

    return package; 
} 

Hinweis: Dieses Mal, ich bin mit dem offiziellen NuGet Paket: Nuget.core 2,14: https://www.nuget.org/packages/NuGet.Core/

Hinweis 2: Wenn ich einen neuen Reference Knoten hinzufüge, habe ich im Attribut processorArchitecture den Werthart codiert

Wenn Sie es testen möchten, könnten Sie es ein wenig zwicken.

Das funktioniert gut für mich.

+0

Danke, dass du zurückkommst und eine Antwort gibst, ich brauche das nicht selbst, aber es ist ein seltener (aber sehr willkommener) Anblick :-) –

+0

@ JayGouldwill freundlich – Thomas

1

(Vorausgesetzt, dass Sie den Code-Generator schreiben auf eigene Faust)

Ich bin nicht sicher, ob dies die beste Lösung ist, aber man könnte so etwas wie dies versuchen:

var assembly = Assembly.LoadFile("path_to_dll"); 
string info = assembly.FullName; // contains something like "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=foobar" 

, die etwas Aufwand hinzufügen wird Laden der Baugruppe, wird aber vermutlich den Job erledigen.

+0

Das wird mir sehr helfen, wenn ich nicht denke heraus, wie man es mit nuget.core machen kann, werde ich Ihre Methode verwenden, um meinen eigenen Generator zu erstellen. – Thomas

+0

Ich schreibe meinen eigenen Code-Generator, und dein Code macht den Trick, danke – Thomas

Verwandte Themen