Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contentFiles (cs, compile) not working in NetStandard projects. #4803

Closed
damianh opened this issue Mar 14, 2017 · 31 comments
Closed

contentFiles (cs, compile) not working in NetStandard projects. #4803

damianh opened this issue Mar 14, 2017 · 31 comments
Labels
Resolution:External This issue appears to be External to nuget

Comments

@damianh
Copy link

damianh commented Mar 14, 2017

Hi, I run LibLog - a source code logging package for library developers. I am failing to achieve NetStandard support ( damianh/LibLog#125 )

I was unsure whether to log issue here or dotnet/sdk. I'm following https://twitter.com/davkean/status/841619178050150405 advice.

Details about Problem

NuGet product used (NuGet.exe | VS UI | Package Manager Console | dotnet.exe): Package Manager Console

NuGet version (x.x.x.xxx): 4.0.0

dotnet.exe --version (if appropriate):

VS version (if appropriate): 2017

OS version (i.e. win10 v1607 (14393.321)): 10.0.14393 Build 14393

Detailed repro steps so we can see the same problem

  1. Checkout this branch https://github.com/damianh/LibLog/tree/loqu8-netstandard
  2. To build a nuget package, run .\build.ps1. This will put a package in build directory
  3. Open the solution src\ContentFilesTest\ContentFilesTest.sln in VS2017. You will see two projects that don't compile where we will install LibLog.
  4. In Package Manager Console, select the project DotNetFramework46 and install LibLog: install-package LibLog -prelease -source ../../build/ . LibLog should be installed into the project DotNetFramework46, visible in folder App_Packages\... and that project should now compile.
  5. In Package Manager Console, select the project DotNetStandard and install LibLog: install-package LibLog -prelease -source ../../build/. The project DotNetStandard continues to not compile and the type LogProvider cannot be resolved.

Other suggested things

There is more information in the comments in the related issue damianh/LibLog#125 , including the fact that no transformed file is written to obj\Debug\...

Verbose Logs

damianh/LibLog#125 (comment)

Sample Project

Let me know if you want a zip of the project instead of checking out the branch.

@emgarten
Copy link
Member

Packages.config projects use the content folder
Project.json/PackageReference/NETCore SDK projects use the contentFiles folder

In your steps the DotNetFramework46 project ends up being a packages.config project which does not use the contentFiles folder where your pp file is.

To allow your package to work in both types of projects you should put the pp file in both places.

The reason for this is that older packages.config projects require Visual Studio to install packages, and items from the content folder are actually copied into the project itself at install time. With project.json/PackageReference packages can change at restore time so the contentFiles folder is used which only contains immutable files.

@damianh
Copy link
Author

damianh commented Mar 16, 2017

Thanks or the response @emgarten , however I'm not grokking what I should actually do.

To allow your package to work in both types of projects you should put the pp file in both places.

It is as far as I can see... if not what changes are need to https://github.com/damianh/LibLog/pull/125/files#diff-6ec70a9e9835da1a3387257b2d950192R36 to make this work?

Cheers.

@tofutim
Copy link

tofutim commented Mar 16, 2017

Loqu8.LibLog.4.2.9.nupkg.zip

Try this

@damianh
Copy link
Author

damianh commented Mar 16, 2017

@tofutim I'll respond on damianh/LibLog#125

@emgarten
Copy link
Member

@damianh you need to have the files under both content and contentFiles.

@damianh
Copy link
Author

damianh commented Mar 17, 2017

@emgarten Like this?

<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
    <metadata minClientVersion="3.3.0">
        <...>
        <dependencies>
            <group targetFramework=".NetStandard1.1">
                <dependency id="Microsoft.CSharp" version="[4.0.1, )" />
                <dependency id="System.Dynamic.Runtime" version="[4.0.11, )" />
            </group>
        </dependencies>
        <contentFiles>
            <files include="contentFiles\cs\**\*.*" buildAction="Compile" />
        </contentFiles>
    </metadata>
    <files>
        <file src="LibLog.cs.pp" target="content\App_Packages\LibLog.4.2\LibLog.cs.pp" />
        <file src="LibLog.cs.pp" target="contentFiles\App_Packages\LibLog.4.2\LibLog.cs.pp" />
    </files>
</package>

@damianh
Copy link
Author

damianh commented Mar 17, 2017

you need to have the files under both content and contentFiles.

Unfortunately this statement is confusing me:

  • There is a <contentFiles> tag, do you mean that?
  • There is a contentFiles\ path in the <files> element under <contentFiles>, do yo meant that?

Honestly a working nuspec would be much easier to move forward on.

@damianh
Copy link
Author

damianh commented Mar 17, 2017

    <files>
      <file src="LibLog.cs.pp" target="content\App_Packages\LibLog.4.2\LibLog.cs.pp" />
      <file src="LibLog.cs.pp" target="contentFiles\App_Packages\LibLog.4.2\LibLog.cs.pp" />
    </files>

... did not work.

@emgarten
Copy link
Member

Files at the root of contentFiles are not picked up. You need to have:

<files>
      <file src="LibLog.cs.pp" target="content\App_Packages\LibLog.4.2\LibLog.cs.pp" />
      <file src="LibLog.cs.pp" target="contentFiles\cs\any\App_Packages\LibLog.4.2\LibLog.cs.pp" />
    </files>

Your nuspec contentFiles section has contentFiles\cs\** which doesn't match contentFiles\App_Packages where you are putting the file.

damianh added a commit to damianh/LibLog that referenced this issue Mar 18, 2017
@damianh
Copy link
Author

damianh commented Mar 18, 2017

Applied your suggest (please correct if wrong). Doesn't appear to work.

    ....
        <contentFiles>
            <files include="contentFiles\App_Packages\**\*.*" buildAction="Compile" />
        </contentFiles>
    </metadata>
    <files>
      <file src="LibLog.cs.pp" target="content\App_Packages\LibLog.4.2\LibLog.cs.pp" />
      <file src="LibLog.cs.pp" target="contentFiles\cs\any\App_Packages\LibLog.4.2\LibLog.cs.pp" />
    </files>

image

@emgarten
Copy link
Member

@damianh
Copy link
Author

damianh commented Mar 19, 2017

@emgarten Thank you very much for that package! However, I've been testing it and there seems to be a number of issues. I hope the problem is me :(

1. Installing the package doesn't show the content files as part of the project:

image

Closing and re-opening the solution subsequently shows the content files:

image

2. The files ExampleInternals.cs and ExampleReader.cs.pp are nowhere to be seen and their types are not resolvable:

image

3. uninstall-package doesn't remove the added files:

image

Closing and re-opening the solution subsequently shows the files removed.

@emgarten
Copy link
Member

emgarten commented Mar 19, 2017

Thanks for the details @damianh

@natidea has anything changed with .pp files? I tried also and didn't see them getting generated in VS 2017 RTM but I do see them in project.assets.json.

Related: dotnet/sdk#70

The delay in adding/removing the files from Solution Explorer looks like a VS issue, I see them written out correctly to the obj props file.

@bmeredith
Copy link

I was also able to reproduce the same issues @damianh mentioned above when trying to use the ContentFilesExample package.

@damianh
Copy link
Author

damianh commented Mar 20, 2017

I am relieved that it has been repro'd. Thanks guys.

@damianh
Copy link
Author

damianh commented Mar 26, 2017

@emgarten @natidea Gents, any update or thoughts on this? It appears that source transforms are completely broken. LiteGuard is another project that is affected. cc @adamralph

@adamralph
Copy link

adamralph commented Mar 26, 2017

LiteGuard, due to it's simplicity, is also a great test-bed for new/changed tooling. I've used it personally as my "hello world" for learning about PCL's, multi-targetting, project.json, etc. etc., with the benefit that it's also a real package, with real users. I'd be more than happy to use LiteGuard to help smoke test any work that comes out of this issue, from a package producer POV, .

@blackcity
Copy link

blackcity commented Mar 29, 2017

Come on NuGet guy's. This problem has been reported at least one year ago. ContentFiles did not work in project.json and also do not work in the new csproj based projects. We need at least a way to copy additional assets to the project. This can't be too hard.

@emgarten
Copy link
Member

@blackcity this issue is currently narrowed down to .pp files not being transformed for NETCore projects. If you are unable to get contentFiles to work at all then you may have a package that is authored incorrectly. Would you own a new issue explaining the issues you are currently seeing along with repro steps and a copy of the package that doesn't work?

@blackcity
Copy link

blackcity commented Mar 29, 2017

It is exactly like described in this post:
#4803 (comment)

  1. Cannot see the files/folders in Solution Explorer after the package has been installed.
  2. Closing and reopening the solution shows files/folders (folders with a red cross) but
  3. Files/folders are not physically copied to the solution (only referenced?)
  4. Uninstalling leaves orphaned entries wich results in errors.

For our packages it is important that the content files (assets) are copied to the solution, not just referenced. With the package we need to copy config files (XML files) the developer wants to change. This was standard in the packages.config era.

We cannot publish a package with this strange behaviour without our customers killing us.

Btw: Just tested again with ASP.NET Core Project (.NetCoreApp1.1) and the package mentioned above: https://www.nuget.org/packages/ContentFilesExample/

@emgarten
Copy link
Member

For our packages it is important that the content files (assets) are copied to the solution, not just referenced. With the package we need to copy config files (XML files) the developer wants to change. This was standard in the packages.config era.

This is not supported with project.json/PackageReference. With packages.config users had to run install and uninstall commands explicitly and this was done through Visual Studio.

With project.json/PackageReference packages can float which allows them to change from restore to restore without an explicit install/uninstall action being performed. For this reason the contentFiles folder is immutable and cannot carry a state like the packages.config content folder.

The plan going forward for this is to allow users to move files from under the contentFiles folder into their project through a gesture in Visual Studio. Currently the include of these files is written out to the auto generated nuget props file in the obj folder which allows them to be removed or overridden.

My suggestion for copying config XML files to the user project is to handle this in an init.ps1 script, or possibly in a .targets file.

@blackcity
Copy link

blackcity commented Mar 29, 2017

Thanks @emgarten for this detailed answer. So init.ps1 and and targets work in ASP.NET Core projects (csproj)?
Currently it is a bit confusing because of the lack of docs. But I'll try it out.

@emgarten
Copy link
Member

init.ps1 and and targets work in ASP.NET Core projects (csproj)?

Yes, if installed using Visual Studio init.ps1 will be executed. This works on all types of projects. The script will also run when opening the solution if the nuget powershell console is open.

If someone manually edits the csproj outside of Visual Studio and restores then it will not run, but you could catch this scenario in a targets file where the config is missing and fail the build with a helpful message.

@natidea
Copy link

natidea commented Mar 30, 2017

Sorry just getting to this after my vacation. I took a look at the pp file transformation issue and found a couple of things:

    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Now I can use the Guard.

So somewhere along the way, some concepts may have been crossed. We default CopyLocalLockFileAssemblies to true in that target file, but it gets set to false in Microsoft.NET.Sdk.BeforeCommon.targets#L57. Perhaps the real issue is that the produce content assets task is tied to ResolveLockFileCopyLocalProjectDeps and should instead be triggered in some other way.

Adding @livarcocc and @dsplaisted from SDK who would need to resolve this.

@emgarten
Copy link
Member

I should have mentioned, I had to modify ContentFilesExample locally to add the netstandard TFM, this package was originally created for a UWP tutorial. I'll take a look at updating it on nuget.org soon.

@blackcity
Copy link

@emgarten This seems to work now. We are using init.ps1, build props and targets.
Last question: We have a NuGet package with 3 TFM (net45, net461, netstandard1.6):

lib
   net45
       library.dll    // for traditional Framework
   net461
       library.dll    // for ASP.NET Core (full Framework)
   netstandard1.6
       library.dll    // for ASP.NET Core

The net461 library can only run in ASP.NET Core projects (the full Framework). Is there any way to prevent traditional projects from referencing the net461 TFM and instead reference the net45 assembly?

@emgarten
Copy link
Member

Is there any way to prevent traditional projects from referencing the net461 TFM and instead reference the net45 assembly?

NuGet will take the highest compatible asset. If the project is net462 for example it will take net461. If the project is net46 it will use net45 since net461 is not compatible. If you use a targets file in the package instead of the lib folder you can select the dll based on other project properties instead.

@blackcity
Copy link

Great answer thanks. Really last question: What if the project is net462 and the NuGet package provides TFM for netstandard1.5 and net461. Does the project choose the netstandard1.5 library because it is the highest compatible TFM or does it choose net461 because it is more specific.
In your tests we added a netstandard1.4 TFM as replacement for net461, but the project choosed the net45 assembly which isn't compatible with ASP.NET Core.

@emgarten
Copy link
Member

If the project is net* then a compatible net* from the package will be used. If there are no compatible matches then it will fallback to netstandard. It is debatable which should be used, but NuGet currently favors keeping the same framework as the project.

@blackcity
Copy link

blackcity commented Apr 1, 2017

@emgarten Thanks for your fantastic support.

Two suggestions.

  1. Please provide docs! NuGet is essential for .NET/.NET Core development. Imagine how many developers struggle when it comes to more advanced things like content files, install scripts, build props and targets. There is almost no documentation out there. We have to read through blogs, outdated docs or ask you guys stupid questions. What a waste of time! Our time and your time. We need maybe 20 pages of in-depth coverage. That's all. Buy me a beer and I'll do it for you.
  2. Add a TFM for libraries that can only be executed in .NET Core over full Framework environments. In the past you had these TFMs like dnx* or netcore*. If we have a library that can only run on .NET Core over full Framework we cannot just put it in a lib/net* folder because it could be imported into traditional projects. Why not just reactivate netcore* (preferred) or maybe add an attribute like this?
     <dependencies>
       <group targetFramework=".NETFramework4.6" netcore="true"> 
         <dependency id="SomeLibrary" version="1.0.0" /> 
       </group> 
     </dependencies> 

@emgarten
Copy link
Member

emgarten commented Apr 7, 2017

Moving this to dotnet/sdk#1100

The issue here appears to be in the SDK. I see the correct outputs from NuGet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution:External This issue appears to be External to nuget
Projects
None yet
Development

No branches or pull requests

7 participants