access referenced projects at runtime - c#

I have a rather strange project where I need to check the assemblies of the projects included as references in my project to see if they contain a certain Type. As far as I can tell the only way to see which projects are in my solution is to parse the solution file - which I can't do at runtime since I don't have it.
Does anyone know a way to see, at runtime, which assemblies are in the project file?

To check the referenced assemblies in your project assembly at runtime, you need to use Reflection.this.GetType().Assembly.GetReferencedAssemblies()

Related

Base project dll reference not found in upper layers

In my current architecture I have the following project organization...
An class library named "MyBaseProject" and different web application projects with reference to MyBaseClassLibrary.
In MyBaseProject I added a 3rd party dll (Newtonsoft.Json)
Now all web projects are throwing the exception "Could not load file or assembly Newtonsoft.Json or one of its dependencies."
I do not want to add the Newtonsoft.Json in all my web projects, what should I do?
See How the Runtime Locates Assemblies.
The most obvious behaviour here is that you have not set the output directory for your projects, and thus they're defaulting to their own, individual locations. Thus, while MyBaseProject references and copies Newtonsoft.Json, your other projects only copy over MyBaseProject. Because of this, the MyBaseProject.dll located in the folder with the other projects does not have a copy of Newtonsoft.Json, and since it's not in the GAC, the reference fails.
The easiest solution is to make all your projects output to the same directory. I'm personally fond of $(SolutionDir)\bin\$(Configuration)\$(Platform). This will ensure that when MyBaseProject.dll is built and carries along any of its requirements, your other projects will be able to get those requirements via the same folder without incident.

Is "Copy Local" transitive for project references?

Wrt. the proposed dupe: Since this here queston suggests the opposite of the linked question, I'd rather like to think it is not a dupe.
First, I did read What is the best practice for “Copy Local” and with project references? (also this) and I'll have to try this out anyway, but getting general feedback on this seems necessary as the docs on this stuff are horrible and I'm only on VS2010 and maybe they changed something in newer versions that'll be nice to know.
Second, I'm only interested in project references for this question as I've read that assemblies from the GAC are handled differently and the GAC is irrelevant for my problem.
Third, after reading the suggested dupe, but more so the nice answer here by #Albireo, it would also appear that it is important to differentiate file dependencies, where the dependency references a dll assembly file and project dependencies (i.e. what I'm asking about), where the dependency references a project and implicitly the output file of that project.
Anyway, here's the situation, somewhat peculiar I think, but still:
2 C# executable projects
n C# dll assembly projects
The 2 executables have different output directories as they will be deployed separately and that way they're also separate on the developer machine
The 2 executables have dependencies on some of the DLL assemblies (which may depend on each other)
There are three output directories:
/x1 for executable 1 project
/x2 for executable 2 project
/lib for all the dll assemblies
The DLL assemblies all have Copy Localset to false for their project references, as they all build to the same output directory.
The 2 executable projects have set Copy Local to true for all the DLL assembly project references they reference directly, so that the DLLs will be copied into /x1 /x2 respectively.
The question now is wrt. to DLLs that are not directly referenced by an executable project, but only transitively through a referenced assembly: Will assemblies, that are only referenced transitively through another assembly, be copied into the output folder of the executable, when "Copy Local" is set to true on the first assembly?
Example:
x1.csproj (e.g.Output = x1/one.exe)
Reference: dlA.csproj ( e.g. Output = lib/a.dll) with Copy Local = *true*
(no direct reference on b.dll)
dlA.csproj ( e.g. Output = lib/a.dll)
Reference: dlB.csproj ( e.g. Output = lib/b.dll) with Copy Local = **false**
(no direct reference on c.dll)
dlC.csproj ( e.g. Output = lib/c.dll)
(no further relevant references)
Thus, we have a logical dependency of one.exe -> a.dll -> b.dll -> c.dll, where only a.dll with obviously be copied to the output directory of one.exe. Will the other two dlls also be copied to the output directory? Is this documented somewhere?
And, yes, I tried it. And, yes, it seems to work, but I haven't poked it hard enough yet and anyway there maybe something more to it that I may have missed. (And also there's the question wrt. any official docs.)
it would also appear that it is important to differentiate file dependencies, where the dependency references a dll assembly file and project dependencies (i.e. what I'm asking about), where the dependency references a project and implicitly the output file of that project.
Not really, no.
MSBuild doesn't really care if the reference points to another project in the solution or to a DLL.
If ProjectA depends on ProjectB to build ProjectA ProjectB must be already built (and up-to-date), MSBuild will then pull its DLL (not its C# code) and link it to ProjectA.
Adding a project reference instead of a DLL is "syntactic sugar" for your convenience: this way MSBuild knows it must pick the output of the referenced project, whatever the output is.
Otherwise, you'll have to manually pre-build the dependency, find its DLL and link it to the project, repeating the process whenever you switch build configuration, move or rename things. Not really practical.
Will the other two dlls also be copied to the output directory?
If any kind of element from a dependency is used directly from the project where the assembly is referenced, that reference will be copied.
An example could be this solution layout:
MySolution
MySolution.ConsoleApplication
MySolution.FirstDependency
MySolution.SecondDependency
MySolution.ThirdDependency
MySolution.FourthDependency
With this dependency chain:
MySolution.ConsoleApplication
MySolution.FirstDependency
MySolution.SecondDependency
MySolution.ThirdDependency
MySolution.FourthDependency
If you build this solution you'll notice that in MySolution.ConsoleApplication output directory there will be the DLLs for MySolution.FirstDependency, MySolution.SecondDependency and MySolution.ThirdDependency but no DLL for MySolution.FourthDependency.
Why is it so? When MSBuild builds MySolution.SecondDependency it notices that there's a dependency declared to MySolution.FourthDependency, but since it can't find any usage of any kind of element from MySolution.FourthDependency in MySolution.SecondDependency code it decides to perform some "optimization" and omits MySolution.FourthDependency assembly from the output.
This same issue bit me in the past when I added through NuGet AutoMapper to a "deep dependency": adding AutoMapper adds two assembly references, AutoMapper and AutoMapper.Net4, where the second assembly is loaded by the first through reflection when it needs to perform certain kind of action on the new collection objects introduced by the .NET Framework 4. Since the second assembly is loaded through reflection MSBuild thinks it's unused and doesn't bother to copy it around.
So, yes, they will be copied as long as you're using them directly and not through reflection.
Is this documented somewhere?
This behavior seems to be a "feature" of MSBuild, I managed to find a blog post by some folks from Microsoft back when I experienced this issue, but I can't find it again at the moment.
It is very straight forward, doesn't have anything to do with Copy Local. MSBuild looks in the metadata of an assembly to see what the dependencies are for an assembly. So can you, run ildasm.exe on the assembly and double-click the Manifest. Be sure to try this to get insight. You'll see the .assembly directives. Inserted by the compiler when it built the assembly, only the referenced assemblies you actually used in your code will be listed.
If MSBuild can find such an assembly in the same directory then it will automatically copy it. If not then it will silently skip the copy.
From this, you can deduce the failure modes. It cannot copy unmanaged DLLs, they do not appear in the metadata. It cannot copy assemblies that you have an indirect dependency on through Assembly.Load/From(), they don't appear in the metadata either. It cannot copy assemblies that haven't been built yet, a build order problem. And it cannot copy assemblies whose Copy Local property you set to False. Which is normally only a valid choice if the assembly is present in the GAC, no copy required.
For such cases you need to help, XCOPY in a post-build event gets the job done.

The type is defined in an assembly that is not referenced, how to find the cause?

I know the error message is common and there are plenty of questions on SO about this error, but no solutions have helped me so far, so I decided to ask the question. Difference to most of similar questions is me using App_Code directory.
Error message:
CS0012: The type 'Project.Rights.OperationsProvider' is defined in an
assembly that is not referenced. You must add a reference to assembly
'Project.Rights, version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Source File:
c:\inetpub\wwwroot\Test\Website\App_Code\Company\Project\BusinessLogic\Manager.cs
Following suggestions here and here, I have deleted all instances of Project.Rights.dll inside C:\Windows\Microsoft.NET/*.*
According to this, I checked if .cs files in question have build action set to "Compile". They do.
I have also double checked that the .cs file containing the "Project.Rights.OperationsProvider" type is deployed to App_Code directory.
For some reason, application is not looking for the type in the App_Code directory. Since I've deleted all instances of Project.Rights.dll (that I know of), I don't know which assembly the error message is mentioning.
When you get this error it isn't always obvious what is going on, but as the error says - you are missing a reference. Take the following line of code as an example:
MyObjectType a = new MyObjectType("parameter");
It looks simple enough and you probably have referenced "MyObjectType" correctly. But lets say one of the overloads for the "MyObjectType" constructor takes a type that you don't have referenced. For example there is an overload defined as:
public MyObjectType(TypeFromOtherAssembly parameter) {
// ... normal constructor code ...
}
That is at least one case where you will get this error. So, look for this type of pattern where you have referenced the type but not all the types of the properties or method parameters that are possible for functions being called on that type.
Hopefully this at least gets you going in the right direction!
Check target framework in the projects.
In my case "You must add a reference to assembly" actually meant, that caller and reference projects didn't have the same target framework. The caller project had .Net 4.5 , but referenced library had target 4.6.1.
I am sure, that MS compiler can be smarter and log more meaningful error message. I've added a suggestion to https://github.com/dotnet/roslyn/issues/14756
In my case this was because doing a NuGet package update had only updated references to a dll dependency in some but not all projects in my solution - resulting in conflicting versions. Using a grep-style tool to search text within *.csproj files in my solution it was then easy to see the projects that still needed to be updated.
When you get this error, it means that code you are using makes a reference to a type that is in an assembly, but the assembly is not part of your project so it can't use it.
Deleting Project.Rights.dll is the opposite of what you want. You need to make sure your project can reference the assembly. So it must either be placed in the Global Assembly Cache or your web application's ~/Bin directory.
Edit-If you don't want to use the assembly, then deleting it is not the proper solution either. Instead, you must remove all references to it in your code. Since the assembly isn't directly needed by code you've written, but instead by something else you're referencing, you'll have to replace that referenced assembly with something that doesn't have Project.Rights.dll as a dependency.
In my case, I was referencing a library that was being built to the wrong Platform/Configuration (I had just created the referenced library).
Furthermore, I was unable to fix the problem in Visual Studio Configuration Manager -- unable to switch and create new Platforms and Configurations for this library. I fixed it by correcting the entries in the ProjectConfigurationPlatforms section of the .sln file for that project. All its permutations were set to Debug|Any CPU (I'm not sure how I did that). I overwrote the entries for the broken project with the ones for a working project and changed the GUID for each entry.
Entries for functioning project
{9E93345C-7A51-4E9A-ACB0-DAAB8F1A1267}.Release|x64.ActiveCfg = Release|x64
{9E93345C-7A51-4E9A-ACB0-DAAB8F1A1267}.Release|x64.Build.0 = Release|x64
Entries for corrupted project
{94562215-903C-47F3-BF64-8B90EF43FD27}.Release|x64.ActiveCfg = Debug|Any CPU
{94562215-903C-47F3-BF64-8B90EF43FD27}.Release|x64.Build.0 = Debug|Any CPU
Corrupted entries now fixed
{94562215-903C-47F3-BF64-8B90EF43FD27}.Release|x64.ActiveCfg = Release|x64
{94562215-903C-47F3-BF64-8B90EF43FD27}.Release|x64.Build.0 = Release|x64
I hope this helps someone.
It just happened to me that different projects were referencing different copies of the same dll.
I made sure all referenced the same file on disk, and the error disappeared as I expected.
Unloading and reloading the class library in Visual Studio solved this for me.
For me, this was caused by the project both directly and indirectly (through another dependency) referencing two different builds of Bouncy Castle that had different assembly names. One of the Bouncy Castle builds was the NuGet package, the other one was a debug build of the source downloaded from GitHub. Both were nominally version 1.8.1, but the project settings of the GitHub code set the assembly name to BouncyCastle whereas the NuGet package had the assembly name BouncyCastle.Crypto. Changing the project settings, thus aligning the assembly names, fixed the problem.
It didn't work for me when I've tried to add the reference from the .NET Assemblies tab.
It worked, though, when I've added the reference with BROWSE to C:\Windows\Microsoft.NET\Framework\v4.0.30319
I had this issue on a newly created solution that used existing projects. For some reason, one project could not "see" one other project, even though it had the same reference as every other project, and the referenced project was also building. I suspect that it was failing to detect something having to do with multiple target frameworks, because it was building in one framework but not the other.
Cleaning and rebuilding didn't work, and restarting VS didn't work.
What ended up working was opening a "Developer Command Prompt for VS 2019" and then issuing a msbuild MySolution.sln command. This completed successfully, and afterwards VS started building successfully also.
one of main reason can be the property of DLL
you must before do any thing to check the specific version property if it true make it false
Reason:
maybe the source code joined with other (old)version when you build it , but this Library upgraded with new update the version now different in the Assembly Cash and your application forbidden to get new DLL ,and after disable specific version property your applacaten will be free to get the new version of DLL references
Maybe a library (DLL file) you are using requires another library. In my case, I referenced a library that contained a database entity model - but I forgot to reference the entity framework library.
This can also mean you use a library, which exposes (public) types that are defined in a library. Even when you do not use these specifically in your library (the one that doesn't build).
What this probably prevents is you writing code that uses a class (which in its signature has the types from a library not referenced) that you cannot use.
For me the reason why the error appeared was that the WebForm where the error was reported has been moved from another folder, but the name of its codefile class remained unchanged and didn't correspond to the actual path.
Initial state:
Original file path: /Folder1/Subfolder1/MyWebForm.aspx.cs
Original codefile class name: Folder1_Subfolder1_MyWebForm
After the file was moved:
File path: /Folder1/MyWebForm.aspx.cs
Codefile class name (unchanged, with the error shown): Folder1_Subfolder1_MyWebForm
The solution:
Rename your codefile class Folder1_Subfolder1_MyWebForm
to one corresponding with the new path: Folder1_MyWebForm
All at once - problem solved, no errors reporting..
The type 'Domain.tblUser' is defined in an assembly that is not
referenced. You must add a reference to assembly 'Domain,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
**Solved:**
Add reference of my domain library layer to my web app libary layer
Note: Make sure your references are correct according to you DI container
In my case this was because I used
Implicit Operator
between BLL and DAL classes.when I want to use BLL Layer In Application Layer I got this error.
I changed
implicit operator
to
explicit operator
it be OK.
Thanks
In my case the version of the dll referenced was actually newer than the one that I had before.
I just needed to roll back to the previous release and that fixed it.
I have a similar problem, and I remove the RuntimeFrameworkVersion, and the problem was fixed.
Try to remove 1.1.1 or
My problem was that the Output Type for one of my projects was set to Console Application. To fix this, I right-clicked the project, chose Properties, clicked the Application tab, and change Output Type (from Console Application) to Class Library. After I re-compiled, this error went away.
Clean your solution and rebuild worked for me (in Visual Studio, these are options you get when you right click in your solution explorer), the error is gone in my project.

How to set "Specific Version" property for project references in Visual Studio

I have got a Visual Studio Solution containing several projects and have set up the references between the projects as project references.
When a reference to an assembly is added, the references' properties contain a setting for
Specific Version = True|False
This property is missing for project references. How can it be set? I'd like my solution to load any available assembly (no matter what version) in the bin folder.
I've had a problem when a workflow instance (Workflow Foundation) was deserialized and the dependencies were updated meanwhile.
I think the problem is that what you are asking is not possible directly with a project reference, I think that always implicitly turns into an 'explicit version', because of the nature of the link.
The way you could do this (calling the currently referenced project A, and the referencing project B):
Have the project you want to reference in your solution, just like you do now with the project reference
Explicitly set the dependency chain so the 'referenced' project is built first
Build the referenced project A once first manually
Create an assembly reference in project B to the results from the build in project A
Set the assembly reference to 'Specific Version = false'
The build order (dependency) will guarantee that A is always built before B, and B will reference it from the binary output directory of A.
(altho, it's a little brittle and I would not recommend it since it's easy to get wrong results if the settings are not all right, or the sun aligns with the stars wrong, or some such)
I might be misunderstanding your question, but when you add a project reference, the project's assembly is always loaded into any project that references it when the project is built. Therefore, you'll always have the latest available assembly in the bin folder for that project. VS treats projects differently than other assemblies in that regard.
You can add references to project output dlls instead of projects. Then you will be able to set Specific Version setting.
I have found the solution to my problem. It's described pretty detailed here.
The problem is not a matter of wrong project references, but more a de/serializing of workflow instances question.
Thanks to everybody who tried to help.

Assembly dependencies with .Net projects

If I have an assembly (A) which references another assembly (B).
I want to reference A in a project, I add the reference and it copies A into my BIN directory. It does not copy B as well, even though A depends on it, so the code doesn't compile.
How can I set things up so that whenever I reference A, both A and B get copied to my bin directory?
In Visual Studio, add each project to the same solution. Ensure you use Project References instead of direct file references (ie browsing for the assembly).
I dont think there is any way around what you ask other than to explicitly add both. I dont think however adding projects for the sake of getting references copied is a viable solution to the issue. Not all projects that a solution depends on should necassarily be added to the solution. This would completely depdend on your overall project structure, processes, source control, division of labour, etc
Reference both A and B.
Unfortunately you'll have to manually add both. This is what happens to me as well whenever I use pre-3.5 versions of NHibernate: it requires both log4net and Iesi.Collections assemblies. So I have no choice but to manually include a reference to both in all my solutions that implement NHibernate.
This is more of an issue, of course, if you only have the DLLs. If it's a project that you have a codebase to Visual Studio itself will warn you beforehand that the references are missing.
How about adding them to Global Assembly Cache?

Categories

Resources