piątek, 5 marca 2010

Debugging Assembly Loading Failures

Debugging Assembly Loading Failures

So...you're seeing a FileNotFoundException, FileLoadException, BadImageFormatException or you suspect an assembly loading failure? Try the steps below to start your debugging process.

First, get the Message property from the exception. If the exception's InnerException property is set, get the Message property from that. If the message is generic, also get the hresult by calling System.Runtime.InteropServices.Marshal.GetHRForException(), passing in the Exception object. If that info is not readily available, you may need to attach a debugger and set it to catch managed exceptions. Then, get the hresult by retrieving the private _HResult field of the managed Exception object.

Retrieving the Fusion log

If the exception message isn t enough for you to determine what the problem is, try getting the Fusion log. It will describe the binding failure (if this is due to an assembly binding failure, instead of a loading failure after the file is found). The exception may already include the log. If not, to get it, run fuslogvw.exe. If you don't have fuslogvw.exe already, install the Framework SDK.

  • For pre-v2.0: click on "Log Failures." If this is an ASP.NET or .NET Windows service app, select the Custom option and using regedit, set [HKLM\Software\Microsoft\Fusion\LogPath] to point to an existing directory (like c:\mylogs, not c:\). If you need to log all binds, not just failing ones, set [HKLM\Software\Microsoft\Fusion\ForceLog] as a DWORD value to 1.
  • For v2: click on "Settings," then choose "Log bind failures to disk" if you only care about the failures or "Log all binds to disk" if you want to see all binding requests.
  • To turn on failure logging during a test run instead of by hand, have your script set [HKLM\Software\Microsoft\Fusion\LogFailures] as a DWORD value to 1 using regedit.

Then, click "OK." Now, re-run the process. Next, click "Refresh" in fuslogvw, and a line should appear for each binding failure (or for each bind, if ForceLog is set). Now, double-click on the line in the "Application" column for the interesting bind, and a web page should come up with the Fusion log.

If the file was found, it was loaded from the last path probed in the log (or from the GAC, if there is no probed path shown).

Note: Unless you are explicitly debugging the failure of a resource to load, you will likely want to ignore failures to find assemblies with the ".resources" extension with the culture set to something other than "neutral". Those are expected failures when the ResourceManager is probing for satellite assemblies.

Troubleshooting Fusion logging

Keep in mind that there may not be any entries if there were no binds or if there were no binding failures (when logging failures only). (And don't forget to restart your application's process after changing logging settings.) If there are not as many entries as you expect, you may need to clear your download cache to make room for them. To do that, in Internet Explorer, choose “Tools“, “Internet Options“, “Delete Files”, “OK“, then re-run your app and finally click “Refresh“ again in fuslogvw.

There is only one Fusion log saved per display name/codebase. So, if the same exact reference is requested twice in the same process, it will only show up once in fuslogvw. To see the duplicate logs, you'll need to stop execution (for example, with breakpoints in your debugger) and then get the log at that time.

For FileNotFoundException:
At the bottom of the log will be the paths that Fusion tried probing for this assembly. If this was a load by path (as in Assembly.LoadFrom()), there will be just one path, and your assembly will need to be there to be found. Otherwise, your assembly will need to be on one of the probing paths listed or in the GAC if it's to be found.

You may also get this exception if an unmanaged dependency or internal module of the assembly failed to load. Try running depends.exe on the file to verify that unmanaged dependencies can be loaded. Note that if you re using ASP.NET, the PATH environment variable it's using may differ from the one the command line uses. If all of them could be loaded, try ildasm.exe on the file, double-click on "MANIFEST" and look for ".file" entries. Each of those files will need to be in the same directory as the manifest-containing file.

For BadImageFormatException:
Try running peverify.exe on the file. That will give a more specific description about why it s considered a bad image. Keep in mind that modules built against v2 can not be loaded by a pre-v2 CLR.

For SecurityException:
You need Execute permission for loading any assembly. Also, if a codebase was used to load this file, you would need both FileIOPermission.Read and FileIOPermission.PathDiscovery or else WebPermission to the location (depending on whether this is a local file or a URL). Try caspol.exe to check your managed security settings.

For FileLoadException:

For an "Access is denied" message (for hresult E_ACCESSDENIED, 0x80070005):
Run tlist -m on the file to see if another process has the file locked and without share-read access. If not, check the ACLs for the file and its dependencies (especially if you're using impersonation).

For a "The located assembly's manifest definition with name [yourAssembly] does not match the assembly reference" message (for hresult FUSION_E_REF_DEF_MISMATCH, 0x80131040):
The Fusion log will say which part of the assembly reference failed to match what was found. It will be the assembly name, culture, public key (or token) or version (if the found assembly was strongly-named).

For "Unverifiable image [yourAssembly] can not be run" or "Can not run executable [yourAssembly] because it contains relocations" messages (for hresult COR_E_FIXUPSINEXE, 0x80131019):
That image must be run as the process exe or else be compiled as a dll. This is because MC++ has made optimizations for you in your image, based on the assumption that it will be the process exe. If it's not the process exe, it won t be loaded at the expected location, so the assumed offsets will be incorrect. When the CLR sees such a file loaded as a non-process exe, it will reject the load.

Published Thursday, May 29, 2003 2:09 PM by Suzanne Cook Filed under:

AppDomain and Shadow Copy

AppDomain and Shadow Copy

.Net Framework has a feature called Shadow Copy. When shadow copy is enabled on an appdomain, assemblies loaded in that appdomain will be copied to a shadow copy cache directory, and will be used from there. This is great because the original file is not locked. So it can be changed at will. ASP.NET uses this extensively. Actually, shadow copy is enabled on every appdomain created by ASP.NET.

This feature is implemented by fusion.

Unfortunately the documentation for shadow copy is rather poor. MSDN has documentation on various things affecting shadow copy. But it does not discuss the detail of shadow copy feature. This post is an attempt to discuss in detail how shadow copy works.

All the discussion is based on AppDomainSetup class unless specified.

There are three things affecting shadow copy:

  1. How to enable shadow copy?
  2. What will be shadow copied?
  3. Where do shadow copied bits go?

1. How to enable shadow copy?

MSDN says it all. Set AppDomainSetup.ShadowCopyFiles to true will enable shadow copy.

2. What will be shadow copied?

AppDomainSetup.ShadowCopyDirectories controls what will be shadow copied. It is a list of directory names, separated by a semicolon. Each directory name should be absolute directory path. Assemblies loaded from those directories will be shadow copied. If ShadowCopyDirectories is null, all assemblies will be shadow copied. (An interesting corner case is what if ShadowCopyDirectories is empty string. I’ll leave this as an exercise for the readers. What do you think the behavior will be?)

3. Where do shadow copied bits go?

AppDomainSetup.CachePath + AppDomainSetup.ApplicationName control where shadow copied bits go. If both CachePath and ApplicationName are set, shadow copied bits will go to CachePath\ApplicationName. Otherwise shadow copied bits will go to your download cache (which is stored in %userprofile%\local settings\application data\assembly). The combination of CachePath and ApplicationName is really handy for ASP.NET, because they can set a common CachePath, and have each application shadow copy to a different location.

You are responsible to clean up the shadow copy cache if you set CachePath+ApplicationName. In the case of download cache as shadow copy cache, it is automatically managed by fusion.

On the default appdomain you cannot change its AppDomainSetup. But you can use AppDomain’s API to change the properties. The relevant APIs are:

SetCachePath, SetShadowCopyFiles, SetShadowCopyPath (the name of this one is not consistent with AppDomainSetup.ShadowCopyDirectories). The ApplicationName is set to the name of the application on default domain.


http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx


piątek, 9 października 2009

English

unfettered - nieskrępowany, swobodny
aware - świadomy
deflate - wypusczać
affect - oddziałowywać, wpływać
desire - pragnienie
emergence - pojawienie się, wyłonienie się
provide - zaspokajać potrzeby, umożliwać
presence - obecność
foist - narzucać
regardless - bez względu, niezależnie
effort - staranie, wysiłek

poniedziałek, 24 sierpnia 2009

Best Practices for Speeding Up Your Web Site

http://developer.yahoo.com/performance/rules.html

poniedziałek, 17 sierpnia 2009

Kiedy ViewState jest zapisywany, a kiedy odtwarzany

Kiedy ViewState jest zapisywany, a kiedy odtwarzany

ViewState zapisywany jest zawsze po zdarzeniu Page_Load (i ewentualnym wykonaniu wszystkich zdarzeń postbacku), przed fazą Render. Oznacza to, że ostatnim miejscem, w którym możemy dokonać zmiany wartości zapisywanych w ViewState jest zdarzenie Page_PreRender. Przed zrenderowaniem strony rekurencyjnie zapisywany jest stan wszystkich kontrolek na stronie, tak aby mógł zostać przesłany jako ukryte pole.

Odtwarzanie ViewState’u występuje tylko przy postbacku, zaraz po inicjalizacji (Page_Init) – dzięki temu w Page_Load mamy już zawsze odtworzony stan strony z ostatniego żądania. Należy pamiętać, że w zdarzeniu Page_Init nie można odczytywać ani wpisywać niczego do ViewState’u – nie jest on jeszcze odtworzony.

poniedziałek, 23 lutego 2009

enum DisplayText

http://www.west-wind.com/weblog/posts/632732.aspx

I usually don't like to use enum values as display content.
Using a custom DisplayText attribute on the enum value that is
extracted in the UI is IMHO more flexible and less code. :-)

public enum BugStatusTypes
{
[DisplayText(Text = "Entered")]
Entered,
[DisplayText(Text = "In Process")]
InProcess,
Fixed,
ByDesign,
NotReproducible,
NoBug,
None
}


Often times this will save some cross assembly refactorings that would
arise as the display text needs to be changed.

You
can then extract the display text with a simple method. (Making it an
extension methods enables calling it directly off the enum value)
public static string GetDisplayText(this Enum enumValue)
{
var type = enumValue.GetType();
MemberInfo[] memberInfo = type.GetMember(enumValue.ToString());

if (memberInfo == null || memberInfo.Length == 0)
return enumValue.ToString();

object[] attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayTextAttribute), false);
if (attributes == null || attributes.Length == 0)
return enumValue.ToString();

return ((DisplayTextAttribute)attributes[0]).Text;
}


The calling code is dead simple.

string displayValue = BugStatusTypes.Entered.GetDisplayText();



The custom attribute
public class DisplayTextAttribute : Attribute
{
public string Text { get; set; }
}


What do you think?

czwartek, 22 listopada 2007

Failed To Create AppDomain

Failed To Create AppDomain

I was playing around with Visual Studio Whidbey last night and had been altering my CAS security policy. I tested what I wanted and forgot all about it.

This morning, I came to play with some of my ASP.NET demo projects and found that when I ran up the local web server I couldn't get any page to display whatsoever (everything was coming back with a "page not found").

I couldn't understand this at all and (having the memory of a goldfish) it took me ages to get back to the point where I worked out when things had last been working and when they'd stopped. I could see in the VS debugger that when the little Visual Web Developer Web Server was coming up it was throwing a "Failed to create AppDomain" exception but I couldn't for the life of me think why that might be given that it'd been working fine up until about half a day ago.

After staring at it for a while I thought a bit about what might go wrong with creating an AppDomain and security suddenly hit me and I remembered that I'd tweaked with my settings last night.

A quick;

caspol -s off

showed me that I could now run up pages in the Web Developer Web Server and a quick

caspol -reset

fixed the problem.

One to bear in mind should you find this page whilst searching for "Failed to create AppDomain".