Thursday, January 28, 2010

All Your .base

I encountered some issues with a .NET service installer embedded into an .MSI package today. If you have classes dependent upon service startup in your installer and the service fails to start you will often get some unexpected and often cryptic messages. It gets even worse if your messages are relating to event log messages that wont write because of permissions or other similar issues. One gotcha I am guilty of was using EventLog instead of base.EventLog. I also failed to set the event log location when calling the static version of the method calls. By using base.EventLog the ServiceBase class creates an event log source and applies all messages to the Application log. Do this and all event log messages are not belong to us.

Tuesday, January 26, 2010

Console XML/XSD Validation Application

Could not find a decent console application to validate an XML file against multiple XSD Schema Documents so I decided to write one and share for any who may need it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Schema;

namespace XmlValidator
{
class Program
{
static void Main(string[] args)
{
int result = 0;
string documentPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, args[0]);
if (!File.Exists(documentPath)) throw new Exception(String.Format("The document '{0}' does not exist", documentPath));
List schemaPaths = new List();
foreach (string path in args.Skip(1))
{
string schemaPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, path);
if (!File.Exists(schemaPath)) throw new Exception(String.Format("The schema document '{0}' does not exist", schemaPath));
schemaPaths.Add(schemaPath);
}
using (Stream stream = File.Open(documentPath,FileMode.Open,FileAccess.Read,FileShare.ReadWrite))
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationEventHandler += new ValidationEventHandler(
delegate(object sender, ValidationEventArgs e)
{
result = -1;
Console.Write("Line:");
Console.Write(e.Exception.LineNumber);
Console.Write(" Position:");
Console.Write(e.Exception.LinePosition);
Console.Write(" ");
Console.Write(e.Severity.ToString("G"));
Console.Write(" ");
Console.WriteLine(e.Message);

}
);
foreach (string path in schemaPaths) settings.Schemas.Add(XmlSchema.Read(XmlReader.Create(path), null));
stream.Position = 0;
XmlReader validator = XmlReader.Create(stream, settings);
while (validator.Read()) ;
validator.Close();
}
if (result == 0) Console.WriteLine("Document is valid");
#if DEBUG
Console.ReadLine();
#endif
Environment.Exit(result);
}
}
}

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.