.NET Assembly References going all circular on me
Update: Last night, I decided that this is just too much work to change the folder where some reports are saved. My work-around here is to rename the folder, run the batch job I need done, and then change the folder name back to what it was originally. I feel like I could spend the rest of today and all of next week working on this and still have nothing to show. I'd rather catch hell for going against my boss than not be able to invoice our customers (which only happens once a year). Thank you to all those who have helped, I'm humbled by your willingness to help some anonymous fella in over his head. I'm not sure how to "abandon" this question but still give you guys props, I'll read the faq and any comments during lunch. Thank you.
I'm trying to debug a c# applica开发者_如何学Gotion that my predecessor created. he's a programmer, I'm a sysadmin, maybe that's where I'm going wrong.
Anyway, I need to recompile one of the assemblies and deploy it to our production server. When I compile it, I get the error:
The type 'Mcrcsip.Web.McrcsipWebExceptionBase is definined in an assembly that is not referenced. You must add a reference to assembly 'Mcrcsip.Web, Version=2.0.3266.28977, Culture=neutral, PublicKeyToken=c3de6c6abcdf794b'.
I happen to have a copy of that assembly, and when I delete the reference to the existing assembly (2.0.0.0 with a different public key token) and add a reference to the assembly it's asking for, when I compile, I get this error message:
The type 'Mcrcsip.Web.McrcsipWebExceptionBase is definined in an assembly that is not referenced. You must add a reference to assembly 'Mcrcsip.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8bbdde85caf008d0'.
If I search for this error on google (genericised, of course) I get a bunch of "this is how you add an assembly reference..." results.
How do I get off this merry-go-round?
Here's how the solution's laid out:
- Mcrcsip.Amwa.Solution
http://amwa-test.internal.lan/
- Mcrcsip.Amwa.Core
- Mcrcsip.Aws.Bol
- Mcrcsip.Common
- Mcrcsip.Web
- nunit.framework
- System
- System.Configuration
- System.Data
- System.Enterprise Services
- System.Web
- System.Web.Services
- System.XML
- Mcrcsip.Amwa.CrFactory
- CrystalDecisions.CrystalReports.Engine
- CrystalDecisions.Enterprise.Framework
- CrystalDecisions.Enterprise.InfoStore
- CrystalDecisions.ReportSource
- CrystalDecisions.Shared
- CrystalDecisions.Web
- Mcrcsip.Amwa.Core
- Mcrcsip.Web
- System
- System.configuration
- System.Data
- System.Drawing
- System.Web
- System.XML
- Mcrcsip.Amwa.PdfFormHandler
- itextsharp
- Mcrcsip.Amwa.Core
- Mcrcsip.Web
- System
- System.Configuration
- System.Data
- System.Web
- System.Xml
- Mcrcsip.Amwa.Web
- Mcrcsip.Amwa.Core
- Mcrcsip.Amwa.CrFactory
- Mcrcsip.Amwa.PdfFormHandler
- Mcrcsip.Aws.BOL
- Mcrcsip.Common
- Mcrcsip.SharePoint
- Mcrcsip.Web
- System
- System.configuration
- System.Data
- System.EnterpriseServices
- System.Web
- System.Web.Services
- System.XML
- Mcrcsip.Amwa.WebControls
- System
- System.Data
- System.Design
- System.Drawing
- System.Web
- System.Xml
- Mcrcsip.Amwa.Setup
Reference inconsistencies or: how i learned how to stop worrying and love ILDASM
ahem, cough cough,
Problem
Nick,
From re-reading your original post, it is clear that you have a dll version-inconsistency issue. That is, at least one project in your solution depends on Mcrcsip.Web version X, and at least one project in your solution depends on Mcrcsip.Web version Y [or worse still, depends on a library that depends on Mcrcsip.Web version Y]. These can be difficult and tedious to track down.
See Recommended Solution to skip to the end.
How
This sort of inconsistency arises when
- you have a dependency such as A depends on B and C, B depends on C,
- A and B are originally built against C ver 1,
- A is updated and built against C ver 2,
contrary to what we intuitively expect, B will not auto-magically update to use C ver 2 when we build A. Both A and B must reference the same library to build properly. So either A must conform to C ver 1, or B must be rebuilt and conform to C ver 2.
Now, this can happen in any project configuration, which is why it is important to version your software [believe me this problem gets worse without proper signing\versioning], and communicate well within your team whenever a dependency update occurs.
It is also worth knowing there are two kinds of dependency references, hard and soft [in actual fact, they are the same, that is links to dlls, except one is a special case of the other, and conceptually it helps to distinguish the two].
Hard References
A hard reference is a dependency of a project to a static dll. That is, the dependency was built at a specific time and will never update unless its physical file is replaced with a new one. Hard references are added to a solution via Add References dialog, and adding a reference from the .Net, COM, or Browse tabs. Hard references are typically used to add dependencies to software developed outside the scope of the current solution [ie framework, third party, and other first party products developed by other internal teams]. Hard references also have a tendency to become stale, because they are maintained and updated by their own development stream.
Assume scenario above
- you have a dependency such as A depends on B and C, B depends on C,
- A and B are originally built against C ver 1,
- A is updated and built against C ver 2,
Further, assume A and B are within the same solution
- SimpleSolution
- A
- B [Hard reference]
- C v2 [Hard reference]
- B
- C v1 [Hard reference]
- A
When A is built, you will receive the error you described. A expects an object from C v2, but because B has a hard dependency on C v1, C v1 is loaded into memory first, and a collision occurs. A expects v2 and finds v1. That is your error.
To resolve this situation, you must
- Update project B hard reference C v1 to C v2
- Force rebuild of project B
- Update project A hard reference B to [newly built] B
- Force rebuild of A
Soft References
A soft reference is a dependency of a project to another project within the same solution. That is, the dependency is rebuilt every time the entire solution is rebuilt. Soft references are added to a solution via Add References dialog, and adding a reference from the Projects tab. Soft references are typically used to add dependencies to software developed inside the scope of the current solution, they have the primary advantage of propagating changes as they are made to consumers within the same solution. By virtue of this fact, soft references cannot be stale.
[this is a special case of a hard reference, Visual Studio will add a reference that points to the output path of the target project, i believe it also updates this path if the target project changes its output configuration - but a very handy feature that warrants distinction]
Assume scenario above
- you have a dependency such as A depends on B and C, B depends on C,
- A and B are originally built against C ver 1,
- A is updated and built against C ver 2,
Further, assume A and B are within the same solution
- SimpleSolution
- A
- B [Soft reference]
- C v2 [Hard reference]
- B
- C v1 [Hard reference]
- A
When A is built, you will receive the error you described. A expects an object from C v2, but because B has a hard dependency on C v1, C v1 is loaded into memory first, and a collision occurs. A expects v2 and finds v1. That is your error.
To resolve,
- Update project B hard reference C v1 to C v2
- Force rebuild of A
As you can see, soft references are easier to maintain.
IL DASM [Intermediate Language DisASeMbler]
Now that you know a bit more about references, and project maintenance, how exactly do you ascertain the state of your build? After all, any one of your projects or their dependencies may be inconsistent.
The easy way is to open your build output directory, and inspect the assembly manifest of each and every single dll that your solution produced.
To inspect an assembly's manifest,
- open
ildasm.exe
- For VS2010, ildasm is available from shortcut
- For VS2008 and VS2005, open a Visual Studio Command Prompt, from command line, type 'ildasm'
- open a dll,
- click File -> Open, or
- press Ctrl-O, or
- drag and drop your dll into
ildasm
window
- open MANIFEST
- double click red triangle node labeled MANIFEST
- find references to Mcrcsip.Web
- click Find and enter Mcrcsip.Web into dialog box, or
- press Alt-F and enter Mcrcsip.Web into dialog box, or
- manually inspect contents of MANIFEST file
- verify version number
This is tedious and painful, but if you encounter a [non-trivial] dll inconsistency error, this is the only way to find it.
Recommended Solution
- Ensure your solution is using soft references where applicable,
- expand Mcrcsip.Amwa.CrFactory
- expand References
- remove reference Mcrcsip.Amwa.Core
- open Add References dialog
- open Mcrcsip.Amwa.Core from Projects tab
- expand Mcrcsip.Amwa.PdfFormHandler
- expand References
- remove reference Mcrcsip.Amwa.Core
- open Add References dialog
- open Mcrcsip.Amwa.Core from Projects tab
- expand Mcrcsip.Amwa.Web
- expand References
- remove reference Mcrcsip.Amwa.Core
- remove reference Mcrcsip.Amwa.CrFactory
- remove reference Mcrcsip.Amwa.PdfFormHandler
- open Add References dialog
- open Mcrcsip.Amwa.Core from Projects tab
- open Mcrcsip.Amwa.CrFactory from Projects tab
- open Mcrcsip.Amwa.PdfFormHandler from Projects tab
- expand Mcrcsip.Amwa.CrFactory
- Ensure your solution is using fresh hard references where applicable,
- expand Mcrcsip.Amwa.Core
- expand References
- remove reference Mcrcsip.Aws.Bol
- remove reference Mcrcsip.Common
- remove reference Mcrcsip.Web
- open Add References dialog
- open Mcrcsip.Aws.Bol from Browse tab [always best to specify location]
- open Mcrcsip.Common from Browse tab
- open Mcrcsip.Web from Browse tab
- expand Mcrcsip.Amwa.CrFactory
- expand References
- remove reference Mcrcsip.Web
- open Add References dialog
- open Mcrcsip.Web from Browse tab
- expand Mcrcsip.Amwa.PdfFormHandler
- expand References
- remove reference Mcrcsip.Web
- open Add References dialog
- open Mcrcsip.Web from Browse tab
- expand Mcrcsip.Amwa.Web
- expand References
- remove reference Mcrcsip.Aws.Bol
- remove reference Mcrcsip.Common
- remove reference Mcrcsip.SharePoint
- remove reference Mcrcsip.Web
- open Add References dialog
- open Mcrcsip.Aws.Bol from Browse tab
- open Mcrcsip.Common from Browse tab
- open Mcrcsip.SharePoint from Browse tab
- open Mcrcsip.Web from Browse tab
- expand Mcrcsip.Amwa.Core
- Build
If you still encounter errors at this step, then you know that one or all of
- Mcrcsip.Aws.BOL
- Mcrcsip.Common
- Mcrcsip.SharePoint
shares your dependency on Mcrcsip.Web, and is referencing the old version. If this is the case, then for each hard reference listed above
- select a reference
- press F4
- copy contents from Path property
- open file dialog in
ildasm
- paste into File name
- inspect MANIFEST
Make sure you do this for each and every one of the three hard references above. once you identify which subset of those three are referencing the old version of Mcrcsip.Web, you may now find that project, update its hard reference, rebuild it, and then finally update your hard reference, rebuild, and voila. Bob's your uncle.
Phew.
Le fin
PS apologies for verbosity. this isn't a terribly complex problem, but as i am sure you would agree, it involves a lot of detail. i really hope this helps. thanks for your co-operation too :)
PPS btw, i am inferring from your comments that original developer used hard references everywhere [ie even within same solution]. perhaps he had his reasons, but imo, that is ass.
If you right-click the reference, go to properties, what is "Specific Version" set to? Make sure that it is set to 'True' and the version listed is indeed 2.0.x.
In the properties page, double-check the path. You might have a different version registered elsewhere in your GAC that is getting precedence. Use "gacutil -l " in the command line to get a list of all registered versions of that assembly. If you see duplicates with different keys, use gacutil to nuke the one you don't want.
Watch the build other under the Batch Build options. This will let you prioritize what assembly to build first, then dependencies shall get their DLL as required in the proper order.
精彩评论