With VisualStudio 2017, Microsoft is moving to embrace the NuGet packaging system and there are very useful utilities in there for Unity developers such as StyleCop and hundreds of others.
Unfortunately Unity is stripping this data out of the CSPROJ file when it updates the project, so despite the NuGet package still technically being installed in the Solution, it no longer functions.
Here is an example of the changes in Unified Patch format:
@@ -624,13 +622,7 @@
Ok I finally managed to hack my way around this issue using the code below. This is obviously a very brittle fix, as it will only work for StyleCop specifically and only this version specifically. If StyleCop gets updated I will need to change the code.
I strongly urge Unity Tech to consider better handling these as the usage of NuGet is only going to become more and more prevalent moving forward.
For anyone needing to work around this issue for now, see the code below and adjust as needed. A couple of things I learned doing this (besides how painful working with xml is):
Every element added needs an explicit namespace that matches the root document. If it doesn’t then it will automatically get an xmlns=“” attribute added which will break Visual Studio.
For a long while I thought my changes weren’t having any effect. Closing Visual Studio, and deleting the sln and csproj files forced Unity to do a full rebuild and that fixed it.
using System;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using UnityEngine;
using UnityEditor;
using SyntaxTree.VisualStudio.Unity.Bridge;
[InitializeOnLoad]
public class ProjectFileHook
{
// necessary for XLinq to save the xml project file in utf8
class Utf8StringWriter : StringWriter
{
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
static ProjectFileHook()
{
ProjectFilesGenerator.ProjectFileGeneration += (string name, string content) =>
{
// parse the document and make some changes
var document = XDocument.Parse(content);
//document.Root.Add(new XComment("FIX ME"));
XNamespace xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";
XElement itemGroup = new XElement(xmlns + "ItemGroup");
itemGroup.Add(new XElement(xmlns + "Analyzer", new XAttribute("Include", "packages\\StyleCop.Analyzers.1.0.0\\analyzers\\dotnet\\cs\\Newtonsoft.Json.dll")));
itemGroup.Add(new XElement(xmlns + "Analyzer", new XAttribute("Include", "packages\\StyleCop.Analyzers.1.0.0\\analyzers\\dotnet\\cs\\StyleCop.Analyzers.CodeFixes.dll")));
itemGroup.Add(new XElement(xmlns + "Analyzer", new XAttribute("Include", "packages\\StyleCop.Analyzers.1.0.0\\analyzers\\dotnet\\cs\\StyleCop.Analyzers.dll")));
document.Root.Add(itemGroup);
// save the changes using the Utf8StringWriter
var str = new Utf8StringWriter();
document.Save(str);
return str.ToString();
};
}
}
Updated version of the script for StyleCop.Analyzers 1.0.2, as well as a few improvements:
Adds the stylecop.json config file to the projects
Wraps everything in a platform specific #if block so it won’t cause issues if opened on say a Mac
#if UNITY_EDITOR_WIN
using System.IO;
using System.Text;
using System.Xml.Linq;
using SyntaxTree.VisualStudio.Unity.Bridge;
using UnityEditor;
/// <summary>
/// Provide a hook into Unity's Project File Generation so that StyleCop gets re-added each time
/// </summary>
[InitializeOnLoad]
public class ProjectFileHook
{
static ProjectFileHook()
{
ProjectFilesGenerator.ProjectFileGeneration += (string name, string content) =>
{
// parse the document and make some changes
var document = XDocument.Parse(content);
XNamespace xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";
XElement itemGroup = new XElement(xmlns + "ItemGroup");
itemGroup.Add(new XElement(xmlns + "Analyzer", new XAttribute("Include", "packages\\StyleCop.Analyzers.1.0.2\\analyzers\\dotnet\\cs\\StyleCop.Analyzers.CodeFixes.dll")));
itemGroup.Add(new XElement(xmlns + "Analyzer", new XAttribute("Include", "packages\\StyleCop.Analyzers.1.0.2\\analyzers\\dotnet\\cs\\StyleCop.Analyzers.dll")));
document.Root.Add(itemGroup);
document.Root.Add(new XElement(xmlns + "ItemGroup", new XElement(xmlns + "AdditionalFiles", new XAttribute("Include", "stylecop.json"))));
// save the changes using the Utf8StringWriter
var str = new Utf8StringWriter();
document.Save(str);
return str.ToString();
};
}
// necessary for XLinq to save the xml project file in utf8
private class Utf8StringWriter : StringWriter
{
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
}
#endif
I tried using this to fix this problem, but it just led to a duplicate Systeml.Xml.XmlDocument definition. Do I have to seperate my VS Solution from Unity in order to get around this?