Tuesday, September 15, 2009

IIS7 64Bit Hang Dump.. The hard way


So I have done so many searches and have not been able to find a half decent way to get a dump when IIS7 running 64bit has hung. DebugDiag even the updated one might run on a 64bit machine but does not seem capable of generating a 64bit crash dump file. The documentation on this subject is pretty poor on the 64b aspect of IIS7 running asp.net. That being said here is how I solved the problem if anyone has a better solution I would love to hear it.


The best solution I have found is to install the debugging tools on the target machine. Then use the code below in a powershell script and run the script in your console session adjust the interval or the time out as needed for your circumstance.


$interval = 2;
$timeout = 15;
$url = 'http://www.mywebsite.com'
$command =
$client = New-Object Net.WebClient;
$client.CachePolicy = New-Object Net.Cache.RequestCachePolicy([Net.Cache.RequestCacheLevel]::NoCacheNoStore);
Write-Host "Begin Monitoring $url";
$elapsed = $null;
$interval = New-Object System.TimeSpan(0,0,0,$interval,0);
do
{
Write-Host "Waiting for next test cycle in $interval"
[System.Threading.Thread]::Sleep($interval);
$started = [System.DateTime]::Now.Ticks;
$client.QueryString['t'] = $started;
$response = $client.DownloadString($url);
$ended = [System.DateTime]::Now.Ticks;
$elapsed = New-Object System.TimeSpan($ended - $started);
Write-Host "$url completed in $elapsed"
}
while ($timeout -gt $elapsed.Seconds)
if($timeout -lt $elapsed.Seconds)
{
$ended = [System.DateTime]::Now;
Write-Host "Dumping All Worker Processes at $ended";
&'C:\Program Files\Debugging Tools for Windows (x64)\dumphangw3wp.cmd'
}

Content of dumphangw3wp.cmd


cscript.exe "C:\Program Files\Debugging Tools for Windows (x64)\ADPlus.vbs" -hang -pn w3wp.exe -o "C:\Dump Files" -quiet

Thursday, July 30, 2009

Using a builder like pattern with MVC Helper Methods

The Microsoft MVC framework is a powerful new technology but after some work I found the helper extension methods to be a little restrictive. While creating copious methods with overloads it dawned on me a string builder like pattern could be used
Here is a pseudo code example what was implemented.


//Example of builder class
using System.Web.Mvc;
public class InlineTagBuilder : TagBuilder, IHelperBuilder
where T : InlineTagBuilder
{
public InlineTagBuilder(HtmlHelper helper, string tagName, TagRenderMode mode)
: base(tagName)
{

Helper = helper;
Mode = mode;
}

protected TagRenderMode Mode { get; private set; }

public HtmlHelper Helper { get; private set; }

new public T AddCssClass(string value)
{
base.AddCssClass(value);
return (T)this;
}

new public T MergeAttribute(string key, string value, bool replaceExisting)
{
base.MergeAttribute(key, value, replaceExisting);
return (T)this;
}

new public T MergeAttribute(string key, string value)
{
base.MergeAttribute(key, value, false);
return (T)this;
}

new public T MergeAttributes(IDictionary attributes, bool replaceExisting)
{
base.MergeAttributes(attributes, replaceExisting);
return (T)this;
}

new public T MergeAttributes(IDictionary attributes)
{
base.MergeAttributes(attributes, false);
return (T)this;
}

new public T SetInnerText(string innerText)
{
base.SetInnerText(innerText);
return (T)this;
}

public T AppendAttributeValue(string key, string right)
{
string left;
if (Attributes.TryGetValue(key, out left))
{
Attributes[key] = String.Concat(left, right);
}
else
{
Attributes.Add(key, right);
}
return (T)this;
}

public T InsertAttributeValue(string key, string left)
{
string right;
if (Attributes.TryGetValue(key, out right))
{
Attributes[key] = String.Concat(left, right);
}
else
{
Attributes.Add(key, left);
}
return (T)this;
}

public T AppendEvent(string name, string body)
{
return AppendAttributeValue(name, body);
}

public T InsertEvent(string name, string body)
{
return InsertAttributeValue(name, body);
}

public T AppendStyle(string value)
{
if (value != null && !value.EndsWith(";"))
{
value = String.Concat(value, ';');
}
return AppendAttributeValue("style", value);
}

public T SetId(string id)
{
return MergeAttribute("id", id, true);
}

public T SetTitle(string title)
{
return MergeAttribute("title", title, true);
}

public T SetInnerHtml(string innerHtml)
{
base.InnerHtml = innerHtml;
return (T)this;
}

public static implicit operator string(InlineTagBuilder builder)
{
return builder.ToString(builder.Mode);
}
}
public class AnchorTagBuilder : InlineTagBuilder
{
//Anchor Set Methods Here Each Method Returns This For Inline Stacking Of Method Calls...
}
//Add extension class for easy access from the helper in the view
public static class AnchorTagBuilderExtensions
{
public static AnchorTagBuilder Anchor(this HtmlHelper helper)
{
return new AnchorTagBuilder(helper);
}
}
//Example of what the view would look like
<html>
<body>

<%=Html.Anchor().MergeAttribute("href","http://www.microsoft.com").AddCssClass("footNote").AppendEvent("onclick","alert('Really Annoying Alert Box!')") %>

</body>
</html>

Tuesday, July 28, 2009

IIS7 Failed Request Tracing Not Writing Logs

Ran in to this today failed request tracing was enabled and showing up in the IIS Admin Console but no matter what I did the logs would not show up. It boils down to two different issues:

  1. The folder you are sending the logs to must have permissions set the app pool writing to the folder must have full control or at least write permission to the folder.
  2. And this is the gotcha, make sure you have the module in the applicationHost.config

    <globalmodules>
    ...
    <add name="FailedRequestsTracingModule" image="%windir%\System32\inetsrv\iisfreb.dll" precondition="bitness64"></add>
    ...
    </globalmodules>



Without that line in the config it will not log, there is nothing in the event log app log or www logs that will tell you its not there either.

Wednesday, July 22, 2009

Locking Multithreaded Unit Tests for Sequential Access In Visual Studio

As I mentioned in a prior post getting Visual Studio Unit tests to execute single threaded is impossible unless you want to write a replacement to the unit test runner. I have several tests that use remoting and rely on a pre-defined channel. When executing things in parallel this causes socket already in use errors. Because each test is executed in an isolated app domain using a lock on a static object wont work either. I have heard you can lock during class setup and teardown this may work due to some locking semantics in the Runner library but for those of you wanting the benefits of setting up and tearing down using class inheritance from a different assembly good luck no dice. I have chosen a very old school solution simply write a file to the unit test directory and use a mutex as a lock this works across multiple processes. Don't forget to test for the unexpected by protecting against an infinite loop Use a timeout to ensure the mutex is not infinitely held waiting for a stalled process.

public int TimeoutInSeconds { get; set; }

public string Name { get; private set; }

private Mutex Mutex
{
get
{
if (_mutex == null)
{
_mutex = new Mutex(false, Name);
}
return _mutex;
}
}

private string LockFileName
{
get
{
return String.Concat(Name, ".lock");
}
}

public override void Initialize(UnitTestBase test)
{
Mutex.WaitOne(new TimeSpan(0, 0, 0, TimeoutInSeconds, 0));
}

public override void Cleanup(UnitTestBase test)
{
Mutex.ReleaseMutex();
}


//Test Setup
long ticks = DateTime.Now.Ticks;
while (File.Exists(LockFileName))
{
Thread.Sleep(100);
if (TimeoutInSeconds > 0 && new TimeSpan(ticks - DateTime.Now.Ticks).Seconds >= TimeoutInSeconds)
{
throw new Exception(String.Format("Unable to obtain lock {0}", Name));
}
}
using (StreamWriter writer = File.CreateText(LockFileName))
{
writer.Write("Lock held by ");
writer.Write(test.GetType().FullName);
}
//Teardown
File.Delete(LockFileName);

Tuesday, July 21, 2009

Using Setup Scripts in For Visual Studio Unit Tests

I could not find much documentation on this so I thought I should post a quick overview of how to create setup scripts for Visual Studio. You specify the setup script in the testrunconfig file under "Setup and Cleanup Scripts" the script is relative to the solution file it applies to. When you run a unit test you will see a qtsetup.bat in the
TestResults\<TestName>
folder. Open the file and it will show you your script merged with the variables generated by the testing process very useful if you are looking for the Deployment Directory Path. The Setup Script is executed relative to the deployment dir folder or
TestResults\<TestName>\Out
in most cases.




One drawback to using deployment items is you cannot use wild cards in the includes. In my case this was a pretty big problem because my binaries are all in one folder, upwards of 500 files. As a work around I created a cmd file and executed a file copy instead this saved a huge amount of time when executing a unit test.

Debugging an external process through Microsoft Visual Studio Unit Test


An update to this article while the code is useful I did not end up using this because I was unable to control the process from within the unit test. Visual studio operates each unit test in an isolated app domain which makes it difficult to instantiate processes across the test run cycle. See my next post on how I have solved this particularity annoying problem. I have been met with an obstacle nearly every step of the way with the Visual Studio Unit tests. Had I not been switching to Teams I would abandon the whole thing and go back to NUnit which was a much more flexible framework.

Debugging a client server type model within Microsoft Visual Studio can be challenging when also trying to leverage the Microsoft Visual Studio Unit Test framework. The problem lies in the fact you cannot easily spin of a second process to host the server side communication and debug both processes at the same time. You will find that the debugger will only debug through the unit test or client side of the communication stack. After some research and testing I have found a way to launch and attach to a process within the unit test execution path without any extra foot work.
The following code will launch a process check to see if the code is within a debugging session then attempt to attach to that process. If you have been googleing you may have found that you can access the visual studio environment using:
(EnvDTE._DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE")

This is not the droid you are looking for, While this returns an instance of visual studio it may not be the executing instance you need to attach the debugging session to.
Thanks to Rick Strahl for publishing an article with the right COM+ incantations to retrieve all active instances the DTE I made some modifications for my purposes and viola! Something that seems like it should be so simple turns out to be quite tricky. The message filter was taken directly from the MSDN site to resolve issues with RPC_E_CALL_REJECTED message. I also as a side note I was never able to debug throgh the property that returns the executing environment. This was due to re-entry, I was in a debug session at a break point while the other process was trying to attach to the current environment context which was returning as busy which is why you will get the RPC_E_CALL_REJECTED during debugging.


public sealed class ExecuteAndAttachToBehaviorAttribute : TestFixtureBehaviorAttribute
{
private static EnvDTE.DTE __executingDevelopmentToolsEnvironment;
private const uint S_OK = 0;

public ExecuteAndAttachToBehaviorAttribute()
{
WaitForProcessInMilliseconds = 0;
}

#region Properties

///
/// Path to the executable relative to the currently executing ApplicationBase path
///

public string Path { get; set; }

public int WaitForProcessInMilliseconds { get; set; }

private Process Process { get; set; }

private EnvDTE.DTE ExecutingDevelopmentToolsEnvironment
{
get
{
UCOMIRunningObjectTable rot;
if (__executingDevelopmentToolsEnvironment == null && GetRunningObjectTable(0, out rot) == S_OK)
{
UCOMIEnumMoniker enumMon;
rot.EnumRunning(out enumMon);
if (enumMon != null)
{
const int numMons = 100;
int Fetched = 0;
UCOMIMoniker[] aMons = new UCOMIMoniker[numMons];
enumMon.Next(numMons, aMons, out Fetched);
UCOMIBindCtx ctx;

if (CreateBindCtx(0, out ctx) == S_OK)
{
MessageFilter.Register();
System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
for (int i = 0; i < Fetched; i++)
{
object instance;
EnvDTE.DTE dte;
rot.GetObject(aMons[i], out instance);
dte = instance as EnvDTE.DTE;
if (dte != null)
{
foreach (EnvDTE.Process p in dte.Debugger.DebuggedProcesses)
{
if (p.ProcessID == currentProcess.Id)
{
__executingDevelopmentToolsEnvironment = dte;
break;
}
}
if (__executingDevelopmentToolsEnvironment != null)
{
break;
}
}
}
MessageFilter.Unregister();
}
}
}
return __executingDevelopmentToolsEnvironment;
}
}

#endregion

#region Methods

[DllImport("ole32.dll", EntryPoint = "GetRunningObjectTable")]
private static extern uint GetRunningObjectTable(uint res, out UCOMIRunningObjectTable ROT);

[DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
private static extern uint CreateBindCtx(uint res, out UCOMIBindCtx ctx);

private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(String.Format("Unable to launch {0} the following error information was returned from the process:\r\n{1}", Path, e.Data));
}

public override void Setup()
{
Process = new Process();
Process.StartInfo = new ProcessStartInfo(Path);
Process.Start();
Process.ErrorDataReceived += new DataReceivedEventHandler(Process_ErrorDataReceived);
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
try
{
if (WaitForProcessInMilliseconds > 0)
{
Thread.Sleep(WaitForProcessInMilliseconds);
}
if (ExecutingDevelopmentToolsEnvironment == null)
throw new Exception("Unable to locate a valid instance of Visual Studio 2008, unable to attach using the current debugger instance.");
bool attached = false;
foreach (EnvDTE.Process process in ExecutingDevelopmentToolsEnvironment.Debugger.LocalProcesses)
{
if (process.ProcessID == Process.Id)
{
process.Attach();
attached = true;
}
}
if (!attached)
throw new Exception(String.Format("Unable to locate process id {0}, attach failed to complete successfully", Process.Id));
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(String.Format("Unable to attach debugger to '{0}' the following exception was generated:\r\n{1}", Path, exception.ToString()));
System.Diagnostics.Debugger.Launch();

}
}
#endif
}

public override void TearDown()
{
try
{
Process.Kill();
Process.Dispose();
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(String.Format("Unable to kill {0} the following error information was returned:\r\n{1}", Path, exception.ToString()));
}
}

#endregion

private class MessageFilter : IOleMessageFilter
{
public static void Register()
{
IOleMessageFilter newFilter = new MessageFilter();
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(newFilter, out oldFilter);
}

public static void Unregister()
{
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(null, out oldFilter);
}

int IOleMessageFilter.HandleInComingCall(int dwCallType, System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr lpInterfaceInfo)
{
return 0;
}

int IOleMessageFilter.RetryRejectedCall(System.IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2)
{
return 99;
}
return -1;
}

int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee,int dwTickCount, int dwPendingType)
{
return 2;
}

[DllImport("Ole32.dll")]
private static extern int
CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}

[ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(
int dwCallType,
IntPtr hTaskCaller,
int dwTickCount,
IntPtr lpInterfaceInfo);

[PreserveSig]
int RetryRejectedCall(
IntPtr hTaskCallee,
int dwTickCount,
int dwRejectType);

[PreserveSig]
int MessagePending(
IntPtr hTaskCallee,
int dwTickCount,
int dwPendingType);
}
}

Wednesday, June 24, 2009

Unable to delete/modify Registry Key Access Is Denied


Ran in to this one today spent an hour or two googling and proding for the answer. Essentially you are getting this message because the owner of the key is not you and has denied permission or has not given permission to you. The fix is very simple and should be obvious to those of you familiar with the NTFS file permission scheme. Just right click on the key above go to advanced reset the owner permission on child objects click ok (you may still get an error however) this will grant you control to the child element from above. From there you should be able to delete/modify the key normally.

Monday, March 23, 2009

Error 1001. No mapping between account names and security IDs was done during msi installation

I have had a hard time finding out how to fix this message in my case it turned out to be a situation
where the user name and password used to install a .net service using the serviceinstaller were incorrect. Would have
been nice if the message said something like the user name and password are incorrect.

Monday, February 9, 2009

AJAX WCF Services and HTTP/HTTPS multiple domains on single IP Address

It seems simple, hosting  an AJAX WCF .svc in IIS under multiple domains with both http and https protocol. Unfortunately this turned out to be a little complex under the binding model used by WCF. You may recieve messages such as "Could not find a base address that matches scheme http for the endpoint with binding WebHttpBinding. Registered base address schemes are [https]".After some exploration I came up with the following solution:
Configuration:
<system.serviceModel> 
 <services>
  <service name="MyNamespace.MyService" behaviorConfiguration="DefaultAspNet">
   <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="MyNamespace.MyService"/>
   <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior" bindingConfiguration="Secure" binding="webHttpBinding" contract="MyNamespace.MyService"/>
  </service>
 </services>
 <behaviors>
  <endpointBehaviors>
   <behavior name="ServiceAspNetAjaxBehavior">
    <enableWebScript />
   </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
   <behavior name="DefaultAspNet">
    <serviceAuthorization impersonateCallerForAllOperations="false" />
    <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
    <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
   </behavior>
  </serviceBehaviors>
 </behaviors>
 <bindings>
  <webHttpBinding>
  <binding name="Secure">
   <security mode="Transport"/>
  </binding>
  </webHttpBinding>
 </bindings>
 <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Factory used to allow multiple host service usage:
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Activation;
using System.ServiceModel;
//Your Namespace Here
 public class IisServiceHostFactory : ServiceHostFactory
 {
  protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
  {
   ServiceHost result = null; if (baseAddresses != null && baseAddresses.Length > 0 && HttpContext.Current != null && HttpContext.Current.Request != null)
   {
    Uri baseAddress = baseAddresses.First();
    UriBuilder httpUriBuilder = new UriBuilder(baseAddress);
    httpUriBuilder.Scheme = Uri.UriSchemeHttp; httpUriBuilder.Port = 80;
    httpUriBuilder.Host = HttpContext.Current.Request.Url.Host;
    UriBuilder httpsUriBuilder = new UriBuilder(baseAddress);
    httpsUriBuilder.Scheme = Uri.UriSchemeHttps; httpsUriBuilder.Port = 443;
    httpsUriBuilder.Host = HttpContext.Current.Request.Url.Host; result = new ServiceHost(serviceType, httpUriBuilder.Uri, httpsUriBuilder.Uri);
   }
   else
   {
    result = new ServiceHost(serviceType, baseAddresses);
   }
   return result;
  }
 }
//Your Namespace Here