|Title:||Change nuget build targets to use 'Content' rather than 'Copy' and 'Delete'|
|Last Modified:||2015-07-06 13:30:25|
|Version Found In:||220.127.116.11|
anonymous added on 2015-05-13 02:49:08:
The 'Copy' and 'Delete' tasks for the interop file will only work for a project which is directly executed (an executable). It won't work for any projects which reference the project which references the System.Data.SQLite nuget package (such as a unit test project or a different executable). Installer projects such as WiX or VS Setup projects similarly won't find the required interop file unless it is 'Content'. Currently because of this bug I have to manually install the nuget package, adding the SQLite.Interop.dll files as content with links and removing the imported targets file you provide. It is a simple bug to fix though. The System.Data.Sqlite.Core.targets file can be simplified as follows: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Condition="'$(MSBuildThisFileDirectory)' != '' And HasTrailingSlash('$(MSBuildThisFileDirectory)')"> <SQLiteInteropFiles Include="$(MSBuildThisFileDirectory)**\SQLite.Interop.*" /> <Content Include="@(SQLiteInteropFiles)"> <Link>%(RecursiveDir)%(FileName)%(Extension)</Link> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> </Project>
mistachkin added on 2015-05-13 05:55:56:
Is there any NuGet documentation that shows examples or gives recommendations for these situations?
anonymous added on 2015-05-15 03:00:33:
I couldn't find any nuget specific documentation regarding this no. It's really just an MSBuild issue though. Using 'Copy' and 'Delete' is just copying and deleting files when that single project is built (or cleaned) but other than those actions the build system has no idea about the files. Using 'Content' means that the build system knows that there are required content files so they will also be included for all other projects which reference that project. Without this change any referencing projects will not have the interop library and will throw an exception. The only current way to solve it is to add the nuget package to every project which calls another assembly using SQLite. For example in my solution that would require adding SQLite package to a dataaccess project, two executable projects and a unit test project. If you fix this bug then it would only require the package to be added to the dataacces project.
mistachkin added on 2015-05-15 16:52:49:
I'm extremely hesitant to remove the existing build targets. However, I might be tempted to add the requested Content tags, perhaps preventing them from copying the files if they already exist.
mistachkin added on 2015-05-15 17:06:54:
If I do end up adding the Content section, you can disable the existing targets by using the following in your project file(s): <CopySQLiteInteropFiles Condition="'$(CopySQLiteInteropFiles)' == ''">false</CopySQLiteInteropFiles> <CleanSQLiteInteropFiles Condition="'$(CleanSQLiteInteropFiles)' == ''">false</CleanSQLiteInteropFiles> <CollectSQLiteInteropFiles Condition="'$(CollectSQLiteInteropFiles)' == ''">false</CollectSQLiteInteropFiles>
anonymous added on 2015-05-20 06:30:33:
Well I'm not suggesting to remove the targets file, just simplify the targets file to use a "Content" element rather than "Copy" and "Delete". I'm not sure how it would be possible to use both together or what benefit you'd gain by doing so. Just to be clear I am not saying to use the "Content" folder in the nuget package as "CopyToOutputDirectory" cannot be set without using a powershell script. I also prefer using "Link" for the content rather than copying the files to the project directory. I'll attach a modified nuget package for you to test. Works quite well for me.
mistachkin added on 2015-05-21 18:34:34:
Adding just the following to the MSBuild file causes it to recognize the interop files as "Content": <ItemGroup Condition="'$(ContentSQLiteInteropFiles)' != 'false' And '$(MSBuildThisFileDirectory)' != '' And HasTrailingSlash('$(MSBuildThisFileDirectory)')"> <Content Include="@(SQLiteInteropFiles)"> <Link>%(RecursiveDir)%(FileName)%(Extension)</Link> </Content> </ItemGroup> It should be noted that the actual file copying is still accomplished via the Copy build task; however, I think this may allow other project types to at least "see" the interop files as content. Will this work for your scenario?
anonymous added on 2015-05-22 00:32:36:
I tested the new version of the targets file you provided but it doesn't solve the issue. Referencing projects still don't have the required interop files as the `Content` files don't have `CopyToOutputDirectory` set. I really don't like the use of properties to turn on and off the content / copy / clean. It would have to be documented in a readme file when the NuGet package is installed otherwise no-one will know it's there. It just seems really hacky and unclean. Is there any particular benefit to using the `Copy` target which I'm not understanding? I really can't see any benefit at all in that approach. Seems to me it just makes things more complicated.
mistachkin added on 2015-05-22 01:48:37:
Documenting the MSBuild (and NuGet) infrastructure for System.Data.SQLite would require quite a README file, unfortunately. Meanwhile, I suppose I could add the 'CopyToOutputDirectory' attribute to the new section; however, for reasons of backward compatibility, it would have to be off by default (and the Copy/Delete tasks would have to be on by default).
mistachkin added on 2015-05-22 01:58:25:
The latest changes on the branch should work *IF* you create a file named "System.Data.SQLite.Core.targets.user" in the same directories as the MSBuild targets file, containing: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ContentSQLiteInteropFiles>true</ContentSQLiteInteropFiles> <CopySQLiteInteropFiles>false</CopySQLiteInteropFiles> <CleanSQLiteInteropFiles>false</CleanSQLiteInteropFiles> <CollectSQLiteInteropFiles>false</CollectSQLiteInteropFiles> </PropertyGroup> </Project>
anonymous added on 2015-05-22 05:12:31:
Ok that works.... but I really must say that is a terrible solution. Every time a new version is released people will have to create that targets.user file. And there are lots of people who don't checkin their nuget packages to source control. Can you please explain what you think is the backwards compatibility issue with removing the Copy and Delete targets? I've tested upgrading from the old targets file to my new targets file and there isn't a single issue. Even in solutions where there are multiple projects with the SQLite package referenced there are absolutely no problems. Oh well. Looks like I'll just have to keep modifying your nuget package myself and keep a custom local version. Disappointing.
anonymous added on 2015-05-22 06:11:06:
Amusing... I was looking at the new EF7 and saw they've added SQlite support using Microsoft.Data.Sqlite project. Downloaded the nuget package to have a look and guess what the targets file they use looks like: <Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Content Include="$(MSBuildThisFileDirectory)..\..\redist\**"> <Link>%(RecursiveDir)%(Filename)%(Extension)</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Visible>False</Visible> </Content> </ItemGroup> </Project> Now doesn't that look familiar?
mistachkin added on 2015-05-22 18:16:04:
I need more time to evaluate all the implications of making this change. I'm going to try and target this for the 18.104.22.168 release.
anonymous added on 2015-07-02 21:16:30:
I've run into a related issue when trying to use ClickOnce publishing and the SQLite.Core nuget package. Because the 2 interop DLLs are not Content within the csproj itself, they are not packaged with the rest of the application files and published. I agree with the general sentiment of this thread so far: the copy and delete should remain (and work well), but it would be very helpful if the interop DLLs showed up in the project as Content. https://msdn.microsoft.com/en-us/library/kzy0fky2(v=vs.140).aspx Thanks, Ryan
mistachkin added on 2015-07-02 22:12:18:
Thanks for the input. I'll look further into it.
mistachkin added on 2015-07-02 22:19:38:
Have you tried setting the ContentSQLiteInteropFiles MSBuild property to true?
anonymous added on 2015-07-06 13:30:25:
Thanks mistachkin, this appears like it will work perfectly. The 2 interop files now show up under the Application Files in ClickOnce, but not as separate files in the project. I'll test this all the way through, but all indications are good ... sorry I didn't see that bool the first time I read through this issue.