Checking web.config on Application Start

December 16, 2009

During development, changes to configuration files are inevitable, such as adding connection strings or service bindings. When several programmers work in the same project, synching these changes manually is prone to errors, so you better have your application startup code check the settings are there.

Let’s start with the simple task: hooking the config file checker into the startup sequence in Global.asax.cs:

namespace My.Namespace
{
  public class Global: System.Web.HttpApplication
  {

    protected void Application_Start(object sender, EventArgs e)
    {
      AppChecker.Check();
    }
  }
}

In the AppChecker class, we check whatever settings we want to make sure exists.

This example will check whether required service endpoints and bindings are present in the web.config file. Since the web.config is a valid XML file (otherwise app startup will fail with an exception), we can use the System.Xml namespace to load and parse it.

namespace My.Namespace
{
  public static class AppChecker
  {
    public static void Check()
    {
      Configuration cfg = WebConfigurationManager.OpenWebConfiguration(
          HttpContext.Current.Request.ApplicationPath);
      XmlDocument WebConfig = new XmlDocument();
      WebConfig.Load(cfg.FilePath);

      XmlNode ndSvc =
        WebConfig.SelectSingleNode("/configuration/system.serviceModel");
      if (ndSvc == null)
        throw new Exception(
          "web.config misses /configuration/system.serviceModel");

      CheckContract(ndSvc, "My.Namespace.ServiceClientProxy.IFooService");
      CheckContract(ndSvc, "My.Namespace.ServiceClientProxy.IBarProcess");
    }

All service information is stored in the <system.serviceModel> section (variable ndSvc). In this section, we look up the required service proxy classes. Then we retrieve the binding from the proxy class. If either retrieval fails, the method will raise an exception.

    private static void CheckContract(XmlNode ndSvc, string Contract)
    {
      XmlNode ndEndPoint = ndSvc.SelectSingleNode(
        "client/endpoint[@contract='" + Contract + "']");
      if (ndEndPoint == null)
        throw new Exception(
          "web.config does not contain endpoint for contract " + Contract);

      XmlNode ndBinding = ndSvc.SelectSingleNode(
        "bindings/basicHttpBinding/binding[@name='" +
        ndEndPoint.Attributes["bindingConfiguration"].Value + "']");
      if (ndBinding == null)
        throw new Exception("web.config does not contain binding " +
          ndEndPoint.Attributes["bindingConfiguration"].Value +
          " for endpoint " + ndEndPoint.Attributes["contract"].Value);
    }

If your web application references the assemblies of your proxy classes directly, you may prefer the type-safe method:

    private static void CheckContract(XmlNode ndSvc, Type contract)
    {
      CheckContract(ndSvc, contract.FullName);
    }
  }
}

Get Absolute URL of ASP.Net Application

October 19, 2009

In one of my web projects, I needed to pass the name of a specific URL inside the application to another application. So the first task was: how do I find the absolute URL of an ASP.Net application’s root directory.

I tried ResolveClientUrl, which, according to MSDN, returns

A fully qualified URL to the specified resource suitable for use on the browser

As I was expecting an absolute URL from this description, it turned out, it doesn’t. (There also seems to be a terminological confusion between a Fully Qualified Domain Name, and Absolute and Relative URLs)

Both ResolveUrl and ResolveClientUrl create URLs relative to the page’s URL or the application root, but no absolute URL.

Fortunately, I found this entry on geekpedia, which provided a solution (that I was very close to develop on my own ;) )

public string FullyQualifiedApplicationPath
{
  get
  {
    //Return variable declaration
    string appPath = null;

    //Getting the current context of HTTP request
    HttpContext context = HttpContext.Current;

    //Checking the current context content
    if (context != null)
    {
      //Formatting the fully qualified website url/name
      appPath = string.Format("{0}://{1}{2}{3}",
        context.Request.Url.Scheme,
        context.Request.Url.Host,
        context.Request.Url.Port == 80
          ? string.Empty : ":" + context.Request.Url.Port,
        context.Request.ApplicationPath);
    }
    if (!appPath.EndsWith("/"))
      appPath += "/";
    return appPath;
  }
}

Of course, if you are inside a Page’s context, this reduced version is sufficient

string appPath = string.Format("{0}://{1}{2}{3}",
  context.Request.Url.Scheme,
  context.Request.Url.Host,
  context.Request.Url.Port == 80
    ? string.Empty : ":" + context.Request.Url.Port,
  context.Request.ApplicationPath);
if (!appPath.EndsWith("/"))
  appPath += "/";

Compiled Type-Safe Databindings in ASP.Net

October 12, 2009

If you have a ListView whose DataSource is set to a collection of typed objects, then the Eval() method will use reflection to access the object properties for each processed record. (This does not only apply to ListViews, but to any container capable of handling data bindings in templates)

Since we know what type of data will be displayed in the ListView, we do not need reflection, but can directly address the object underlying the current data item:

protected Foo CurrentItem(object Container)
{
    return (Container as ListViewDataItem).DataItem as Foo;
}

This allows the usual Eval() notation as in

<asp:Label runat="server" Text='<%# Eval("Bar") %>'>

to be replaced by

<asp:Label runat="server" Text='<%# CurrentItem(Container).Bar %>'>

While this works in principle, what is still missing is that the compiler throws an error if the databinding expression is invalid. This is due to the fact that ASP.Net compiles databindings only when the page is requested.

To force the compiler, instead of the runtime, to compile databindings, we need to add aspnet_compiler as a post-build event (thank you StackOverflow):

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe -v /
    -p "$(ProjectDir)\"

and set the “Run the post-build event” option to “On successful build”.

(Note: .Net 3.5 also uses the 2.0 compiler, so no need to change the path)


Implementing a Feedback form

May 28, 2009

If you want to implement a feedback form for your application or web application without relying on the user configuring mail accounts etc., the simplest solution may be a web service which the application will access to deliver the message.

We would want the user to enter name, email address, and the message. Minimal validation would require the user to enter non-blank values for each field using a RequiredFieldValidator.

Additionally, we can check the email address for formal constraints using regular expressions, but this is quite tricky. Checking the name field for validity seems impossible.

Additionally, the application should also provide its name and version.

Thus, our web service looks something like this:

[WebMethod]
 public string PostFeedback(string Application, string Version,
    string Name, string Email, string Message)

It’s up to you what logic you implement in the web service handler. I chose to check application and version, and send an email to the contact stored for the application.

The web service returns a message to the user notifying successful receipt of the feedback (or an error message) which the invoking application finally displays.


Writing to Event Log from ASP.Net

May 20, 2009

If you create an Event Log entry from an ASP.Net application using

System.Diagnostics. EventLog.WriteEntry()

with an unregistered value for the Source parameter, you may raise the exception

System.Security. SecurityException: Requested registry access is not allowed.

This can be solved by creating a registry Key with the Source name under

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application

manually or via an installer application, as described in MS KnowledgeBase article 329291. Another possibility is to create a .reg file and import it into the registry.


Tools and Libraries for .Net Developers

May 14, 2009

ASP.Net Page_Load and Page_LoadComplete

February 25, 2009

My application dbscript has a simple page structure for most pages: Each page related to a single record has a menu control displaying the links and actions for the current record.

For example, the Project page proj_edit.aspx embeds a proj_menu.ascx control, which retrieves some data from the database in the control’s Page_Load event.

If you want to access this data from the embedding page through the ascx control, you cannot access it in the page’s Page_Load event, as the Page_Load of the control has not yet fired. There is another event, less known (at least I did not know it), called Page_LoadComplete, which fires after each embedded control’s Page_Load has been processed.

To implement a Page_LoadComplete event in a page, you need to set

AutoEventWireup="true"

in the @Page directive of the aspx file.

Then simply add the lines

protected void Page_LoadComplete(object sender, EventArgs e)
{
}

to your page class in the aspx.cs file.

I posted about the ASP.Net page life cycle about a year ago, but recently came across this post which has a more detailed diagram on the page and control life cycle.

Download it. Memorize it. Make it your desktop background! ;)


JavaScript pageLoad() for MasterPage and ContentPage

February 22, 2009

I was experimenting with the DragPanelExtender recently, and almost immediately ran into the question of how to position it upon opening.

There are a lot of articles to be found on this question, and they always deal with it by means of a JavaScript function called pageLoad(), which is called by the ASP.Net Ajax framework sometime while the page is loading.

Now my application already has a pageLoad() function in the MasterPage, so adding a function of the same name in the ContentPage just did not work, as it would not be called by the framework.

My knowledge of JavaScript is not too profound, and I found that a function definition in JavaScript is actually a property of the window object. The hint was a line in the MicrosoftAjax.js file:

if (window.pageLoad) window.pageLoad(this,a);

meaning: if there is a defined function named pageLoad(), it is a property of the window object, and the value of the property is not null (== not false), and I can call it.

The solution was clear to me soon: if I need a pageLoad() method in the ContentPage, I need to name it differently and check for its definition in the MasterPage.

The pageLoad() in the MasterPage looks like this:

function pageLoad(sender, args)
{
    ...
    // ... do my MasterPage JavaScript stuff...
    ...
    if (window.contentPageLoad) {
        window.contentPageLoad(sender, args);
    }
}

and the ContentPage has its equivalent contentPageLoad() function:

function contentPageLoad(sender, args)
{
    // do something
}

Page-specific actions in Selenium NUnit crawler

January 6, 2009

In my previous posts on Selenium and NUnit I described how to crawl your web application by following all the links on every page, and hashing the visited addresses.

My crawler can optionally reduce a page’s URL to a kind of signature consisting of the address and the names of its parameters. For example, the URL

http://myhost/app1/mypage.aspx?page=7&section=1

would be reduced to

mypage.aspx?page&section

If we want to add page-specific actions, the simplest approach is a huge switch/case statement which finds us the actions to be performed depending on the current address (and thus, depending on the signature of the current URL). Let’s define

delegate void PageTest();

and

string sUrlPattern = sUrl.Substring(sUrl.LastIndexOf("/") + 1);
if (sUrlPattern.Contains("?"))
{
    sUrlPattern = Regex.Replace(sUrlPattern, "=.+?&", "&");  // non-greedy
    sUrlPattern = Regex.Replace(sUrlPattern, "=.+", "");
}
List<PageTest> lifnTests = new List<PageTest>();

We can then add page tests to the list:

switch(sUrlPattern)
{
    case "mypage.aspx?page&section":
      lifnTests.Add(delegate() { TestMyPageWithPageAndSection(); });
      break;
    ...
}

The List<PageTest> now contains all the test functions that can be called because of the parameters of the current page.

foreach(PageTest pt in lifnTests)
{
    selenium.Open(sUrl);
    selenium.WaitForPageToLoad("60000");
    pt();
}

An action consists of the usual Selenium commands:

private void TestMyPageWithPageAndSection()
{
    selenium.Click("btnClickMe");
}

Of course, the necessary try/catch blocks, logging, etc need to be added to let NUnit run through an application test in case of an error.


Finding SELECT Commands in .aspx Files

December 22, 2008

During tests of my most recent versions of dbscript I ran into problems with a SELECT statement that works fine on SQL Server 2000, but raises an error on SQL Server 2005.

The statement is in the form of

SELECT NULL AS OID, NULL AS ID
UNION ALL
SELECT MyTable.OID, MyTable.ID
FROM MyTable
ORDER BY MyTable.ID

The statement retrieves all records of MyTable, and adds an empty record at the beginning. The problem seems to be that while SQL2000 only considers the column name of the ORDER BY clause, SQL2005 cannot find the column MyTable.ID in the result set, as it is only defined as ID in the first SELECT.

After fixing the statement, the obvious question was where else in the source code such statements occurred.

A single line on the cmd prompt invoking my graspx tool showed the occurrences:

graspx l SelectCommand *.aspx | find "UNION" | find "ORDER"