I have a Visual Studio 2022 solution, with multiple projects, but four in particular are interesting here.
Provider1 which is based on .NET Framework 4.
Provider2 which is based on .NET 6.
Provider1Test which is based on .NET Framework 4.
Provider2Test which is based on .NET 6.
The Provider1 project has a number of classes, all in the Provider.Data namespace, one of them being Class1. This is my source code. The Provider1.csproj file:
<ItemGroup>
<Compile Include="Class1.cs">
<SubType>Code</SubType>
</Compile>
...
</ItemGroup>
The Class1.cs file:
namespace Provider.Data
{
public class Class1
{
...
}
}
The Provider2 project has links to these source files, i.e. "Add"->"Existing item"->"As link". It compiles with different conditional compilation symbols, so the output is not the same as for the Provider1 project.
The Provider2.csproj file:
<ItemGroup>
<Compile Include="..\Provider1\Class1.cs" Link="Class1.cs" />
</ItemGroup>
The Provider1Test project is an NUnit test project, that tests Provider1. It has multiple test classes, one of them is TestClass1.
The Provider2Test project is also a NUnit test project, with a ProjectReference to Provider2. It links to the test classes in Provider1Test in the same way as the source code does. The Provider2Test.csproj file:
<ItemGroup>
<ProjectReference Include="..\Provider2\Provider2.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Provider1Test\TestClass1.cs" Link="TestClass1.cs" />
</ItemGroup>
The TestClass1.cs file:
using Provider.Data;
namespace ProviderTests
{
public class TestClass1
{
...
}
}
Now, this builds and runs just fine inside Visual Studio, but if I navigate to the Provider2Test folder and try to build with the dotnet build command, it doesn't find the source code.
C:\dev\DataProvider\Provider2Test>dotnet build
MSBuild version 17.3.1+2badb37d1 for .NET
Determining projects to restore...
All projects are up-to-date for restore.
Provider2 -> C:\dev\DataProvider\Provider2\bin\x64\Debug\net6.0\Provider.Data.dll
1 file(s) copied.
C:\dev\DataProvider\Provider1Test\TestClass1.cs(14,7): error CS0246: The type or namespace name 'Provider' could not be found (are you missing a using directive or an assembly reference?) [C:\dev\DataProvider\Provider2Test\Provider2Test.csproj]
Build FAILED.
What is the issue here, why doesn't dotnet build follow the reference path here, and how do I solve it?
I tried to create a TestClass2.cs file directly in Provider2Test, that is not a link but a standard compile include, and also using the Provider.Data namespace. It produces the same error.
I found a workaround, so I'm posting it here and I'm going with it for now, but I don't think it's a good solution, and it doesn't explain the original issue, so I'm not going to mark this as the accepted answer.
In Provider2.csproj, I added that if it is built with dotnet build, it has a post-build event that copies its source code dll to Provider2Test. This is not run if the project is build within Visual Studio ("$(MSBuildRuntimeType)" == "Full").
if "$(MSBuildRuntimeType)" == "Core" XCOPY "$(OutDir)Provider.Data.dll" "$(ProjectDir)..\Provider2Test\$(OutDir)" /Y /F
In Provider2Test.csproj I added a conditional assembly reference.
<ItemGroup>
<Reference Include="Provider.Data" Condition="$(MSBuildRuntimeType) == 'Core'">
<HintPath>$(OutDir)Provider.Data.dll</HintPath>
</Reference>
</ItemGroup>
I kept the ProjectReference in all cases (both "Full" and "Core"), in order to trigger a Provider2 build whenever Provider2Test is built.
Related
After I installed this nuget package in my specflow demo C# .NET Core 3.1 project, I got this error:
Severity Code Description Project File Line Suppression State
Error CS0246 The type or namespace name
'Specflow_Demo_XUnitAssemblyFixture' could not be found (are you
missing a using directive or an assembly
reference?) Specflow.Demo ...\Specflow.Demo\Features\LoggedInDiscount.feature.cs\LoggedInDiscount.feature 3 Active
This is my csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.9.22" />
<PackageReference Include="SpecFlow.xUnit" Version="3.9.22" />
<PackageReference Include="SpecRun.SpecFlow" Version="3.9.7" />
</ItemGroup>
</Project>
After I close all the files in Visual Studio and rebuild, I got another error:
There is an open issue with SpecFlow related to this: Type or namespace [TestNamespace]_XunitAssemblyFixture could not be found. Are you still able to run your test cases? The above link says its an intellisense only issue.
From a comment on the GitHub issue discussion:
The generated assemblyFixture file (e.g.: [TestNamespace]_XunitAssemblyFixture) can be found in the obj folder (obj\Debug\targetframework\xUnit.AssemblyHooks.cs).
We realized that this is IntelliSense related "issue" (IntelliSense of VisualStudio itself, not R#).
As you all noticed, the build was successful, but the error was still there. This is because the generated code behind file (*.feature.cs) is opened in your editor. If you close them, and build again, the error will disappear.
...
BTW there is an ongoing PR which will move the generated files to the obj folder, so this problem will disappear when it'll be merged.
I had a quick look through the types in the referenced nuget packages. None of them uses the naming style that you have there 'Specflow_Demo_XUnitAssemblyFixture' - and none of them has a type with a similar name.
So, as the error says, the type doesnt exist.
I am developing a .net5.0 web api and i am getting the following error while using DinkToPdf:
DllNotFoundException: Unable to load DLL 'libwkhtmltox' or one of its dependencies: The specified module could not be found. (0x8007007E)
I have followed this tutorial, with a few exceptions:
added the service added the service, which was not done in the tutorial
services.AddSingleton(typeof(IConverter),
new SynchronizedConverter(new PdfTools()));
...
services.AddScoped<IPdfService, PdfService>();
named the services differently, but that shouldn't matter
installed it via NuGet instead of Install-Package DinkToPdf
my project is just an API, frontend is not in C#, shouln't matter sincer the error is here:
return this._converter.Convert(htmlToPdfDocument);
Did everything else like in the tutorial.
For me adding this into the csproj file resolved the issue -
<ItemGroup>
<None Remove="libwkhtmltox.dll" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="libwkhtmltox.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
What is happening there is you are missing the dlls under your project directory.
you can get them here DinkToPdf dlls and include them in your project.
You can run below and it will install dlls into bin. Make sure copy those dlls into root directory
Install-Package DinkToPdfCopyDependencies -Version 1.0.8
You can also try using this package to include the dependencies:
https://www.nuget.org/packages/DinkToPdfCopyDependencies
TL:DR;
Is there a way to resolve a "partial" circular dependency between C# projects using MSBuild wizardry? 🧙‍♂️
Long version
We have a project A that depends on project B. A.csproj looks like this:
<ItemGroup>
<ProjectReference Include="..\projectB\B.csproj" />
</ItemGroup>
Now project B needs a type from Project A. VS prevents us from adding a reference to project A (circular dependency) but it doesn't complain when we add a link to the specific file, like so in B.csproj:
<ItemGroup>
<Compile Include="..\projectA\ClassA.cs" Link="ClassA.cs" />
</ItemGroup>
The problem appears when we use ClassA on project A. Now VS complains (rightfully) about multiple declarations of ClassA (CS0436 - we have set warnings as errors), one from each project.
I am aware that this shows that our design is flawed and as other answers here in SO indicate the right solution would be to refactor. If this is not possible due to time constraints, is there any MSBuild trick that would allow projectA to compile?
For reference, things that I tried and don’t work
In A.csproj: set ReferenceOutputAssembly=false from project B.
=> Would work if project A doesn’t need anything from B.
In B.csproj: include and then remove 🥴
<ItemGroup>
<Compile Include="..\circdependency\ClassA.cs" Link="ClassA.cs" />
<Compile Remove="ClassA.cs" />
</ItemGroup>
In B.csproj: CopyToOutputDirectory=Never
Other options that work but are not ideal:
Suppressing the warning.
Duplicating ClassA in project B and using a different namespace, making it internal etc.
I currently have an issue with loading assemblies at runtime using Assembly.LoadFrom(String).
While the specified assembly is loaded just fine, referenced third-party assemblies (e.g. nuget packages) are not loaded when the targeted framework is either netcoreapp or netstandard.
To figure out the problem i have created a simple solution consisting of three projects.
Each project contains exactly one class.
I'm using Newtonsoft.Json as a nuget example here but it could be any other assembly.
ClassLibrary0.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;netstandard1.0</TargetFrameworks>
</PropertyGroup>
</Project>
namespace ClassLibrary0 {
public class Class0 {
public System.String SomeValue { get; set; }
}
}
ClassLibrary1.csproj
Has a package reference to Newtonsoft.Json via nuget.
Has a reference to additional assembly ClassLibrary0 depending on TargetFramework (shitty conditional ItemGroups).
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netstandard1.0;netstandard1.1;netstandard1.2;netstandard1.3;netstandard1.4;netstandard1.5;netstandard1.6;netstandard2.0;netcoreapp1.0;netcoreapp1.1;netcoreapp2.0;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net20' OR '$(TargetFramework)'=='net35' OR '$(TargetFramework)'=='net40' OR '$(TargetFramework)'=='net45' OR '$(TargetFramework)'=='net451' OR '$(TargetFramework)'=='net452' OR '$(TargetFramework)'=='net46' OR '$(TargetFramework)'=='net461' OR '$(TargetFramework)'=='net462' OR '$(TargetFramework)'=='net47' OR '$(TargetFramework)'=='net471' OR '$(TargetFramework)'=='net472'">
<Reference Include="ClassLibrary0">
<HintPath>..\net20\ClassLibrary0.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.0' OR '$(TargetFramework)'=='netstandard1.1' OR '$(TargetFramework)'=='netstandard1.2' OR '$(TargetFramework)'=='netstandard1.3' OR '$(TargetFramework)'=='netstandard1.4' OR '$(TargetFramework)'=='netstandard1.5' OR '$(TargetFramework)'=='netstandard1.6' OR '$(TargetFramework)'=='netstandard2.0'">
<Reference Include="ClassLibrary0">
<HintPath>..\netstandard1.0\ClassLibrary0.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp1.0' OR '$(TargetFramework)'=='netcoreapp1.1' OR '$(TargetFramework)'=='netcoreapp2.0' OR '$(TargetFramework)'=='netcoreapp2.1'">
<Reference Include="ClassLibrary0">
<HintPath>..\netstandard1.0\ClassLibrary0.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
namespace ClassLibrary1 {
public class Class1 {
public System.String SomeValue { get; set; }
public Class1() {
var tmp = new ClassLibrary0.Class0();
var tmp2 = new Newtonsoft.Json.DefaultJsonNameTable();
}
}
}
ClassLibrary2.csproj
Has a project reference to ClassLibrary1.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;netstandard1.0;netstandard1.1;netstandard1.2;netstandard1.3;netstandard1.4;netstandard1.5;netstandard1.6;netstandard2.0;netcoreapp1.0;netcoreapp1.1;netcoreapp2.0;netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" />
</ItemGroup>
</Project>
namespace ClassLibrary2 {
public class Class2 {
public System.String SomeValue { get; set; }
public Class2() {
var tmp = new ClassLibrary1.Class1();
}
}
}
After running dotnet restore and rebuilding the solution the root problem can be observed in the output directories:
The Problem:
Copies of ClassLibrary0.dll are present in all output directories (=> references to third-party are good).
Copies of ClassLibrary1.dll are present in all output directories of ClassLibrary2 (=> project references are good too).
Copies of Newtonsoft.Json are only present in net output directories but are missing in all netcoreapp and netstandard.
All netcoreapp and netstandard output directories contain a *.deps.json file that correctly mentions the Newtonsoft.Json package as a dependency.
A call to Assembly.LoadFrom(String) however won't load these dependencies to Newtonsoft.Json in case of netcoreapp and netstandard.
This results in FileNotFoundException at runtime after running code from the specified loaded assemblies.
What i've tried:
I am trying to resolve those by attaching to the AppDomain.AssemblyResolve event but so far i'm out of luck.
Those *.deps.json don't contain a location path of the dependency.
I've tried looking for the assembly in all the locations within the Path environment variable but the nuget package location doesn't seem to be listed there.
The location on all my machines seems to be %userprofile%\.nuget\packages\package-name\version\.
However i'm not 100% positive that this will always be the correct location for nuget packages on all machines that might execute my code.
The actual question:
Is there a solid way to resolve nuget dependencies at runtime when manually loading assemblies?
Restrictions:
This needs to be an offline solution, no downloading of package versions on the fly.
Cannot rely on <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> in the original projects.
Cannot rely on me having references to the dependencies in question.
The whole point of doing this is to be able to dynamically load assemblies that i can't know about at compile time.
I have solved the problem by writing my own NuGet package resolver, which looks for the appropriate package at runtime. I haven't had the time for a proper documentation yet but it's already on my plate. Resolving at runtime requires to attach to AppDomain.AssemblyResolve with something like that:
private Assembly OnAssemblyResolve(Object sender, ResolveEventArgs args) {
if(AssemblyResolver.Nuget.TryResolve(args, out IEnumerable<FileInfo> files)) {
foreach(FileInfo file in files) {
if(AssemblyHelper.TryLoadFrom(file, out Assembly assembly)) {
return assembly;
}
}
}
return null;
}
This requires the use of my NuGet package which contains the resolver and some helpers. There is also an article that goes into the details and design decisions of the resolver.
I realize that dotnet publish will also copy any dependencies but this is a special edge case.
I have Referenced MySql.Data on one project and Other project referenced nuget package which also referenced MySqlConnector inside of it. projects has dependency .
when i compile application im getting this error
This is application hierarchy
is there any way to avoid this? or did i do anything wrong when referencing packages?
Thanks
UPDATE
this is the same namespaces from difference libs
UPDATE 2
This is the sample repo which reproduced same issue
In NET.Framework projects you can go to the reference properties and set an alias for assembly. Net core projects doesn't fully support yet aliases for assemblies. But there is a workaround to use aliases in .net core. Edit your csproj file like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'MySqlConnector'">
<Aliases>MySqlConnectorAlias</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
...
</Project>
then in your cs file before all usings:
extern alias MySqlConnectorAlias;
then you can reference to you type from MySqlConnector like this:
MySqlConnectorAlias::MySql.Data.MySqlClient.MySqlConnection
It will work If you remove mysql.data reference from Your project/references.
Hope it will work for you. for me it was worked. My project is ASP.NET Core Framework. Created project in VS2017 and opening in VS2019 at that time it introduced.