March 2007 Archives
using System;
using System.IO;
using System.Text;
using System.Web;
using System.Xml;
using System.Collections.Generic;
class RequestToInputStream
{
// Constructor and previous code omitted for brevity
private XmlDocument PrepareXmlDocument()
{
XmlDocument doc = new XmlDocument();
doc.InnerXml = RequestInputStreamToString(Request.InputStream);
return doc;
}
private List<Dictionary<string, string>> NodeAttributesCollection(XmlDocument Document, string XPathExpression)
{
List<Dictionary<string, string>> nodesCollection = new List<Dictionary<string, string>>();
foreach (XmlNode n in Document.SelectNodes(XPathExpression))
{
nodesCollection.Add(NodeAttributes(n));
}
return nodesCollection;
}
private Dictionary<string, string> NodeAttributes(XmlDocument Document, string XPathExpression)
{
return NodeAttributes(Document.SelectSingleNode(XPathExpression));
}
private Dictionary<string, string> NodeAttributes(XmlNode node)
{
Dictionary<string, string> attributes = new Dictionary<string, string>();
if ((node != null) && (node.Attributes.Count != 0))
{
foreach (XmlAttribute a in node.Attributes)
{
attributes.Add(a.Name, a.Value);
}
}
return attributes;
}
private string RequestInputStreamToString(stream s)
{
// code as previously
}
}
Two new helper functions, NodeAttributes and NodeAttributeCollection, the purpose of each being:
- NodeAttributes - When passed an XPath expression that resolves to a single node (such as "entity" in the specimen below) returns a generic Dictionary of strings which contains pairs of attribute names and values.
- NodeAttributesCollection - When passed an XPath expression that resolves to more than one node (such as "entityMulti" in the specimen below) returns a collection of Dictionaries (as would be returned by NodeAttributes
Specimen XML: <entity name="entityName" otherValue="otherValue"> <entityMulti name="entityMulti1" /> <entityMulti name="entityMulti2" /> <entityMulti name="entityMulti3" /> </entity>
There are basically two options when it comes to constructing XML within Javascript, string concatenation and using the XMLDocument and its methods to construct a "proper" XML document. Depending on need, either is equally valid but it does make life a lot easier further down the line if the XML Document is used. To show the difference, the code below constructs virtually the same XML:
var sXML = '<someEntity id="' + document.getEntityID() + '" userId="' + document.getUserID() +'" />';
function CreateXMLDocument(sRootElementName) { var oXMLDoc = new ActiveXObject('Microsoft.XMLDOM'); var oXMLRoot = oXMLDoc.createElement(sRootElementName); oXMLDoc.documentElement = oXMLRoot; return oXMLDoc; }oXMLDoc = CreateXMLDocument('someEntity');
oXMLDoc.setAttribute('id', document.getEntityID());
oXMLDoc.setAttribute('userId', document.getUserID());
A couple of little useful Javascript helper functions for populating select boxes. If you've got a significant number of choices to present to the user, or a clear reason to categorise the choices presented (maybe providing the list of major towns to choose from restricted by a previous choice of county/state) dynamically populating/re-populating the select drop-down can make the user experience a lot better. There's also the added bonus that, for a list which could run to several hundreds of items, the download overhead of only bringing back those required, when required, by using a call to the server via the XMLHTTP object is significantly reduced as SELECT -> OPTION elements are quite verbose,
/*
Parameters:
controlID: The HTML ID of the element to populate
itemArray: An aray of arrays (of) to use to populate the drop down
selectedIndex: [NOT USED] The selectedIndex value to use
*/
function populateDropDown(controlID, itemArray, selectedIndex)
{
var x = document.getElementById(controlID);
var item;
for (i = 0; i < itemArray.length; i++)
{
addOptionToDropDown(x, itemArray[i][0], itemArray[i][1]);
}
}/*
Parameters:
dropDown: The selectbox DOM object to work on
itemValue: The value for the option.value attribute
itemText: The value for the option.text attributeNotes:
Called by populateDropDown*/
function addOptionToDropDown(dropDown, itemValue, itemText)
{
/*
Note: This code is Internet Explorer specific and will require changing if compatibility with other
browsers is needed (See: http://www.w3schools.com/htmldom/met_select_add.asp)
*/
var option = document.createElement('option');
option.id = dropDown.id + '_' + itemValue;
option.value = itemValue;
option.text = itemText;
dropDown.add(option);
}
Very "in brief" as I'm busy, busy, busy,.. but - start by adding a reference to "System.Messaging.DLL" to your project, then add a using statement to your class for the namespace of the same name (obviously sans ".DLL"). Thus far the project I'm working on has only required the addition of a message to a queue, so that's all that'll be described here.
At a simplistic level, to provide fail-over (yes, it can be done within the MSMQ infrastructure but bear with me!) the simplest solution is to store the detail of the message into a database table and use the message queue as a "prompt" to the down-stream system that there's work to be done. If this system is already polling the database at a pre-set interval, MSMQ failure (for whatever reason) is a non-critical, albeit un-desirable, failure.
public static class MessageRequest { private static MessageQueue mq; private static bool bUseMessageQueue = false;static MessageRequest()
{
try
{
if (!MessageQueue.Exists(ConfigurationManager.AppSettings["MessageQueueName"]))
{
mq = MessageQueue.Create(ConfigurationManager.AppSettings["MessageQueueName"]);
}
else
{
mq = new MessageQueue(ConfigurationManager.AppSettings["MessageQueueName"]);
}
bUseMessageQueue = true;
}
catch (System.Messaging.MessageQueueException ex)
{
bUseMessageQueue = false;
}
}
public static void SendMessage(string MessageName)
{
if (bUseMessageQueue)
{
mq.Send(MessageName);
}
//
// Place database insertion logic (via a Data Layer, of course! ;-) here
//
}
}
Notes
- Multiple calls to the ConfigurationManager in the constructor should be replaced with a single call, although in a static constructor the cost is negligible when amortised over the lifetime of the process.
- The whole thing will blow up if the appSetting named doesn't exist, but coating the above sample in error-testing code really doesn't help convey intention.
- As mentioned previously, everything redundancy/reliability related can be provided by the MSMQ framework, but it's well beyond the needs of the project I'm working on so I've simply not looked into it :-)
Nowhere could I find a simple, concise way of converting the Request.InputStream from an ASP.net page into a string ready for processing, something which is very useful to do if you're passing a large amount of data (such as a constructed XML submission) via the content of an XMLHTTPRequest. So, the following is an amalgam of the different examples I found that appears to work:
private string RequestInputStreamToString() { StringBuilder sb = new StringBuilder(); int streamLength; int streamRead; Stream s = Request.InputStream; streamLength = Convert.ToInt32(s.Length);Byte[] streamArray = new Byte[streamLength];
streamRead = s.Read(streamArray, 0, streamLength);
for (int i = 0; i < streamLength; i++)
{
sb.Append(Convert.ToChar(streamArray[i]));
}return sb.ToString();
}
I'm sure that it could be more elegant and there's room for optimisation, but it works well enough for my purposes.
An implementation of the XML Http Request sender (IE specific) that I use with this is below:
/*
Parameters:
sRPCPageUrl: The URL (including query string if appropriate) of the page to call
Notes:*/
function SynchronousXMLRPCCall(sRPCPageUrl)
{
return SynchronousXMLRPCCallWithPostData(sRPCPageUrl, '');
}/*
Parameters:
sRPCPageUrl: The URL (including query string if appropriate) of the page to call
sPostData: Post Data to pass to the server as part of the call
Notes:
called by SynchronousXMLRPCCall*/
function SynchronousXMLRPCCallWithPostData(sRPCPageUrl, sPostData)
{
oXMLDoc = new ActiveXObject("Microsoft.XMLHTTP");
oXMLDoc.open("GET", sRPCPageUrl, false);
oXMLDoc.send(sPostData);
return oXMLDoc;
}
A useful trick I've picked up recently is the ability to get the name of a value of an enumeration in C#. Using the following example enumeration:
enum fruit
{
apples,
pears,
oranges
}
The following sample code can be used to pop-up a message box stating what the name of the enumeration value passed in is:
function void WhatIsTheFruitCalled (fruit fruitValue)
{
string sFruitName = Enum.GetName(typeof(fruit), fruitValue);
MessageBox.Show(sFruitName);
}
The code could be made generic and more robust by changing it to the following:
function string WhatIsTheFruitCalled2 (fruit fruitValue)
{
string sFruitName = "";
if (Enum.IsDefined(typeof(fruit), fruitValue))
{
sFruitName = Enum.GetName(typeof(fruit), fruitValue);
}
return sFruitName;
}
Of course this code is specific to an enum of fruit, but it's a fairly simple exercise to make this generic as below:
public static string GetEnumValueName(T Value)
{
if (Value.GetType().IsEnum)
{
Type t = Value.GetType();
if (Enum.IsDefined(t, Value))
{
return Enum.GetName(t, Value);
}
else
{
throw new ArgumentException(string.Format("Value out of range for enumeration of type {0}", t.Name), "Value");
}
}
else
{
throw new ArgumentException("Value must be an Enumeration", "Value");
}
}
The option's there to suppress the exceptions and return empty string instead if that's the desired result, but this is a tidy bit of logic.
