@@ -73,17 +73,120 @@ public static bool HasCondition(XElement element, string condition)
7373 return StringComparer . OrdinalIgnoreCase . Equals ( MSBuildStringUtility . TrimAndGetNullForEmpty ( condition ) , elementCondition ) ;
7474 }
7575
76+ /// <summary>
77+ /// Opens a project file, adds an MSBuild item, and writes it back.
78+ /// This is the simplest method for adding an item to a project file, but it is not the most efficient if you need to add multiple items since it opens and writes the file for each item added.
79+ /// Prefer this method whenever there you only need to do 1 item change.
80+ /// </summary>
81+ /// <param name="projectFilePath">The full path to the project file.</param>
82+ /// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>).</param>
83+ /// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
84+ /// <param name="framework">
85+ /// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c>.
86+ /// Pass an empty string to emit the item unconditionally.
87+ /// </param>
88+ /// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
89+ public static void AddItem ( string projectFilePath ,
90+ string name ,
91+ string identity ,
92+ string framework ,
93+ Dictionary < string , string > attributes )
94+ {
95+ using var stream = File . Open ( projectFilePath , FileMode . Open , FileAccess . ReadWrite ) ;
96+ var xml = XDocument . Load ( stream ) ;
97+ AddItem ( xml , name , identity , framework , attributes ) ;
98+ WriteXmlToFile ( xml , stream ) ;
99+ }
100+
101+ /// <summary>
102+ /// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
103+ /// When <paramref name="framework"/> is a specific framework, a <c>Condition</c> attribute of the form
104+ /// <c>'$(TargetFramework)' == '<tfm>'</c> is added to the <c>ItemGroup</c>; otherwise no condition is emitted.
105+ /// Scenarios:
106+ /// <list type="bullet">
107+ /// <item>Adding a <c>PackageReference</c> item</item>
108+ /// <item>Adding a <c>PackageVersion</c> item</item>
109+ /// <item>Adding a <c>FrameworkReference</c> item</item>
110+ /// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
111+ /// <item>Adding a <c>PrunePackageReference</c> item</item>
112+ /// </list>
113+ /// </summary>
114+ /// <param name="doc">The project XML document to modify.</param>
115+ /// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
116+ /// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
117+ /// <param name="framework">
118+ /// The target framework used to generate a per-TFM condition on the <c>ItemGroup</c>.
119+ /// Pass <see cref="NuGetFramework.AnyFramework"/> (or any non-specific framework) to emit the item unconditionally.
120+ /// </param>
121+ /// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
76122 public static void AddItem ( XDocument doc ,
77123 string name ,
78124 string identity ,
79125 NuGetFramework framework ,
80- Dictionary < string , string > properties ,
81126 Dictionary < string , string > attributes )
82127 {
83128 AddItem ( doc , name , identity ,
84- framework ? . IsSpecificFramework == true ? framework . GetShortFolderName ( ) : string . Empty , properties , attributes ) ;
129+ framework ? . IsSpecificFramework == true ? framework . GetShortFolderName ( ) : string . Empty , attributes ) ;
130+ }
131+
132+ /// <summary>
133+ /// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
134+ /// When <paramref name="framework"/> is a non-empty string, a <c>Condition</c> attribute of the form
135+ /// <c>'$(TargetFramework)' == '<tfm>'</c> is added to the <c>ItemGroup</c>; pass an empty string to emit the item unconditionally.
136+ /// Item metadata is expressed as XML attributes on the item element. For most scenarios this overload is preferred over
137+ /// the one that accepts both <c>properties</c> and <c>attributes</c>.
138+ /// Scenarios:
139+ /// <list type="bullet">
140+ /// <item>Adding a <c>PackageReference</c> item</item>
141+ /// <item>Adding a <c>PackageVersion</c> item</item>
142+ /// <item>Adding a <c>FrameworkReference</c> item</item>
143+ /// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
144+ /// <item>Adding a <c>PrunePackageReference</c> item</item>
145+ /// </list>
146+ /// </summary>
147+ /// <param name="doc">The project XML document to modify.</param>
148+ /// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
149+ /// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
150+ /// <param name="framework">
151+ /// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c> (e.g. <c>"net8.0"</c>).
152+ /// Pass an empty string to emit the item unconditionally.
153+ /// </param>
154+ /// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
155+ public static void AddItem ( XDocument doc ,
156+ string name ,
157+ string identity ,
158+ string framework ,
159+ Dictionary < string , string > attributes )
160+ {
161+ AddItem ( doc , name , identity , framework , properties : [ ] , attributes ) ;
85162 }
86163
164+ /// <summary>
165+ /// Adds a new MSBuild item to the project file inside a new <c>ItemGroup</c>.
166+ /// When <paramref name="framework"/> is a non-empty string, a <c>Condition</c> attribute of the form
167+ /// <c>'$(TargetFramework)' == '<tfm>'</c> is added to the <c>ItemGroup</c>; pass an empty string to emit the item unconditionally.
168+ /// This overload accepts both <paramref name="attributes"/> (written as XML attributes on the item element) and
169+ /// <paramref name="properties"/> (written as child XML elements). While MSBuild evaluates both equivalently as item metadata,
170+ /// prefer the overload that only takes <paramref name="attributes"/> for new call sites — it is more concise and matches
171+ /// the SDK-style project convention of expressing metadata as attributes.
172+ /// Use this overload only when a caller must distinguish between attribute-style and element-style metadata.
173+ /// <list type="bullet">
174+ /// <item>Adding a <c>PackageReference</c> item</item>
175+ /// <item>Adding a <c>PackageVersion</c> item</item>
176+ /// <item>Adding a <c>FrameworkReference</c> item</item>
177+ /// <item>Adding a <c>NuGetAuditSuppress</c> item</item>
178+ /// <item>Adding a <c>PrunePackageReference</c> item</item>
179+ /// </list>
180+ /// </summary>
181+ /// <param name="doc">The project XML document to modify.</param>
182+ /// <param name="name">The MSBuild item type (e.g. <c>PackageReference</c>, <c>FrameworkReference</c>).</param>
183+ /// <param name="identity">The value of the <c>Include</c> attribute on the item element.</param>
184+ /// <param name="framework">
185+ /// The short TFM string used to generate a per-TFM condition on the <c>ItemGroup</c> (e.g. <c>"net8.0"</c>).
186+ /// Pass an empty string to emit the item unconditionally.
187+ /// </param>
188+ /// <param name="properties">Child XML elements to add under the item element (e.g. <c><Version>1.0.0</Version></c>).</param>
189+ /// <param name="attributes">XML attributes to add on the item element itself (e.g. <c>Version="1.0.0"</c>).</param>
87190 public static void AddItem ( XDocument doc ,
88191 string name ,
89192 string identity ,
0 commit comments