Monday, April 6, 2009

They can go 36-126

And I won't care as long as all 36 wins are against the MFY and MFRS (if you don't know those abbreviations ask an Orioles fan in person).

Eat it C.C. 10-5 sucker, enjoy your 160 million. Oh and Tex you're supposed to get the ball out of the infield for 180 million, not hit weak grounders. So proud of all the fans that made it out today to and boo'd Tex heartily. Every story around the interwebz I read today made mention of that, it was awesome. Just goes to show the Warehouse what the fans will do if given a reason. so, McPhail... give us a reason!!

Thursday, April 2, 2009

And another job goes overseas

My company, which I'll still not name, shipped another job overseas this week. Sorry Jeff, the DBA job isn't here anymore. My biggest concern is that he's 12 hours ahead of us, how am I supposed to working interactively with him/her?

Wednesday, April 1, 2009

I hate you IE. I hate your guts with the fire of a thousand suns

I've been working professionally for 8 years now. I've been a programmer for 14. And nothing, NOTHING!, pisses me off more than Microsoft's Internet Explorer. Seriously don't use it.

Today's case in point? Javascripts getElementsByName function. The documentation says that it returns all DOM objects with the name given. So if you said something like:


var verisons = document.getElementsByName('Mike');


It should return to you all the elements on the page that have the name attribute set to Mike. In fact, this is exactly what Firefox does (I can only speak for FF and IE because I dont' have/use Safari, Opera or Chrome). What does IE return? Every element who's ID attribute is 'Mike'. Why?! That's what getElementById does!!! Learn to actually read your own flippin documentation!!!!!!!

God, I hate IE!

Tuesday, March 24, 2009

Not my code, but worth repeating

Scenario: A piece of software works with a configuration file. This file is shared between multiple installations of this software in a distributed environment. It holds common values and it is very important that these values not get out of sync. What do you do?

One solution is to use this very cool chunk from Koders. And ofcourse, I had to reboot and lost the link. Needless to say, this one ain't mine. I'm not this smart.


using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;


namespace Program
{
///
/// A non-reentrant mutex that is implemented using
/// a lock file, and thus works across processes,
/// sessions, and machines (as long as the underlying
/// FS provides robust r/w locking).
///
/// To use:
///
/// FileLock fLock = new FileLock(@"c:\foo\my.lock");
///
/// using (fLock.Acquire())
/// {
/// // protected operations
/// }
///

internal class LockFile
{


private readonly string filepath;
private readonly DisposeHelper disposeHelper;
private Stream stream;

public LockFile(string filepath)
{
this.filepath = filepath;
this.disposeHelper = new DisposeHelper(this);
}

public IDisposable Acquire()
{
string dir = Path.GetDirectoryName(filepath);

lock (this)
{
while (stream != null)
Monitor.Wait(this);

while (true)
{
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
try
{
Debug.Assert(stream == null, "Stream was not null--programmer error");
stream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None, 8, false);
return disposeHelper;
}
catch (IOException)
{
Thread.Sleep(50);
continue;
// int errorCode = Marshal.GetHRForException(ioe) & 0xFFFF;
// switch (errorCode)
// {
// case 32:
// case 33:
// case 32 | 0x1620:
// case 33 | 0x1620:
// Thread.Sleep(50);
// continue;
// default:
// throw;
// }
}
}
}
}

internal void Release()
{
lock (this)
{
// Doesn't hurt to pulse. Note that waiting threads will not actually
// continue to execute until this critical section is exited.
Monitor.PulseAll(this);

if (stream == null)
throw new InvalidOperationException("Tried to dispose a FileLock that was not owned");
try
{
stream.Close();
try
{
File.Delete(filepath);
} catch(IOException) { /* could fail if already acquired elsewhere */ }
}
finally
{
stream = null;
}
}
}

private class DisposeHelper : IDisposable
{
private readonly LockFile lockFile;

public DisposeHelper(LockFile lockFile)
{
this.lockFile = lockFile;
}

public void Dispose()
{
lockFile.Release();
}
}
}
}

Monday, March 23, 2009

/facepalm

First Dead Poets Malygos kill. We all get so excited that we forget to dodge the last static field. This is the result:



I think Capt. Picard would have this to say...

Friday, March 20, 2009

Flames of War

Nate....
Ah Nate my friend

WHY!! Why do you get me into new games? Huh?! I spent the night trying to figure out which mini's go on which bases for Flames of War. In FoW you don't have one trooper per base, you get 2,3 or 4. And wow is it confusing. First time ever, I've got a headache after assembling mini's.

Remote web service testing

Recently my company decided that hosting our website locally (read down the hall) wasn't good enough. They felt that we needed to be in a hosting facility in a city I won't name. If you know me in person, you've heard about this already and know where it is. Needless to say this caused huge problems. Our website grew organically, we wrote the roots 30 months ago and the thing just kinda grew and grew and grew until we got to where we are now... code bloat. My bad.

The transfer to the hosting facility was not easy and one of the biggest problems turned out to be our Web Services (for more information see articles on Software as a Service, Saas). There were all kinds of configuration errors as well as testing problems. About 10 days after the deployment my boss sends me this innocuous email:



Please create a new folder in the web site called “test”
Create one new webpage that reference your web services.
One for CreateJob.

The page should merely have all of the required fields on an input form and invoke the web service call and display the XML response.
People other than you have to be able to test this functionality.

For those who might ever be in a position to manage geeks with creation complexes don't write blank checks like this, it leads to the following.

I spent my entire day Tuesday writing a complete, automatically generated, test bed system for testing webservices. The idea behind it was to request the WSDL (Web Service Description Language) for the web service, generate the list of available services, use the reflection library of C# (System.Reflection - super cool) to enumerate the methods and parameters of all available services and then execute a test call to the method.

There were some snags, but I completed the entire Research-Design-Develop-Test-Deploy cycle in one day for some very cool (in my own mind) code.

I wound up with two pages:
  • ServiceList.aspx
  • TestOperation.aspx
The first page does that what it says, it lists the services on the server:
Markup

<div class="Form">
<h3>Web Service Operations - <asp:Label ID="lblServicesURL" runat="Server" /></h3>
<table class="ListView_Table" border="0" cellpadding="0" cellspacing="0" >
<tr class="HeaderRow">
<th>Name</th>
<th>Description</th>
</tr>
<asp:PlaceHolder ID="OperationsList" runat="server" />
</table>
</div>


Code Behind

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
using System.Reflection;
using System.Text;

/// Web service references
using localhost;

public partial class test_servicelist : System.Web.UI.Page
{
struct WSDLOperation
{
public string operation;
public string description;
}

protected void Page_Load(object sender, EventArgs e)
{
// Request the WSDL from the services site
System.Collections.ArrayList wsdlOperations = new System.Collections.ArrayList();
Services services = new Services();

System.Collections.ArrayList wsdlOperationNames = ParseWSDL(services.Url + "?WSDL", ref wsdlOperations);
lblServicesURL.Text = services.Url;
int i = 0;
foreach (WSDLOperation op in wsdlOperations)
{
HtmlTableRow tr = new HtmlTableRow();
HtmlTableCell td = new HtmlTableCell();
HtmlAnchor link = new HtmlAnchor();
link.InnerText = op.operation;
link.HRef = "testOperation.aspx?op=" + HttpUtility.HtmlEncode(op.operation);
td.Attributes.Add("style", "padding-left: 10px;");

td.Controls.Add(link);
tr.Cells.Add(td);
td = new HtmlTableCell();
td.InnerText = op.description;
tr.Cells.Add(td);

if (i % 2 == 0)
tr.Attributes.Add("class", "EvenRow");
else
tr.Attributes.Add("class", "OddRow");
i++;
OperationsList.Controls.Add(tr);
}



}

private static System.Collections.ArrayList ParseWSDL(string url, ref System.Collections.ArrayList wsdlOperations)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
System.Text.StringBuilder html = new StringBuilder();
// read in and store the XML
using (System.IO.StreamReader stream = new System.IO.StreamReader(response.GetResponseStream()))
{
string line = "";
while ((line = stream.ReadLine()) != null)
{
html.AppendLine(line);
}
}
response.Close();

//System.Console.WriteLine(html.ToString());
// Open an array list for use in storing the available operations.
System.Collections.ArrayList wsdlOperationNames = new System.Collections.ArrayList();
int start, end;
string wsdl = html.ToString();
// skip down to the list of operations in the WSDL listing.
// we don't need to worry about the types so we can skip them for now.
start = wsdl.IndexOf(">wsdl:porttype"); end="wsdl.IndexOf("</wsdl:portType">", start);
wsdl = wsdl.Substring(start, end - start);

while (true)
{
start = wsdl.IndexOf(">wsdl:operation"); if="" start=""> end =" wsdl.IndexOf("<");
// single out an operation
string operation = wsdl.Substring(start, end - start);
// and remove it from the operation listing
wsdl = wsdl.Substring(end + ">/wsdl:operation");<".Length);


WSDLOperation op = new WSDLOperation();
// parse out the name of the operation
start = operation.IndexOf("name=\"") + "name=\"".Length;
end = operation.IndexOf("\"<", start);
op.operation = operation.Substring(start, end - start);

// parse out the description of the operation
start = operation.IndexOf(">wsdl:documentation"); if="" start=""> 0)
{
start = operation.IndexOf(">", start) + 1;
end = operation.IndexOf("</wsdl:documentation");>", start);
op.description = operation.Substring(start, end - start);
if (op.description.Length > 80)
op.description = op.description.Substring(0, 80);
}
else
op.description = "No description from the WSDL is available";

wsdlOperations.Add(op);
wsdlOperationNames.Add(op.operation);
}

// print out the names of all the available operations
return wsdlOperationNames;
}
}

Test Operation used the reflection library for executing the method call to the remote service:

Markup

<div class="Form">
<h3><asp:Label ID="lblOperation" runat="Server" /></h3>

<table class="ListView_Table" border="0" cellpadding="0" cellspacing="0" >
<tr class="HeaderRow">
<th>Parameter Name</th>
<th>Type</th>
<th></th>
</tr>
<asp:PlaceHolder ID="Input" runat="server" />
<tr>
<td colspan="3" style="text-align: right;">
<asp:Button ID="btnSubmit" runat="server" Text="Test Operation" OnClick="btnSubmit_Click" />
</td>
</tr>
</table>
<p />
<h3>Response</h3>

<table class="ListView_Table">
<tr class="HeaderRow">
<th>Return Parameter</th>
<th>Value</th>
</tr>
<ajax:UpdatePanel ID="ResponsePanel" runat="server">
<Triggers>
<ajax:PostBackTrigger ControlID="btnSubmit" />
</Triggers>
<ContentTemplate>
<asp:PlaceHolder ID="PHResponse" runat="Server" />
</table>
</ContentTemplate>
</ajax:UpdatePanel>
</table>
</div>



Code Behind


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.Reflection;
/// Web service references
//using PBTMM;
using localhost;
public partial class test_testOperation : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Request["op"] == null || Request["op"].Length == 0)
Response.Redirect("servicelist.aspx");
Services services = new Services();
lblOperation.Text = Request["op"] + " from " + services.Url;
// Use the reflection library to get the associated data for the operations from the
// web reference DLL
Type serviceType = typeof(Services);
MethodInfo method = serviceType.GetMethod(Request["op"]);
int i = 0;
foreach (ParameterInfo parameterInfo in method.GetParameters())
{
// Print the Parameter Type and the Parameter Name
HtmlTableRow tr = new HtmlTableRow();
HtmlTableCell td = new HtmlTableCell();

td.InnerText = parameterInfo.Name;
tr.Cells.Add(td);

td = new HtmlTableCell();
td.InnerText = parameterInfo.ParameterType.ToString();
tr.Cells.Add(td);

td = new HtmlTableCell();
TextBox txt = new TextBox();
txt.ID = "txt" + parameterInfo.Name;
txt.CssClass = "Required";
txt.Width = Unit.Pixel(200);
td.Controls.Add(txt);
tr.Cells.Add(td);

if (i % 2 == 0)
tr.Attributes.Add("class", "EvenRow");
else
tr.Attributes.Add("class", "OddRow");
i++;


Input.Controls.Add(tr);

}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
Type serviceType = typeof(Services);
object iBaseType = Activator.CreateInstance(serviceType);
int parmCount = 0;
MethodInfo method = serviceType.GetMethod(Request["op"]);
parmCount = method.GetParameters().Length;
object[] arguments = new object[parmCount];
int i = 0;
foreach (ParameterInfo parameterInfo in method.GetParameters())
{
TextBox txt = (TextBox)Input.FindControl("txt" + parameterInfo.Name);
if (parameterInfo.ParameterType == typeof(String))
arguments[i] = txt.Text;
// We need some sort of sanity check here
else if (parameterInfo.ParameterType == typeof(Int32))
arguments[i] = System.Convert.ToInt32(txt.Text);

i++;
}
object response = serviceType.InvokeMember(Request["op"], BindingFlags.InvokeMethod | BindingFlags.Default, null, iBaseType, arguments);

Type responseType = response.GetType();
i = 0;
foreach (PropertyInfo pi in responseType.GetProperties())
{
if (pi.CanRead)
{
//pi.GetValue(responseType, null);

HtmlTableRow tr = new HtmlTableRow();
HtmlTableCell td = new HtmlTableCell();
td.InnerText = pi.Name;
tr.Cells.Add(td);
td = new HtmlTableCell();
object o = pi.GetValue(response, null);
if (o != null)
{
td.InnerText = o.ToString();
}
else
td.InnerText = "(null)";
tr.Cells.Add(td);
if (i % 2 == 0)
tr.Attributes.Add("class", "EvenRow");
else
tr.Attributes.Add("class", "OddRow");
i++;
PHResponse.Controls.Add(tr);

}
}

}
}

Monday, February 2, 2009

Tap tap - this thing on?

Yeah yeah, it's been 9 months since I used this, but Nate asked me what the address was and it got me thinking. I started this blog as a way to basically keep all my "cool" code fragments together. So I figured I'll share one of them now.

My company sends a lot of emails to clients. Order confirmation's, alert's, reports, yada yada yada. And God forbid one of them needs to be changed (I never misspell anything I swear!). So about 6 months ago Andrew (one of the other developers here) and I came up with this system.

We create several email templates that have reserved character strings in them and then use find and replace functions (String.Replace(find, replace)) to substitute in all of the values for the email. Boring right? The stroke of "genius" part for me was to access these over the web. The templates are stored on our webserver but any of the processes that need to send an email can do so via a web request. Check it out:

static public string RetrieveMailTemplate(string link)
{
System.Text.StringBuilder html = new System.Text.StringBuilder();
System.Net.HttpWebRequest request =
(System.Net.HttpWebRequest)System.Net.WebRequest.Create(link);
System.Net.HttpWebResponse response =
(System.Net.HttpWebResponse)request.GetResponse();
using (System.IO.StreamReader stream = new
System.IO.StreamReader(response.GetResponseStream()))
{
string line = "";
while ((line = stream.ReadLine()) != null)
{
html.AppendLine(line);
}
}
response.Close();
return html.ToString();
}

So you call this function with the location of the template and it returns to you the contents of the HTML document which you can modify. We use reserved strings like {#USER_ID#} that the calling function then replaces. This does require knowledge of the HTML contents, which I was hoping to avoid when I designed this, but so far in use it hasn't been a problem. Usage example:


string templatePath =
EmailTemplatesPath +
(mCurrentUser.Theme.Length > 0 ? mCurrentUser.Theme : "Normal") +
"/JobCreateSingleEmailTemplate.html;
body = RetrieveMailTemplate(templatePath);
body = body.Replace("{#PROTOCOL#}",
ConfigurationManager.AppSettings["Protocol"] + "://");
body = body.Replace("{#HTTP_HOST#}", Request.ServerVariables["HTTP_HOST"]);
body = body.Replace("{#APP_PATH#}", Request.ApplicationPath);


The example has been scrubbed of any references to the company I work for, I don't want to get sued if I broke any laws by posting this.

You can also do some neat things if your webserver is an .NET server. When you make that Request call to a .NET page the page is compiled and run before the HTML is returned to you. So any code-behind that you want to run can be executed before you get that HTML back. This means that any HTML document is dynamic so long as the .NET code-behind modifies it. Cool!