Mon
Jan 25
2010

Find Conflicting Assembly References

A small test to help resolve the compiler warning:

warning MSB3247: Found conflicts between different versions of the same dependent assembly.

Point it to the build folder of your project and it will look for referenced assemblies with the same short name but different full names.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
 
namespace MyProject
{
    [TestFixture]
    public class UtilityTest
    {
        [Test]
        public void FindConflictingReferences()
        {
            var assemblies = GetAllAssemblies(@"E:\dev\myapp\myproject\bin\debug");
 
            var references = GetReferencesFromAllAssemblies(assemblies);
 
            var groupsOfConflicts = FindReferencesWithTheSameShortNameButDiffererntFullNames(references);
 
            foreach (var group in groupsOfConflicts)
            {
                Console.Out.WriteLine("Possible conflicts for {0}:", group.Key);
                foreach (var reference in group)
                {
                    Console.Out.WriteLine("{0} references {1}",
                                          reference.Assembly.Name.PadRight(25),
                                          reference.ReferencedAssembly.FullName);
                }
            }
        }
 
        private IEnumerable<IGrouping<string, Reference>> FindReferencesWithTheSameShortNameButDiffererntFullNames(List<Reference> references)
        {
            return from reference in references
                   group reference by reference.ReferencedAssembly.Name
                       into referenceGroup
                       where referenceGroup.ToList().Select(reference => reference.ReferencedAssembly.FullName).Distinct().Count() > 1
                       select referenceGroup;
        }
 
        private List<Reference> GetReferencesFromAllAssemblies(List<Assembly> assemblies)
        {
            var references = new List<Reference>();
            foreach (var assembly in assemblies)
            {
                foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
                {
                    references.Add(new Reference
                    {
                        Assembly = assembly.GetName(),
                        ReferencedAssembly = referencedAssembly
                    });
                }
            }
            return references;
        }
 
        private List<Assembly> GetAllAssemblies(string path)
        {
            var files = new List<FileInfo>();
            var directoryToSearch = new DirectoryInfo(path);
            files.AddRange(directoryToSearch.GetFiles("*.dll", SearchOption.AllDirectories));
            files.AddRange(directoryToSearch.GetFiles("*.exe", SearchOption.AllDirectories));
            return files.ConvertAll(file => Assembly.LoadFile(file.FullName));
        }
 
        private class Reference
        {
            public AssemblyName Assembly { get; set; }
            public AssemblyName ReferencedAssembly { get; set; }
        }
 
    }
}
Mon
Apr 6
2009

Resharper live templates for NUnit

aae       Assert.AreEqual
aane      Assert.AreNotEqual
aif       Assert.IsFalse
ait       Assert.IsTrue
ain       Assert.IsNull
ainn      Assert.IsNotNull
setup     NUnit [Setup] method
teardown  NUnit [TearDown] method
test      NUnit [Test] method

For ReSharper 3.0

For ReSharper 4.5

Sun
Aug 31
2008

Build ASP.NET WebService from the Command-line

This NAnt target will build the project into a new folder with a (single) precompiled DLL. All source files and other non-deployment files are removed.

<target name="publish.webservice">
    <exec basedir="."
          program="${msbuild.exe}"
          commandline=" ${web.project.file}
                        /nologo
                        /p:OutDir=${publish.webservice.dir}bin
                        /p:WebProjectOutputDir=${publish.webservice.dir}"
          workingdir="."
          failonerror="true" />
</target>
Mon
Jun 25
2007

HttpContext.Cache vs. HttpContext.Items

HttpContext.Cache is simply a pointer the HttpRuntime.Cache also known as the application cache. This can be verified by opening System.Web with Reflector. The MSDN documentation for this member is misleading: “Gets the Cache object for the current HTTP request”. Information stored here is global to the application domain, not a specific request.

To store per-request information use HttpContext.Items.

Fri
Apr 20
2007

Impersonate User

/// <summary>
/// Impersonate a user within the current thread.
/// This class will automatically revert the user to the original user 
/// identity when this class is disposed. Use this class with the 
/// C# using or a try/catch block to ensure the user is reverted
/// after an exception.
/// 
/// Suggested usage:
/// using (new ImpersonateHelper("domain", "joe", "password"))
/// {
///     ...code to run as joe
/// }
/// ...code to run as orignial user
/// 
/// Note, this implementation is vulnerable to "exception filter" attacks
/// as described below. Evaluate it against the risk of other attacks
/// such as the credential store used to impersonate.
/// http://blogs.msdn.com/shawnfa/archive/2005/03/22/400749.aspx
/// </summary>
public class ImpersonationHelper : IDisposable
{
    IntPtr m_tokenHandle = new IntPtr(0);
    WindowsImpersonationContext m_impersonatedUser;
 
    #region Win32 API Declarations
 
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;    //This parameter causes LogonUser to create a primary token.
 
    [DllImport("advapi32.dll", SetLastError=true)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, 
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
 
    [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);
 
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, 
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
 
    #endregion
 
    /// <summary>
    /// Constructor. Impersonates the requested user. Impersonation lasts until
    /// the instance is disposed.
    /// </summary>
    public ImpersonationHelper(string domain, string user, string password)
    {
        // Call LogonUser to obtain a handle to an access token.
        bool returnValue = LogonUser(user, domain, password,
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
            ref m_tokenHandle);
        if (false == returnValue)
        {
            int ret = Marshal.GetLastWin32Error();
            throw new System.ComponentModel.Win32Exception(ret);
        }
 
        // Impersonate
        m_impersonatedUser = new WindowsIdentity(m_tokenHandle).Impersonate();
    }
 
    #region IDisposable Pattern
 
    /// <summary>
    /// Revert to original user and cleanup.
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Revert to original user identity
            if (m_impersonatedUser != null)
                m_impersonatedUser.Undo();
        }
 
        // Free the tokens.
        if (m_tokenHandle != IntPtr.Zero)
            CloseHandle(m_tokenHandle);
    }
 
    /// <summary>
    /// Explicit dispose.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    /// <summary>
    /// Destructor
    /// </summary>
    ~ImpersonationHelper()
    {
        Dispose(false);
    }
 
    #endregion
}
Tue
Apr 17
2007

Log4Net + ASP.Net

In web applications, Log4Net’s ThreadContext properties (typically items like the current user) should be set immediately before each logging call.

Normally these properties are set in Global.Session_Start(). However, log4net internally stores these properties in thread local storage. Using Reflector to disassemble log4net.dll (v1.2.10), start with log4net.ThreadContext which leads to ThreadContextProperties.get_Item() and then to ThreadContextProperties.GetProperties(). The disassembly for this method:

internal PropertiesDictionary GetProperties(bool create)
{
    PropertiesDictionary data;
    data = (PropertiesDictionary) Thread.GetData(s_threadLocalSlot);
    if ((data == null) && create)
    {
        data = new PropertiesDictionary();
        Thread.SetData(s_threadLocalSlot, data);
    }
    return data;
}

The call to Thread.GetData() is the problem. ASP.Net, when under load, may switch threads when processing a single request (see ThreadStatic, CallContext and HttpContext in ASP.Net). You may initialize log4net with the current user on one thread, then attempt to log on a different thread. Log4net.LogicalThreadContext() suffers a similar problem as it uses CallContext to store its data rather than HttpContext.

For reliable logging information, set these ThreadContext properties each time you log an entry. The additional processing time will be negligable in most cases. Further, as a general rule of thumb, use HttpContext to store request-specific information in ASP.Net applications.

10 minutes after finishing this post I come across this post, also from piers7:
log4net Context problems with ASP.Net thread agility. It suggests another workaround.

Sun
Mar 25
2007

Formatting File Sizes

In Windows Explorer file sizes are displayed in two different formats. In the Properties page, file sizes are displayed in bytes, KB, MB, GB or TB depending on the size. The StrFormatByteSize() Win32 API can reproduce this format. The second format is used under the “Size” column when viewing a folder. File sizes are displayed in whole KB with thousands separators. I have not found a API call to reproduce this format. The StrFormatKBSize() function is close but differs (it displays two decimal places).

Here are two pure C# functions to reproduce these formats:

/// <summary>
/// Converts a number value into a string that represents the number 
/// expressed in whole kilobytes. This is a format similar to the 
///	Windows Explorer "Size" column.
/// </summary>
public static string FileSizeToStringKB(long fileSize)
{
	return string.Format("{0:n0} KB", Math.Ceiling((double)fileSize / 1024));
}
 
 
/// <summary>
/// Converts a numeric value into a string that represents the number 
///	expressed as a size value in bytes, kilobytes, megabytes, gigabytes, 
///	or terabytes depending on the size. Output is identical to 
///	StrFormatByteSize() in shlwapi.dll. This is a format similar to 
/// the Windows Explorer file Properties page. For example:
///	     532 ->  532 bytes
///     1240 -> 1.21 KB
///	  235606 ->  230 KB
///  5400016 -> 5.14 MB
/// </summary>
/// <remarks>
///	It was surprisingly difficult to emulate the StrFormatByteSize() function
/// due to a few quirks. First, the function only displays three digits:
///  - displays 2 decimal places for values under 10	(e.g. 2.12 KB)
///  - displays 1 decimal place for values under 100	(e.g. 88.2 KB)
///	 - displays 0 decimal places for values under 1000	(e.g. 532 KB)
///	 - jumps to the next unit of measure for values over 1000  (e.g. 0.97 MB)
/// The second quirk: insiginificant digits are truncated rather than 
/// rounded. The original function likely uses integer math.
/// This implementation was tested to 100 TB.
/// </remarks>
public static string FileSizeToString(long fileSize)
{
	double value;
	string unit;
 
	if (fileSize < 1024)
	{
		return string.Format("{0} bytes", fileSize);
	}
	else 
	{
		value = fileSize;
		value = value / 1024;
		unit = "KB";
		if (value >= 1000)
		{
			value = Math.Floor( value );
			value = value / 1024;
			unit = "MB";
		}
		if (value >= 1000)
		{
			value = Math.Floor( value );
			value = value / 1024;
			unit = "GB";
		}
		if (value >= 1000)
		{			value = Math.Floor( value );
			value = value / 1024;
			unit = "TB";
		}
 
		if (value < 10)
		{
			value = Math.Floor( value * 100 ) / 100;
			return string.Format("{0:f2} {1}", value, unit);
		}
		else if (value < 100)
		{
			value = Math.Floor( value * 10) / 10;
			return string.Format("{0:f1} {1}", value, unit);
		}
		else
		{
			value = Math.Floor( value * 1) / 1;
			return string.Format("{0:f0} {1}", value, unit);
		}
	}
}
Fri
Jan 19
2007

CLR Debugging

To get started with debugging the CLR see Tess Ferrandez’s post on getting .NET memory dumps and Associating Windbg with .dmp files. See her other posts for mining these dumps for useful information.

To debug ASP.Net worker process crashes, create a batch file named debug_crash_iis5.bat in windbg folder with:
cscript.exe adplus.vbs -crash -pn aspnet_wp.exe -FullOnFirst

To dump (non-crashing) exceptions from ASP.Net, create a batch file named debug_monitor_iis5.bat with:
cscript.exe adplus.vbs -pn aspnet_wp.exe -c TrackCLR.cfg

and another file named TrackCLR.cfg with:

<ADPLUS>
  <SETTINGS>
   <RUNMODE>CRASH</RUNMODE>
  </SETTINGS>
  <PRECOMMANDS>
   <CMD>!load clr10\sos</CMD>
  </PRECOMMANDS>
  <EXCEPTIONS>
   <OPTION>NoDumpOnFirstChance</OPTION>
   <OPTION>NoDumpOnSecondChance</OPTION>
   <CONFIG><!-- This is for the CLR exception -->
    <CODE>clr</CODE>
    <ACTIONS1>Log</ACTIONS1>
    <CUSTOMACTIONS1>!cen;!clrstack;.dump /ma /u c:\exceptiondump.dmp;gn </CUSTOMACTIONS1>
    <RETURNACTION1>GN</RETURNACTION1>
   </CONFIG>
  </EXCEPTIONS>
</ADPLUS>

After opening a .dmp file with windbg, the most useful commands are:
!clrstack
!dae
!help

Thu
Jan 11
2007

Catching Unhandled ASP.Net Exceptions

Exceptions that occur off the worker process thread are silently swallowed by ASP.NET 1.1. Use the method described in MS article 911816 to create an HttpModule to catch the exceptions. The follow is adapted for ASP.NET 1.1 without requiring registration in the GAC and a strong name. It also logs to the EventLog as well as sending an email as

Add the following code to UnhandledExceptionModule.cs:

using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Web;
 
namespace WebMonitor {
    public class UnhandledExceptionModule: IHttpModule {
 
        static int _unhandledExceptionCount = 0;
 
        static string _sourceName = null;
        static object _initLock = new object();
        static bool _initialized = false;
        static string _mailServer = "mymailserver";
        static string _mailTo = "abc@xyz.com";
 
        public void Init(HttpApplication app) {
 
            // Do this one time for each AppDomain.
            if (!_initialized) {
                lock (_initLock) {
                    if (!_initialized) { 
 
                        _sourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0",
							System.Environment.Version.Major, 
							System.Environment.Version.Minor,
							System.Environment.Version.Build);
 
                        if (!EventLog.SourceExists(_sourceName)) {
                            throw new Exception(String.Format(CultureInfo.InvariantCulture,
                                                              "There is no EventLog source named '{0}'.", 
                                                              _sourceName));
                        }
 
                        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
 
                        _initialized = true;
 
						LogMessage("UnhandledExceptionModule started", "", EventLogEntryType.Information);
 
                    }
                }
            }
        }
 
        public void Dispose() {
        }
 
        void OnUnhandledException(object o, UnhandledExceptionEventArgs e) {
            // Let this occur one time for each AppDomain.
            if (Interlocked.Exchange(ref _unhandledExceptionCount, 1) != 0)
                return;
 
            StringBuilder message = new StringBuilder("\r\n\r\nUnhandledException logged by UnhandledExceptionModule.dll:\r\n\r\nappId=");
 
            string appId = (string) AppDomain.CurrentDomain.GetData(".appId");
            if (appId != null) {
                message.Append(appId);
            }
 
            Exception currentException = null;
            for (currentException = (Exception)e.ExceptionObject; currentException != null; currentException = currentException.InnerException) {
                message.AppendFormat("\r\n\r\ntype={0}\r\n\r\nmessage={1}\r\n\r\nstack=\r\n{2}\r\n\r\n",
                                     currentException.GetType().FullName, 
                                     currentException.Message,
                                     currentException.StackTrace);
            }           
 
			LogMessage("UnhandledExceptionModule exception", message.ToString(), EventLogEntryType.Error);
        }
 
		void LogMessage(string subject, string message, EventLogEntryType severity)
		{
			try
			{
				EventLog Log = new EventLog();
				Log.Source = _sourceName;
				Log.WriteEntry(subject + "\n" + message, severity);
			}
			catch  {}
			try
			{
				System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage();
				msg.Body = message;
				msg.To = _mailTo;
				msg.Subject = severity.ToString() + ": " + subject;
				msg.From = _mailTo;
 
				System.Web.Mail.SmtpMail.SmtpServer = _mailServer;
				System.Web.Mail.SmtpMail.Send(msg);
			}
			catch {}
		}
 
    }
}

Open a Visual Studio Command Prompt and run: csc /t:library /r:system.web.dll,system.dll UnhandledExceptionModule.cs

Place the DLL in your bin folder

Add following to your web.config:

<system.web>
  <httpModules>
    <add type="WebMonitor.UnhandledExceptionModule, UnhandledExceptionModule" name="UnhandledExceptionModule"/>
  </httpModules>
</system.web>

Here is sample code to trigger an unhandled exception

using System.Threading;
Timer t;
private void btnTest_Click(object sender, System.EventArgs e)
{
  t = new Timer(new TimerCallback(t_Elapsed), null, 250, Timeout.Infinite);
}
private void t_Elapsed(object state)
{
  throw new Exception("My unhandled exception");
}
Wed
Jan 3
2007

VSS Best Practices

Team Development with Visual Studio .NET and Visual SourceSafe

Older Posts »

© 2009 Brian Low. All rights reserved.