sdk: Moving Dependencies to csproj is a bad idea
I’ve seen this blog entry (https://blogs.msdn.microsoft.com/dotnet/2016/10/19/net-core-tooling-in-visual-studio-15) that details moving the dependencies to the XML inside of csproj and I think this is a really bad idea. I am for moving most of what is inside project.json to csproj, but the great experience of editing the project.json for dependencies is going to slow people down, even if you do support intellisense. It’s just going to push people to use the PowerShell extensions or the VS Nuget UI both of which are a big step back.
This means we’re going from the simple and sublime:
"Microsoft.AspNetCore.Mvc": "1.0.0"
to:
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.0" />
This is even a step back from the XML file from prior versions since the csproj has to be reloaded to make these changes. Please reconsider this.
My suggestion is to keep the dependencies as a nuget.json or packages.json instead.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 57
- Comments: 29 (15 by maintainers)
Personally, I’m happy to see NuGet finally become a first-class citizen in the .NET project/build system. The real issue is that MSBuild needs to support additional file formats besides just XML…
For the record, it is possible (just tried it out) to move all package references to a separate file. Not sure how tooling is going to like that when managing references via UI but it restores/builds/runs just fine like this:
packages.props
:TestProject.csproj
:Sorry folks, we have no intention of moving back to project.json. PackageReference is here is to stay.
For those using the new bits, having
<PackageReference/>
as items is quite powerful. Here’s a few of the things you can do with them:Share package references across a solution Condition them Unify package versions across a solution
The csproj file editing wouldn’t be bad if two things happened:
May be spam but let me just dump my thoughts on this here. Background: When the news broke on moving away from project.json (april/may?), i was devastated. Loved that thing and somehow still do. Now to the “yes, but” arguments that i have run into:
Language / Format
Language and format preferences are highly subjective. There are many reasons to favour YAML, JSON, XML, F#/C# build scripts, Package.swift ore something completely different for various scenarios. It doesn’t really matter and there are many up- and downsides for each approach (e.g. i had a few merge conflicts in
project.json
files just with comma needed when adding a new line to a json object). I don’t think there can ever be a logical / deterministic decision on this.Fixed descriptive schema vs Extensibility
Build frameworks usually fall somewhere between “we define what you can choose from” and “we give you some tools to build your own”. Project.json is definitely more the first one. It has some capabilities and ways you can configure it. It’s only extension points are script invocations. While that is ok for a lot of tasks, it has two major drawbacks: It relies on the shell of the platform so you need to work with the minimum intersection of cmd/bash/zsh/etc and you have no integration with the build itself while running the commands - you have no access to the build system’s model and can’t communicate back to it other than a success/failure state via exit code. Frameworks like gulp or grunt on the other hand let you run your own code to set up the build pipeline and inject custom actions on the way. Want to analyse all JS objects, parse the parameter names of all constructor functions out and append DI metadata to the build output so minifying won’t kill you? no problem. just insert a step where appropriate. Project.json can’t do stuff like that. But MSBuild can. I can easily write before-build targets that can emit
<Compile Include="obj/$(Configuration)/AutoGeneratedAwesomeness.cs" />
elements. Or embedded resources, simple files to put next to the output or whatever else i can think of to scare my coworkers. See CoreCLR/CoreFx: they have logic to decide between includingFoo.Windows.cs
andFoo.Unix.cs
based on custom build arguments. The interesting part is that i can get extensions via NuGet now. Just likeMicrosoft.NET.Sdk
is just a NuGet with*.targets
and*.props
files, i can just as easily make my own or consume 3rd party packages to get awesome build and deployment targets. Some have complained about missing publish-to-azure / webdeploy functionality in thedotnet
CLI. such features could easily be brought in via NuGet. Also, the VS docker integration just adds targets and props files to your project and adds them to your solution. Some of that could also be moved to a NuGet. My best example for this is the current CoreRT integration. It basically is “add this line to your csproj and then calldotnet build3 /t:LinkNative
”. Previously, the CLI had to know how CoreRT works and implement the necessary logic fordotnet build --native
.Convergence of build system and package management
NuGet and MSBuild haven’t had much integration until now. It worked somehow if you build with
devenv
thanks to NuGet’s vsix package. If you built project.json based things with it, you have probably run intorestore.dg
. This temporary file is a manifestation of all the problems a separated package / build system can have. I don’t fully understand the internals and i don’t really care. I want things to just work. For JS, there are npm and bower. Both specific to what you want to do with either the library you’re pulling or the code you’re writing. Can be a bit of a mess when you are new to web / node development. For Java development, people mostly use maven or gradle. Both have a deep understanding of and integration with package management. It is fairly easy to add a dependency and have it build. How does that work with NuGet and csproj? If you install a NuGet package in thepackages.config
world, it’s a mess. NuGet will add the package you need to yourpackages.config
, install the dll-references / targets / custom stuff into the csproj. If packages use a custom install script, it may be impossible to completely uninstall a packet. The migration guide for packages.config to project.json has just too many manual steps including editing your csproj files. At build time / CI server, you then need to figure out how to actually restore the packages. Turns out the best way is to have anuget.exe
somewhere and point it to the packages.config files or the solution file. MSBuild itself can’t do “restore on build”, that’s again a VS feature you’d have to use viadevenv.exe
somehow (tell me if i’m wrong on this!). In the new world (current CI builds of the dotnet cli), msbuild does everything.dotnet restore
has the same effect asdotnet msbuild /t:Restore
. It just translates the arguments. So, if NuGet packages are a primary development tool and the build pipeline shall handle it, it makes sense to merge the files and not have NuGet edit the other.Integration into existing MSBuild infrastructure
Building large project is a pain in the a*, independent of the languages / tools used. Setting up complex msbuild “solutions” isn’t easy but if you have that running, it’s awesome. And most of the infrastructure in .NET is msbuild-based. If I want to build an installer for a windows app, i create a
.wixproj
project. That references a csproj as<ProjectReference>
, allowing me to use the output information for that project that MSBuild provides to create an installer configuration. If any new project type comes out i can add it too, as long as it is msbuild-based. I can’t reference aproject.json
out of a.wixproj
. Btw, how do you currently build a project containing 20 project.json-based projects? Either calldotnet build
20 times or have an msbuild solution that includes all 20.xproj
files. That will also get better if it’s just a csproj and the dotnet cli is able to build.sln
files.Improvements to existing projects
At our company, we moved some libraries and application to project.json just to get the integrated NuGet pack support and transitive package references. Much easier that maintaining
.nuspec
files. That is one example of features that all C# solutions instantly get with the move from project.json to msbuild.Future possibilities
While csproj files are getting a lot better with all the recent updates (more defaults, less clutter), there are still additional options that have been suggested to “make msbuild great again”:
*proj
file as XML and JSON, use whichever succeeds).XML versus JSON is a personal preference, it’s not a flaw in the design of anything.
I personally like both approaches, they are both compact and get the job done.
Liking is valanced familiarity. XML has gotten a bad wrap and thus we’re projecting that negative perception of XML onto this being a “bad” way to reference packages. If you give it a chance and think about the benefits (that this accomplishes the same thing and is still compact) - you can learn to like either approach.
Neither format is “better” - JSON for example doesn’t support commenting, and instead of angle bracket soup, it’s curly bracket soup.
In either approach I’m happy that we:
These are marked improvements, so kudos and thank you to the developers behind all of this, you’ve truly eliminated things that are a PITA.
@llehn I was intrigued by your question and blogged this post.
@TheOnlyRealTodd
The old project.json could be used on Windows, Linux and Mac. The new MSBuild-based csproj will be usable on Windows, Linux and Mac. I don’t see how does that make the old format any more cross-platform than the new one.
Don’t know/don’t care. Syntax is irrelevant to me too.
With upcoming
dotnet ref [add/rem]
command (#4521), the general experience of dealing with references (and not needing to edit the csprojs) would be improved IMO.A related thread is here dotnet/roslyn-project-system#639 (ability to add reference from nested directory via glob).
Typing a version number in an XML file is no more a “bad idea” than typing a version number in a JSON file. There is no significant difference, and the semantics of how to use this functionality in a text editor or VS2017 are identical to how you use project.json in a text editor or VS2015.
@shawnwildermuth In the meantime, open up the Environment > Keyboard settings and create a shortcut key to Project.EditProjectFile (i used CTRL + SHIFT + E, CTRL + SHIFT + P). Then just select the project file and use your shortkey.