Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
452 views
in Technique[技术] by (71.8m points)

.net - ASP.Net error: “The type ‘foo’ exists in both ”temp1.dll“ and ”temp2.dll" (pt 2)

Solution:

I had also moved ashx and asmx files at the same time as this. The Class attribute of the WebService/WebHandler directives were pointed at the wrong namespace. The moral of the story is to make sure you view the markup for all as*x files you change the namespace for by right-clicking on them and choosing "View Markup".


I'm experiencing the same problem as in this question and this link, but none of the answers fixed my problem. (edit: Setting the web.config batch attribute works, but that's a coverup, not a solution)

The problem I'm having is with a User Control that I moved from the root directory to a subdirectory within the same Web Application project. It used to work fine before I moved it. When I moved it it started giving me the error message.

It's saying that the class name exists in two dll files in Temporary ASP.NET Files. Sure enough, when I open Reflector, it's in two dlls.

If I rename the class and ascx file, everything works fine. No usages of the original name exist within any of the files in my entire application. When I rename the file, I opened all of the dll files in Temporary ASP.NET Files with Reflector, and no references to the original class name exists.

So where's this phantom reference coming from how can I fix this?

Update: I literally grepped every file in my working directory for the solution and my temp directory for the old class name and deleted every file that contained it. I then renamed back to the original, broken name and I still get the error.

Server Error in '/' Application. Compilation Error Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error ssage: CS0433: The type 'ASP.dashboard_badusercontrol_ascx' exists in both 'c:Docunts and SettingsmeLocal SettingsTempTemporary ASP.NET Files oot3c2b7e1f2e8a7620App_Web_badusercontrol.ascx.a57ad085.iljdmp1p.dll' and 'c:Docunts and SettingsmeLocal SettingsTempTemporary ASP.NET Files oot3c2b7e1f2e8a7620App_Web_bhdqaimy.dll'

Source Error:

Line 1098: Line 1099:
[System.Diagnostics.DebuggerNonUserCodeAttribute()] Line 1100: private global::ASP.dashboard_badusercontrol_ascx @__BuildControlMyBadUserControl() { Line 1101:
global::ASP.dashboard_badusercontrol_ascx @__ctrl; Line 1102:

Source File: c:Docunts and SettingsmeLocal SettingsTempTemporary ASP.NET Files oot3c2b7e1f2e8a7620App_Web_foo.aspx.a57ad085.1nw6dais.0.cs Line: 1100


Edit: Ok, so I did some more testing on what works and doesn't work. Let's say the original file name was "BadUserControl.ascx" in namespace "MyNamespace".

I moved the file to a directory called "NewDirectory" and changed the namespace to "MyNamespace.NewDirectory". There are no copies of "BadUserControl.ascx" anywhere else on my HDD. I double-checked my TFS history to ensure the ONLY difference is the addition of ".NewDirectory" to the namespace in the markup and code-behind files.

Inside of this namespace are two other user controls named "OtherUserControl" and "AnotherUserControl".

This situation fails: I have 2 Register directives:

<%@ Register src="BadUserControl.ascx" tagname="BadUserControl" tagprefix="uc1" %> 
<%@ Register src="OtherUserControl.ascx" tagname="OtherUserControl" tagprefix="uc2" %>

These situations work:

  1. I keep "BadUserControl.ascx" named as is. I have 1 Register directive on a page in the same namespace:

    <%@ Register src="BadUserControl.ascx" tagname="BadUserControl" tagprefix="uc1" %>
    
  2. I change "BadUserControl.ascx" to "GoodUserControl.ascx" I have 2 Register directives:

    <%@ Register src="GoodUserControl.ascx" tagname="GoodUserControl" tagprefix="uc1" %>
    <%@ Register src="OtherUserControl.ascx" tagname="OtherUserControl" tagprefix="uc2" %>
    
  3. 2 Register directives without BadUserControl.ascx at all:

    <%@ Register src="AnotherUserControl.ascx" tagname="AnotherUserControl" tagprefix="uc1" %>
    <%@ Register src="OtherUserControl.ascx" tagname="OtherUserControl" tagprefix="uc2" %>
    
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

UPDATE: ok, as you found, the circular reference was the wrong guess, as there are other situation that may cause similar behavior.

The more general way to describe the problem is that batching at runtime works in a very permissive way which can mask problems. Basically, we try to batch everything in one folder, but if we get a compile error when compiling that batch, we fall back to individual file compilation. In many cases that works fine, but sometimes, this can lead to a given page getting compiled twice (similar to what I described below, but for a different reason).

On the other hand, aspnet_compiler works in a strict way, where if batching fails it fails altogether and does not fall back. That's why running this tool is a great way to locate various type of issues (or latent issues) that can be far from obvious at runtime. I guess we didn't do a good job evangelizing this tool for this purpose :)

As for why renaming the file fixed it, this may be caused by it changing the ordering in which files are processed, which is a bit arbitrary. It may be that if you rename it to something else, you'll see it happen again.

Frankly, looking back I kind of wish we had made this batching behavior strict at runtime, to catch those situations earlier. The reason we chose the current fall back design was to avoid failing whenever possible, but this came with a price: when something is wrong, it's a pain to catch it :)


ORIGINAL ANSWER: In short, the problem is that when batching is turned on (and it is by default), you should avoid having directory level circular dependencies. Let me explain what I mean by that.

Here is an example. Say you have:

  • In folder1: page.aspx and uc2.ascx
  • In forder2: uc1.ascx

And say that page.aspx references uc1.ascx (via a @register directive), and that uc1.ascx references uc2.ascx. At the file level, that’s perfectly fine, but at the directory level, there is a circular dependency: folder1 references something in folder2, which references something in folder1.

Why this is problematic has to do with how batching works: when you request the page, it first tries to compile everything in folder1 together. But since folder1/page.aspx references folder2/uc1.ascx, it needs to compile folder2 before it can do folder1. But then uc1 uses uc2, meaning it must first do folder1! At this point, ASP.NET detects the situation and tries to make the best of it by compiling uc2.asc by itself. While this allows some scenarios to work, it can also cause weird things because some items end up compiled in two assemblies. Here, uc2.ascx would be both compiled by itself and with the folder1 batch.

There is actually a way to easily detect if your site has such folder level circular dependencies. From a VS console window, go to the root of your site and run:

aspnet_compiler -v foo -p .

If you have folder level circular dependencies, you’ll get some errors that look like:

/foo/Sub/UC1.ascx(2): error ASPPARSE: Circular file references are not allowed.

The cheap way to avoid this issue is what you already know: disable batching. Now at least you know why that works :)

But the better thing to do if you can is to avoid the folder level circular dependencies. If you start thinking of each folders as a ‘component’ which produces an assembly, that actually makes sense, and can help make the pieces of your site more modular.

Yes, it’s also fair to call this a ‘bug’ in the compilation system, or at least a limitation. But once you’re aware of it, it’s fairly easy to avoid.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...