.NET Core build with dll reference - c#

I am trying to get .NET core to work with the build system at my work, which had been designed with Java in mind. But it is sadly so integrated into our pipelines that there is no way we can be without it. So if I want to use .NET at work will it have to be with this build system.
Each project is built into a package, with their own git repository.
Given a program like below where MyConsoleApp has a dependency on MyLibrary.
MyProgram-Solution
- MyConsoleApp
- MyLibrary
At build time the source code would be placed in
/build/packages/MyConsoleApp/
/build/packages/MyLibrary/
However I can only build one at the time, and I cannot move the source code.
Which means that I would need to build MyLibrary first, with the DLL ending up in
/build/packages/MyLibrary/out/MyLibrary.1.0.dll
When I then build MyConsoleApp, I need a way to tell the .NET Core build tool that the MyLibrary.1.0.dll file can be found at
/build/packages/MyLibrary/out/MyLibrary.1.0.dll
Storing packages in Nuget is not an option, as the package may not be ready for release at the build time, and the build system works in a sandbox mode, meaning it has no external connections.
I can edit the MyConsoleApp.csproj if that makes it possible.

You can add assembly references using Visual Studio, same as with .NET Framework projects.
If you want to modify the project file by hand, you'll need something like the following:
<ItemGroup>
<Reference Include="MyLibrary">
<HintPath>..\..\..\MyLibrary\out\MyLibrary.1.0.dll</HintPath>
</Reference>
</ItemGroup>

Related

Where to put the DLL in C# source?

I just built https://snowballstem.org 's C# port.
It makes a dll I can reference in my project
<ItemGroup>
<Reference Include="Snowball">
<HintPath>..\..\..\snowballstemmer.dll</HintPath>
</Reference>
</ItemGroup>
What's the best place to put that (and other such) dll so that my codebase remains well-structured and portable and other developers can join in development very easily after cloning it?
As mentioned in the comment by mason, for .NET project it recommended to references to NuGet packages. However if you, for some reason, need / like to keep the libraries you use in a repository, you can use a file structure like this:
1 YourSolutionName
1.1 src // sources
1.1.1 project 1
etc.
1.2 libs // libraries / dlls you reference
1.2.1 library1
etc.
1.3 docs // documentation
etc.
It is true, we really don't want to have dll references in our code repo, if possible. However, if the target project does not have a NuGet package then it's not really possible.
Assuming you have a project folder and a solution file outside of it, I would create another folder, called something like ThirdPartyDlls and chuck in there. You can then add a reference to it in your project, making sure you use a relative path to it. This can be changed in the project file if necessary.
If you use Git for your source control, you can force push dlls.
Now, I am not a fan of this method, but sometimes you just don't have an option.

Use local source code of NuGet package to debug and edit code

I have a solution with an application project (ASP.NET Core) and multiple library projects. I want to separate some of the library projects into a separate solution and turn them into NuGet packages.
With the libraries in the same solution I could of course simply edit something in a library, run the application and see how it works (and debug, if necessary).
However, when I turn the libraries into a NuGet package, the application references the packages from our private NuGet feed instead of the project file.
My question is: is it possible to locally "override" the package reference and use the local source code instead? That way I could still edit the libraries and see the effects in the application. This is a lot easier than having to publish a new package for every small change (especially when trying to fix an issue or implementing a new feature).
DNT (Dot Net Tools) does this. You can specify which packages to switch and where they are.
See the 'switch-to-packages' and 'switch-to-projects' command line switches.
Its a bit fiddley as (when I last tried) you had to create a config file that holds the mapping, and it seems to be easy to break the switching. But its something.
https://github.com/RicoSuter/DNT
I've not tried it, but maybe you can use it to switch to packages on a commit for the build server to work correctly? (Or to ensure the references are correct in source control?)
If you want to use nuget in your project and debug, even modify the source files of the nuget packages, this is not a good choice because you should build the nuget project(generate the new changed dll) and repack it as a nuget package, then reinstall, to enable the changes. It is too complex.
Once you install the nuget, no matter how many changes you make, it’s useless. The nuget installed at this time is the version you made before any changes. No matter how you change it, it is the previous version. The version stays at that timestamp, unless you repackage the project. Generate nupkg and update the nuget version.
So nuget is not a good choice for your situation, you should use ProjectReference.
Directly use the ProjectReference to reference two source projects, build at the same time, and get the changed parts at the same time.
ProjectReference could cross two different solutions.
Add this on the main project:
<ItemGroup>
<!--add any nuget project'csproj file like this to debug its source code-->
<ProjectReference Include="..\xxx\xxx.csproj">
</ProjectReference>
</ItemGroup>
If the proejct is out of the solution, you could directly use the full path of the nuget project's csproj to connect it.
I'm not sure what you mean by "override" but you can always add the library project to your ASP.NET Core solution and reference it like normal project references. A project referenced within a solution doesn't have to be physically placed in the same folder as the solution itself.
This, however, does require that any developer on the project has both GIT repositories cloned locally (given your two solutions are located in separate GIT repos) in order to be able to build the ASP.NET Core solution. But I don't really see that as a downside.

Nuget package not copying native DLLs on build

I'm trying to create a managed library and package it with Nuget. The managed library consumes another DLL written in C and makes the calls through [DllImport] P/Invoke calls. In the root of the project I have a folder structure like:
root/runtimes/win-x86/native/file.dll
root/runtimes/win-x64/native/file.dll
I am not using a .nuspec file but instead generating the Nuget package from the .csproj file from a .NET STandard 2.0 project. I'm including those files with this in the .csproj file.
<ItemGroup>
<Content Include="runtimes\**" PackagePath="runtimes" Visible="true" />
</ItemGroup>
The nuget package has the managed DLL in the lib/netstandard2.0 directory and even has the unmanaged DLL in root/runtimes/RID/native directory. The project that is consuming this nuget package installs perfectly and builds without error.
The managed DLL the consumer will interface with is trying to use that native DLL like this
[DllImport("file_name.dll")]
private static extern IntPtr CscanHOpen(string connectionString);
//...
public void Open(string connectionString, int port) {
_handle = CscanHOpen(connectionString, port);
}
I'm getting the "file cannot be found" error from the project installing the nuget package and when I look in the build directory I don't see that unmanaged DLL there. I've tried using a targets file to copy the unmanaged DLL to the output directory of the consuming project but it never shows up.
I keep looking back at this question because there are no answers, so I'm going to repeat what we discussed in the comments.
The runtimes feature of NuGet only works for projects using your package with PackageReference, not packages.config. In fact, despite being on the NuGet client team, I'm not actually sure if runtimes is an SDK-style project feature, or if it also works with traditional projects. Honestly, I expect it only works with SDK style projects, because it requires the rest of the build system to know how to use these assets.
Therefore the answer to your question is to test your package with a SDK-style project. All .NET Core apps are SDK style, but you can also edit the project and change <TargetFramework>netcoreapp2.2</TargetFramework> to `net48, or make the xml tag plural and the value a semi-colon delimited list of TFMs.
Also note that class libraries don't have a host, hence don't have a RID. Therefore you may not see the runtime dlls. You need to make sure your test project that uses the package is something that has a host & entry point, like a console app.
To support packages.config projects (and probably traditional projects using PackageReference) you will need to bundle your own props and targets file in the package. You said you tried it, but it didn't work, which unfortunately just means you were doing it wrong. NuGet has a convention on how you must name your props and targets file. If you got that right, then the way you implemented copying the files didn't work. You can use MSBuild's increased verbosity, or msbuild -bl coupled with the MSBuild structured log viewer to debug your targets file.
Using the runtimes feature is so uncommon I don't really have any experience with it and don't know how to support both traditional projects, while using the integrated runtimes support in SDK style projects. I suggest you'll need to make sure your targets have a condition to run only when it's not an SDK style project, but I don't know how you'd detect that.

MSBuild .NET project that will output existing assembly as it's result

I need to create csproj file that will be usable as project reference in VS2013 and will output prebuilt binary as it's "Build" result.
We use referenced projects for build, however company policy doesn't allow access to some of that projects for everyone. As a result projects need to be updated manually to make them build. This is really a major inconvenience when switching branches and when making edits to project files, so I want to create dummy project that will be bound to pre-built binaries as their "output" and will be placed instead of real projects.
EDIT: Moving that assembly to Nuget package is not an option for now since Nuget has some issues with dev flow (when you need to debug/test/develop package). I saw some VS extension that implements switching between Nuget package and local project which might solve this issue, but I'm not sure if it will be accepted and want to explore other options.
To be clear - the thing I want to avoid is editing project in any way, so that project can be built cleanly after pulling it from Git, and I don't have to clean it every time before commit.
I haven't properly tested it, but the solution seems really simple (if I understand the question properly).
Just add this to the existing .csproj, overriding the Build target to just give the path to the pre-built assembly.
<Target
Name="Build"
Returns="$(TargetPath)" />
This assumes the TargetPath property already defined, and it should automatically be if you're modifying the original .csproj. Otherwise just define it yourself in a <PropertyGroup> before the Build task.
Note that having TargetPath defined is important for the ProjectReferences in your own project to resolve.
How about having those restricted (binary only) projects reside in an internal Nuget package feed, so that Nuget can install the packages as needed, on build?

Pain-free local development while also referencing NuGet packages

I am attempting to publish and consume versioned NuGet packages of class libraries while avoiding headaches for local development. Here is a sample Visual Studio solution layout:
| Libraries
| LibraryA
| LibraryB
| LibraryC
| Applications
| ApplicationD
| ApplicationE
This is a single solution containing both shared class libraries and multiple applications. Currently references to the class libraries by the applications are local in-solution references.
What I would like to do is to publish the libraries (A,B,C) as versioned NuGet packages which are then referenced by the applications as needed (D,E). This allows a change to a shared library to be independent from an update to an application which is deployed. Without this, changing one library could cause the binaries to change in a dozen or more applications, all of which would technically need to be tested. This is undesirable, and versioning with NuGet fixes this.
However, let us say that I want to update the content of LibraryA and ApplicationD at the same time. In order to do this after we have switched to NuGet, I will have to make changes to LibraryA, commit them, wait for the package to be created, tell ApplicationD to update its reference to LibraryA, and then test or develop in ApplicationD. This is far more complicated than simply working with both at the same time using local in-solution references.
What is a better way to get both the robustness of versioned NuGet packages for my shared class libraries while also keeping development simple even if it spans over multiple projects and applications? The only other solutions I have found all involve too much overhead or headache, such as having to constantly change the references for ApplicationD between the NuGet package and the local project.
EDIT: To clarify the premise, this question assumes the following:
The architecture (solution and project organization) cannot be significantly reorganized
Shared libraries are going to change at a non-trivial frequency
Changing a shared library cannot force any application to be updated
Applications can reference different versions of shared libraries
Although it takes some work, it is possible to hand-edit .csproj files in order to set up conditional referencing by adding a Condition attribute to the appropriate references.
EDIT I've moved these conditions into ItemGroups, as it seems this is how my mentioned production code is working, and there has been mention of this being a possible issue in VS 2013.
<ItemGroup Condition="'$(Configuration)' == 'Debug Local'">
<!-- Library A reference as generated by VS for an in-solution reference, children unmodified -->
<ProjectReference>...
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug NuGet'">
<!-- Library A reference as generated by NuGet, child nodes unmodified -->
<Reference Include="LibraryA">...
</ItemGroup>
This would allow you to have, on the Projects D & E, configurations of "Debug NuGet" vs. "Debug Local" which reference the libraries differently. If you then have multiple solution files which have their configurations mapped to the appropriate configurations on the projects within, the end user would never see more than "Debug" and "Release" for most operation, since those are the solution configs, and would only need to open the full solution for editing the A, B, & C projects.
Now, as for getting the A, B, & C projects out of the way, you could set them up under a folder marked as a subrepo (assuming you're using an SCM that supports this, such as Git). Most users would never need to pull the subrepo since they're not accessing the ABC projects, and are instead grabbing from NuGet.
Maintenance wise, I can guarantee that VS will not edit the conditional references, and will respect them during compilation -I have gone through both VS 2010 and 2013 (EDIT: Professional version, though I have delved into doing the same with express) with the same conditional reference projects at work. Keep in mind than in VS, references can be made version-agnostic, making NuGet the only place from which version need be maintained, and that can be done like any other NuGet package. While I'm hopeful, I have NOT tested whether NuGet will fight with the conditional references.
EDIT It may also be prudent to note that conditional references can cause warnings about missing DLLs, but does not actually hinder compilation or run.
EDIT For those still reading this, I'm now (7/2019) hearing that the IDE isn't as friendly to these changes anymore, and either it or the Package Manager may override them. Proceed with caution, and always read your commits!
Update for .NET Core (2.x ++)
.NET Core 2.x actually has this functionality built in!
If you have a project reference to project A in project B, and project A is a .NET Standard or Core project with proper package information (Properties -> Package with Package id set to your NuGet package ID), then you can have a regular project reference in project B's .csproj file:
<ItemGroup>
<ProjectReference Include="..\..\A\ProjectA.csproj" />
</ItemGroup>
When you pack (dotnet pack) project B, because of the Package id in project A, the generated .nuspec file will be set up with a NuGet dependency to that Package ID, together with other NuGet references you might have, instead of just including the built DLL file.
<dependencies>
<group targetFramework=".NETStandard2.0">
<dependency id="Project.A" version="1.2.3" exclude="Build,Analyzers" />
<dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
</group>
</dependencies>
I know this is a 2-years old post, but just found it while facing the same situation. Also found this for VS2015, I'm in the process of testing it. I'll come back and adjust my answer accordingly.
https://marketplace.visualstudio.com/items?itemName=RicoSuter.NuGetReferenceSwitcherforVisualStudio2015
I also faced a similar problem. One approach that worked was using local repository (which is basically just a folder in local) and adding post-build script in the libraries. For example: let's say you need to update your implementation for LibraryA, then include following 3 steps in your post-build event for LibraryA:
Check if local repository has that version of package; if yes then delete it
rd /s /q %userprofile%\.nuget\packages\LibraryA\#(VersionNumber) -Recurse -ErrorAction Ignore
Create a nuget package
nuget pack LibraryA.csproj
Push it to local repository
nuget push LibraryA#(VersionNumber) -Source %userprofile%\.nuget\packages
These steps will make sure that the package is always updated for that version after each build (we had to do this since nuget packages are immutable)
Now in ApplicationD, you can point to local repository (%userprofile%.nuget\packages) to get LibraryA; such that after each build of LibraryA, you will receive an updated version of it in ApplicationD
PS: Inorder to get version number of you library you can use this : Determine assembly version during a post-build event
Unfortunately, there really isn't a way to have the best of both worlds. Internally in my company, we've mitigated it somewhat with a fast build/deploy process, which counteracts most of the burdens with always referencing a NuGet package. Basically, all of our applications use a different version of the same library hosted in a local NuGet repository. Since we use our own software to build, deploy, and host the packages, it makes it pretty quick to update the library, then update its NuGet package in another solution. Essentially, the fastest workflow we've found is this:
Make changes to library
Automatically build and deploy version of library incremented by 1 to internal NuGet feed
Update NuGet package in consumer application
The whole process from check-in to updating the consuming project takes around 3 minutes. The NuGet repository also has a symbol/source server which helps tremendously with debugging.
In the properties of ApplicationD, go to the "Reference Paths" tab and add the path of the output folder of LibraryA. Then, if you change and build LibraryA, the next build of ApplicationD will use the modified LibraryA.
When you are finished, don't forget to remove the "Reference Paths" and update the referenced NuGet package version.
My not-so-clean yet fastest solution so far is:
Assuming the following two separate solutions:
VS Solution 1: contains libraries published as nuget packages:
Solution1
|_ my.first.library
|_ my.second.library
VS Solution 2: contains applications, which consume one or more of the above libraries as PackageReferences:
Solution2
|_ my.first.application
| |_ depends on nuget my.first.library (let us say v1.0.1)
|
|_ my.second.application
In case, I'm making changes to my.first.library
I proceed as follows:
Make code changes to my.first.library and rebuild
Navigate to the build output directory of my.first.library (e.g. <Solution1 directory>/my.first.library/bin/debug/netstandard2.0) and copy the .dll and .pdb files
Navigate to the my.first.library's local directory of the currently being used nuget feed (for example at: C:\Users\user.name\.nuget\packages\my.first.library\1.0.1lib\netstandard2.0) and replace the .dll and .pdb files there with the ones generated in step 1 (possibly making backup).
Changes get reflected in my.first.application. Continue working and repeat steps 1-4, when needed
Advantages:
being completely local. No secondary nuget feeds needed.
zero changes to .csproj/.sln files
Caution:
While this solution offers you flexibility, make sure you clear your nuget cache before acting on them, for example by publishing to a nuget server. Thanks #Benrobot

Categories