Skip to content
This repository has been archived by the owner on Nov 20, 2018. It is now read-only.

Determine value of MSBuildProjectExtensionsPath #244

Closed
natemcmaster opened this issue Dec 7, 2016 · 15 comments
Closed

Determine value of MSBuildProjectExtensionsPath #244

natemcmaster opened this issue Dec 7, 2016 · 15 comments

Comments

@natemcmaster
Copy link
Contributor

natemcmaster commented Dec 7, 2016

dotnet-watch and dotnet-user-secrets assume MSBuildProjectExtensionsPath is the default value is obj\, but users can change this by moving their intermediate path. We should attempt to discover its actual value. This path is required to be correct in order to find and import generated targets files.

cref #243 (comment)

See https://github.com/Microsoft/msbuild/blob/052ad30f8f706a87e9fa9431fda1ec9c0b73893b/src/XMakeTasks/Microsoft.Common.targets#L127

Workarounds

  1. Users can manually import the generated targets from their csproj.
<Import Project="obj\$(MSBuildProjectFile).dotnetwatch.g.targets" Condition="Exists('obj\$(MSBuildProjectFile).dotnetwatch.g.targets')" />
  1. Pass in the path explicitly so the targets are generated in a different folder. (requires 2.0.0 preview2 or newer)
    ⚠️ Caution: this has been removed in 2.1.0, and was only added as an experimental, unsupported workaround.
dotnet watch --msbuildprojectextensionspath build/obj run
@natemcmaster
Copy link
Contributor Author

Might be possible if CLI were to implement this feature: https://github.com/dotnet/cli/issues/5300. Otherwise, I'm not quite sure how we implement this correctly without opening ourselves to all the problems of using MSBuild API directly.

@muratg
Copy link

muratg commented Mar 8, 2017

Depends on dotnet/cli#5300.

@muratg muratg added this to the Backlog milestone Mar 8, 2017
natemcmaster pushed a commit that referenced this issue Jun 2, 2017
In the event someone wants to move the obj/ folder, MSBuild will not be able to locate dotnet-watch's generated targets. dotnet-watch cannot automatically find the obj folder (#244), so this command line switch allows users to point dotnet-watch to the right location.
natemcmaster pushed a commit that referenced this issue Jun 2, 2017
In the event someone wants to move the obj/ folder, MSBuild will not be able to locate dotnet-watch's generated targets. dotnet-watch cannot automatically find the obj folder (#244), so this command line switch allows users to point dotnet-watch to the right location.
@natemcmaster
Copy link
Contributor Author

Another workaround idea: we could write the dotnet-watch targets to MSBuildUserExtensionsPath instead of MSBuildProjectExtensionsPath.

@natemcmaster
Copy link
Contributor Author

Another idea: when calling any project, we override CustomBeforeMicrosoftCommonTargets and CustomBeforeMicrosoftCommonCrossTargetingTargets to the location of the path containing dotnet-watch's targets.

@hartmannr76
Copy link

Is it not possible for watch to evaluate a csproj to determine what the properties are going to be? (i.e. programmatically figure out something like BaseIntermediateOutputPath). Using Microsoft.Build.Evaluation and Microsoft.Build.Construction seem like they could get us that? Deferring to you to see if you've tried this route before but I have seen it in another project

@natemcmaster
Copy link
Contributor Author

Is it not possible for watch to evaluate a csproj to determine what the properties are going to be?

@hartmannr76 this was actually the first way we attempted to implement dotnet-watch. It turned out to be very fragile due to dotnet/msbuild#1097. There is no global installation of MSBuild. dotnet-watch would need to bundle a complete copy of MSBuild (as Omnisharp and VS Code do). Without this, project evaluation will fail anytime a user's project references something our bundled copy of MSBuild is missing. This could be almost anything: docker SDKs, new versions of bundled assemblies (NuGet, MSBuild, BCL, JSON.NET), new targets, etc. It's a huge problem with the way MSBuild APIs are designed.

@hartmannr76
Copy link

hartmannr76 commented Aug 28, 2017

Thats a bummer... Is there any way to do this without injecting that targets file? (I'm fairly new to the MSBuild props/targets stuff so am still trying to connect the dots on the necessity of it for certain things). I'm guessing its to support the Watch property functionality?

@natemcmaster
Copy link
Contributor Author

Is there any way to do this without injecting that targets file?

This is the only reliable solution we've found. Our current method of injecting the target causes issues when anyone changes BaseIntermediateOutputPath (a pretty setting to change), so I'm hoping to try other ways of injecting the target that are less fragile.

@ricky-hartmann-zocdoc
Copy link

ricky-hartmann-zocdoc commented Sep 7, 2017

Understood, but why hook into the msbuild process instead of specifying a config file? A common theme in the JS community is:

  1. Passing in a config file
    dotnet watch --config ./.watch.json run
  2. Placing a file at the root
- Foo.csproj
- .watch
- Program.cs

And it is transparently picked up at runtime.

Personally, I prefer the former because I feel the later is way too elusive; but this gives you the ability to specify what is included/excluded as well as some other items you may want configured that would normally be added into a project file, without coupling this to the msbuild process. In thinking about using/installing this tool at the global level like you specified with dotnet-web, I feel like this makes more sense.

Thoughts?

@natemcmaster
Copy link
Contributor Author

Understood, but why hook into the msbuild process instead of specifying a config file?

@ricky-hartmann-zocdoc a separate configuration file was considered early on in the design process (see #204), but we decided to use the MSBuild file as the source of truth on which files should be watched. The benefit was that that users don't need to yet-another-json-file, and didn't have to manually keep two files in sync (the csproj file and a json file). We found that most users are satisfied with the default list of files given to us from MSBuild. We enabled MSBuild settings to change these defaults, but so far I haven't seen anyone use them. That could be because the settings are an undiscoverable feature, or because the default is good enough. Hard to know.

@asfernandes
Copy link

I tried both workarounds and have this error for many attributes:

error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute
...

@natemcmaster
Copy link
Contributor Author

@asfernandes this error appears to be unrelated to this issue. Can you open a separate bug and include repro steps?

@asfernandes
Copy link

Yes, but meanwhile, I'm just starting with dotnet core 2 and want to use watch inside docker at the same time leaving vscode working outside docker. Is there a more direct way to do it or I'm going in the correct path?

My problem is that tools (inside / outside docker) writes absolute paths in files placed in obj.

@natemcmaster
Copy link
Contributor Author

@asfernandes not trying to be mean, but the scope of your question is beyond what this thread is about. Please open a new issue and tag me. Also, StackOverflow is a good place for these kinds of questions. I'd be happy to explain how to setup dotnet-watch + docker.

@czifro
Copy link

czifro commented Oct 10, 2017

Was this moved to a new thread? or SO? If so, could someone share a link, please?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants