Wednesday, May 09, 2007

Work around limitations of VS 2005 Deployment Projects with Windows Services

I needed to deploy a Windows Service using an MSI. The project was built in VS 2005 using .Net 2.0; so far, so good.

The problem arose when I wanted to have the Service write to its own Event Log, rather than the default Application log. The standard Installer class from System.Configuration.Install, which otherwise does a fine job of installing the Windows Service, proved less than ideal because it automatically creates an EventLogSource with the same name as the Service executable, and sets its event log to be Application.

The solution lies in the way in which the Installer class contains a series of other installers in the Installer.Installers collection, which in turn contain other installer objects.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;

namespace MyService
{
  [RunInstaller(true)]
  public partial class ProjectInstaller : Installer
  {
    public ProjectInstaller()
    {
      InitializeComponent();

      // 
      // ProjectInstaller
      // 
      this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.serviceProcessInstaller1,
            this.serviceInstaller1});
    }

    private void serviceInstaller1_BeforeInstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }

    /// 
    /// Recursive method to remove EventLogInstaller Installers from the Installers collection.
    /// This is needed to avoid automatic setting up of the event logs
    private static void RemoveEventLogInstallers(Installer installer, int depth)
    {
      Console.Out.WriteLine(String.Format("Number of installers at depth {0}: {1}", installer.Installers.Count, depth));
      for (int i = installer.Installers.Count - 1; i >= 0; --i)
      {
        Installer childInstaller = installer.Installers[i];
        Console.Out.WriteLine(String.Format("Installer {0} at depth {1} is of type: {2}", i, depth, installer.GetType().Name));

        RemoveEventLogInstallers(childInstaller, depth + 1); //recurse

        if (childInstaller is EventLogInstaller)
        {
          Console.Out.WriteLine(String.Format("Removing Installer {0} at depth {1} because it is of type: {2}", i, depth, childInstaller.GetType().Name));
          installer.Installers.Remove(childInstaller);
        }
        
      }
    }

    private void serviceInstaller1_BeforeUninstall(object sender, InstallEventArgs e)
    {
      RemoveEventLogInstallers(this, 0);
    }
  }
}

Search recursively through the entire tree of Installer objects and remove any installer whose type is EventLogInstaller, and the problem is solved! Make sure to do this before Install and before Uninstall, otherwise the (un)installation does not complete successfully.

Labels:

Saturday, April 21, 2007

Calling Javascript from C#

Call JavaScript from C# code, passing parameters and returning results.

I came across a need to call JavaScript methods on HTML code inside a web page from a C# WinForms application. How could that language gap be bridged?

It turns out that Type.InvokeMember() does the trick when using a WebBrowser control to load a web page.

using mshtml;
...
private AxSHDocVw.AxWebBrowser axWebBrowser1;
...
/// 
/// Retrieves a reference to the HTML element containing a DIV.
/// JavaScript methods are implemented on this element itself.
/// 
/// A reference to the HTML element holding the JavaScript methods
private HTMLDivElementClass GetContainer()
{      
 HTMLDivElementClass container = null;   
 IHTMLDocument2 doc = axWebBrowser1.Document as IHTMLDocument2;
   
 if (null != doc)
 {
  foreach (IHTMLElement element in doc.all)
  {
   if (element.id == "My_Container")
   {
    container = element as HTMLDivElementClass;
    break;
   }
  }
 }
   
 return container;
}

/// 
/// Gets the text from the container 
/// 
/// A string containing the text of the container
private string GetText()
{
 string result = null;
 HTMLDivElementClass div = GetContainer();
 if (null != div)
 {
  Type type = div.GetType();
  result = (string) type.InvokeMember(
    "GetText", 
    BindingFlags.InvokeMethod, 
    null, 
    div, 
    null);
 }   
   
 return result;
}

The HTML page loaded in the WebBrowser control has a DIV element with an id of "My_Container", attached to which is a method called GetText(), which returns some arbitrary text.

Having acquired a reference to the DIV on which the JavaScript method is declared (using GetContainer()), the JavaScript method is called using the InvokeMember() method of the Type class instance; the return value is cast to a string.

Discussion

There is every reason why this should NOT work, but the implementers of the WebBrowser control decided that JavaScript methods living within the DOM should be accessible as first class object members at runtime (in this case, via IDispatch). Nice!

Result

C# code can call arbitrary JavaScript within an HTML page! The only limitation is that the return types of the JavaScript methods can be only simple types (even DateTime is too complex).

Labels: , , ,

Thursday, June 01, 2006

Grey Matter Workout

I spent part of today scratching my head and dredging up long-forgotten details of the .Net Framework and C# over at BrainBench.com - to my relief, I didn't disgrace myself: a test score average of 4.25 puts me in good stead for my forthcoming MCP exam later in June.

Some of the tricky areas:

Labels:

Tuesday, May 30, 2006

Microsoft Application Blocks

Microsoft Application Blocks form a collection of ready-built 'clumps' of code which solve common problems such as security management, data access, logging, etc. They are the tangible result of the Microsoft Patterns and Practices advice: all of it sound and solid.

John Jakovich, one of the 4 Guys From Rolla, gives a useful An Introduction and Overview of the Microsoft Application Blocks. He summarises the utility of the Application Blocks thus:

...you don't have to worry about the tedious details required to return a DataReader or write an exception to the System Log. This allows us to concentrate on the business logic in our applications.
I have written too many logging frameworks in the past: it's boring above all else. I just want to log exceptions in a thread-safe manner, with a unique ID.which I can display to the user if necessary. If someone (i.e MS) has already written code to do (most of) this, then fine - I'll use it.

The Security block is particularly useful for ASP.NET 1.1, where security and profile management is not as simple as in version 2.0. All that boring stuff about storing Role information in cookies? Solved! Better still, any security holes will be fixed by MS. Again, more time to concentraste on business logic.

Design Guidelines for Class Library Developers

The Application Blocks tie in nicely with a set of guidelines from MS on class library development. They include advice on:

  • array usage
  • exposure to COM
  • casting
  • threading
and several other subjects. This is basically just a gloop of Common Sense, but well worth a read.

MBR BootFX Application Framework

An alternative to the MS Application Blocks comes from Matt Baxter-Reynolds (he of DotNet247) in the form of BootFX:

The MBR BootFX Application Framework is a best-of-breed application framework that we offer to all our clients who engage us to develop software applications or software components for them. It's designed to give us a "leg up" on new projects by providing a tried and tested code base for common software development activities.
There are lots of goodies there, including Object Relational Mapping (ORM), and support for SQL Server, Oracle, and MySQL databases. To top it all, it's open source, via the Mozilla Public Licence 1.1. I met Matt 18 months or so back at a seminar run by Iridium; very personable guy.

Labels:

Monday, April 24, 2006

ACCU Conference 2006

I went to the ACCU Spring Conference 2006 last week. There were some interesting sessions, as usual.

XSLT2 and XPath2

Version 1 of XSLT and XPath were fairly limited in their XML processing abilities in some respects: no possibility to reference local variables was the worst. Version 2.0 of these langauges fixes this and other shortcomings with a raft of new features and generalisations. In fact XSLT2 and XPath2 are very different from their predecessors.

XSLT2 allows operations on temporary/local variables and returned node sets. This can lead to greatly simplified XSLT documents. In addition, there are some nice new operator and keywords:

  • xsl:for-each - generalised operations over the universal new Sequence type (see below)
  • xsl:for-each-group - allows GROUP BY (pivot) of data
  • xsl:analyze-string - use RegEx to match text in nodes
  • xsl:function - define a custom function in XSL, and call it using XPath2 expressions
  • xsl:unparsed-text - handle non-XML text e.g. CSV

The most fundamental change in XPath2 is that all XPath2 expressions now operate upon the (typed) Sequence datatype instead of node sets. XPath2 also allows conditional expressions, whereas in XPath1 all expressions had to resolve at 'compile' time.

Comments are now allowed in XPath2 expressions, and nested loops are allowed (akin to JOIN in SQL). There is a new doc() function for pulling in nodes from a separate XML document, and RegEx support has been beefed up.

Java Server Faces 1.2 (JSF)

Java Server Faces is Sun's answer to ASP.NET, and shares the smae basic approach of separating logic from presentation.

Sun seems to have taken the 'any browser' abstraction from ASP.NET and extended this to 'any device': we were shown a demonstration of the same JSF application serving pages to a web browser, a Telnet client, and a Jabber client, of all things!

It's possible to define much of the application and component configuration via config files, and this process seemed simpler than the techinique for ASP.NET, even version 2.0 with the improved config file handlers.

The other nice thing about JSF 1.2 was the Page Flow model: a sequence of navigation actions by the user can be captured in the config file, allowing JSF to craft up appropriate links (e.g. for Edit, Save, Delete actions) automatically.

Due Diligence

I spend some valuable time talking to on of the keynote speakers about Due Diligence reviews for software. Approximation: the source code doesn't matter: it's the environment and processes which determine how maintainable the software is. More on this later...

Labels: , , ,

Tuesday, April 12, 2005

Controlling optimization and debug info in Release builds in .Net applications

Some interesting info on controlling optimization and debug info for deployed applications:
...the little-known little-used [.NET Framework Debugging Control] section of a {gasp} .INI file. These help guide and control the JIT. From MSDN:
This JIT configuration has two aspects:
  • You can request the JIT-compiler to generate tracking information. This makes it possible for the debugger to match up a chain of MSIL with its machine code counterpart, and to track where local variables and function arguments are stored.
  • You can request the JIT-compiler to not optimize the resulting machine code.
So Mark suggested this (emphasis mine):
You can have the best of both worlds with a rather neat trick. The major differences between the default debug build and default release build are that when doing a default release build, optimization is turned on and debug symbols are not emitted. So:
  • Step 1: Change your release config to emit debug symbols. This has virtually no effect on the performance of your app, and is very useful if (when?) you need to debug a release build of your app.
  • Step 2: Compile using your new release build config, i.e. *with* debug symbols and *with* optimization. Note that 99% of code optimization is done by the JIT compiler, not the language compiler, so read on...
  • Step 3: Create a text file in your app's folder called xxxx.exe.ini (or dll or whatever), where xxxx is the name of your executable. This text file should initially look like:

  • [.NET Framework Debugging Control] GenerateTrackingInfo=0 AllowOptimize=1
  • Step 4: With these settings, your app runs at full speed. When you want to debug your app by turning on debug tracking and possibly turning off (CIL) code optimization, just use the following settings:

  • [.NET Framework Debugging Control] GenerateTrackingInfo=1 AllowOptimize=0
[http://www.hanselman.com/blog/ DebugVsReleaseTheBestOfBothWorlds.aspx]

Labels:

Wednesday, March 16, 2005

Converting a byte[] to a System.String

Discussion at http://weblogs.asp.net/oldnewthing/ archive/2004/09/07/226306.aspx:

For some reason, this question gets asked a lot. How do I convert a byte[] to a System.String? (Yes, this is a CLR question. Sorry.)

You can use String System.Text.UnicodeEncoding.GetString() which takes a byte[] array and produces a string.

Note that this is not the same as just blindly copying the bytes from the byte[] array into a hunk of memory and calling it a string. The GetString() method must validate the bytes and forbid invalid surrogates, for example.

You might be tempted to create a string and just mash the bytes into it, but that violates string immutability and can lead to subtle problems.

The MSDN help for Encoding.GetString() is here:

http://msdn.microsoft.com/library/default.asp? url=/library/en-us/cpref/html/ frlrfSystemTextEncodingClassGetStringTopic1.asp

Labels:

Thursday, January 27, 2005

Assembly Dependency Viewer

This simple application gets any VS.NET project or assembly and displays all the assembly / project dependencies. All dependencies are shown in a tree view with images that indicate the assembly location (Bin, GAC or registered as COM+ component). http://www.codeproject.com/dotnet/Assemblydependencies.asp

Labels:

Sunday, April 18, 2004

ACCU Conference 2004

Just back from the ACCU Conference. Good sessions on OOP in Python 2.2+ [text], Game development, C++ Templates, PsyCo [screenshot], and even publishing.

Interesting job openings with CMed (Python on Linux for clinical systems). C++ Threading slides available at www.curbralan.com, and Organic Programming at (d'oh) www.organicprogramming.com. The OOP in Python talk looked at Descriptors, and how they are used (since 2.3) in everyday normal method calls: they sit between the caller and the returned method object, a bit like Delegates/Remoting in .NET. Or in fact, standard properties in C# and Delphi, though a little more complex. Essentially, Descriptors allow for 'behind-the-scenes' side effects. It is possible to 'decorate' classes so that for certain (?sorts of) attributes, special actions will be performed. Read-only attributes can be implementde by having __set__ raise an exception. Whoopeedo. There was also some stuff about Method Resolution Order, given that Python supports multiple inheritance.

Incidently, PyGame was described by several people os one of the best games dev packages around.

Labels: ,

Saturday, February 14, 2004

Scott Guthrie on ASP.NET

Last Monday I went to hear Scott Guthrie speak on ASP.NET. What follows is a précis of the session. The slides are online (under ASP.NET Presentation in Reading, England).

Introduction

First impressions were good: as a speaker Guthrie was very clear and measured, and flexible yet firm with questions. The talk assumed no prior knowledge of the ASP.NET architecture, so started from a basic discussion of embedded script tags (<% foo() %>) found in most dynamic content framworks ('vanilla' ASP/PHP/JSP etc.). By the end of the session, we had covered: the ASP.NET Server Control model; targetting of mobile devices; form validation; Web Services; Output Caching; Session State; and site security, including SQL Injection and XSS attacks.

Spaghetti

The existing model of dynamic (on-the-fly) HTML content generation as used with ASP/PHP/JSP etc. tends to use a script interpreter to parse server directives/commands embedded in the HTML document. This can lead to a mix of Code and Content which is very difficult to manage and understand. ASP.NET attempts to address this "spaghetti code" problem by proving the means to separate Code and Content. In addition, ASP.NET does not use a scripting engine, but rather compiles all code fragments, resulting in faster execution, especially when combined with Caching. In fact, the code to implement a particular feature need not live in the same file as the markup at all, but in a separate file using a feature called CodeBehind; the code lives "behind" the page, as it were.

Deployment

To address the need for seamless 'zero-downtime' udpates, ASP.NET uses an 'xcopy' deployment model, meaning that deployment is designed to be as simple as copying across new files to the webserver: no configuration tools to run nor locked DLLs to contend with. No doubt there are complications, but the promise is certainly welcome; with Assemblies and Side-By-Side execution, the whole .NET Framework appears to offer a similar promise too.

Server Controls

The ASP.NET coding model seems to have been designed to mimic the familiar Drag-n-Drop (Delphi/VB) style of visual programming, with UI elements exposed as objects with properties, methods and events. This is clearly quite different from the features provided by the underlying HTML, but no more so than the Delphi approach is (thankfully) different from the underlying Win32 API: in each case a flat, procedural style of programming is hidden by an Object-Oriented wrapper. This lets the programmer concentrate on good design and coding without needing to be concerned about 'plumbing'.
In an ASP.NET file (.aspx) there may be little of no HTML at all, because the ASP.NET runtime produces HTML as output, having compiled and run the code contained in (or referenced by) the page. By sending only HTML back to the browser, ASP.NET can guarantee a much wider range of targets than if, say, some functionality were implemented as ActiveX Controls. Thus, not only is it possible to separate the location of the Content from the Code, but the implementation detail (plumbing) is conceptually separated. This said, there are two different models for code in ASP.NET pages: The CodeBehind model (used by Visual Studio) and Single-file (as used by the free WebMatrix environment). The end effect is broadly the same wherever the code lies, with compiled code running at the server to generate HTML from the Controls specified in the .aspx file.
To learn about ASP.NET programming, WebMatrix was recommended, and it certainly allows you to get 'up and running' much more quickly than with VS.NET, largely because it has a built-in Web Server (bound by default to localhost for security reasons), so changes to files can be tested immediately rather than exporting the files to the IIS or Apache tree. The following images show ASP.NET development under WebMatrix.

Set Properties of Form Controls  Set Properties of Form Controls  Set Properties of Form Controls

The runat="server" attribute of the different Controls on the form indicates to ASP.NET that event handling and state management code should be generated for those Controls. Any existing HTML control can be attributed in this way; a wider range of ASP.NET Controls uses the <asp:Control ... > element, and these Controls are always run at the Server. The code is quite simple:

The code to hook events from different elements of the page is handled automatically by ASP.NET as can be seen below. The HTML generated (together with JavaScript for non-<input> elements) is comparitavely complex:

Notice the __doPostBack event hooked onto the different cells of the Calendar: the programmer had to write no such event-handling code manually - it was all generated by ASP.NET before pushing the HTML to the browser. There is automatic handling of differences in DOM support between Internet Explorer and Netscape, and a hidden field named '__VIEWSTATE' contains information about the state of the form for when the form is submitted; ASP.NET does not maintain state between page submissions except by the use of these hidden fields.

Styles and Templates

Basic styles of controls can be set at Design-Time using the properties panel in Visual Studio. To apply a collection of styles of property settings across multiple controls, one either must edit the changes on each control manually, or create a User Control (there a re some fine distinctions between Server Controls and User Controls). There is, however, an alternative to property setting: ASP Templates. It is possible to specify (either hard-coded or programmatically) a template for presenting data. Using a DataList (not a DataGrid), formatting can be applied to each logical element in the data collection. That element could be in effect a section of HTML pertaining to a single record in a data set, showing, for example, the title, author and description of a book, along with a picture of the cover.

Mobile Devices

Many mobile devices have extremely limited rendering and display capabilities, and most read markup in WML format, a flavour of XML. A WML document is typically divided into one or more subsections or "Cards". This approach is sufficiently different from the HTML approach (dealing with the whole document at once) that ASP.NET has amrkup specially for mobile devices. The <mobile:Control ...> tag is broadly equivilent to the <asp:Control ... > tag for HTML; Controls described with this element are rendered at the server, which pushes WML to the mobile device. One thing not covered by the speaker was the availability of a mechanism to produce 'cut-down' markup for low-end/downlevel clients, or clients with special requirements, such as screen readers for the visually impaired. I would guess that some sort of StyleSheet switching based on the UserAgent string may be a way to go, combined with measures to ensure that all elements contain useful descriptive text (e.g. the alt text property of the img tag). Simple WebServices seem easy to implement with .NET: decorating a class method with the [WebMethod] attribute is all that needs to be done. Use of a WebService proxy helps to abstract the code.

Validation

Validation is best performed at BOTH the client AND the server. Validation on the client prevents unnecessary calls to the server: if bad user input can be caught early, bandwidth and time are both saved. However, even if client-side validation succeeds, the server should still validate; because the client-side validation code runs as javascript, there is no guarantee that it has been executed before the form is sent to the server (users may have Javascript turned off, etc.). If the user has Javascript enbled, she sees the page update as she changes the fields on the form, providing a richer user experience.

Caching

The ASP.NET caching mechanism is powerful and can greatly improve server performance. Whole pages, page fragments and user-specific data can be distinguished and cached separately. The term Output Cache is used because the cache is downstream from the ASP HTML generation engine: it is on the "output" side. Caching can be tied to particular page parameters, so that fine-grained control over page data freshness can be maintained. For example: two separate requests arrive for a page, specifying the same parameters; the first request is served by creating the page, but the second is served from the cache. The varying longevity of data stored in Databases can thus be addressed by specifying different timeout periods for different parts of the page: page hit statistics for the past month can be cached for weeks, whereas (say) "current online users" would have a much shorter cache timeout. The Web Application Stress Tool helps test caching.

Session State

There are two options for stateful browsing sessions under ASP.NET: Cookies and Cookieless. With Cookies, the Session ID is stored on the client, whereas Cookieless mode tracks the Session ID via a special URL string. In both cases, all other state information is stored on the server, although this data can actually be stored on a machine separate to the webserver (i.e. out-of-process). This is achieved using the output_state service: net start output_state is the command to turn this on. State can also be stored in a SQL server. The default is to store state In-Process. This transparency of state storage enables web farm scenarios and increased reliability. Pages can be personalised using the Session State information, but only those parts of the page which are specific to a particular session need to created afresh; the common parts can be retrieved from the Output Cache - see Caching above.

Security

The two types of attacks covered by Guthrie were SQL Injection attacks and Cross-Site Scripting (XSS) attacks. SQL Injection vulnerabilities are not specific to any particular programming language or server platform, but rely on naive SQL command construction by the programmer, and the fact that SQL commands can be concatenated very easily. Any unfiltered user input is essentially dangerous.

In the example above, the line marked "!!! DANGER !!!" shows how SQL could be injected by an attacker into the database query. If the attacker includes special characters like . (period), ' (comma), etc., as follows:

  • Attempt to return other columns in the table: a' union select 1, 2, 3;--
  • Check and see if a priveledged account is being used: 1' union select dbid, name, filename, 3 from master..sysdatabases;--
  • Dump Password Table: 1' union select fullname, emailaddress, password, 3 from commerce..customers;--

In each case, the ' terminates the first part of the query, which is then compounded with another query, which can be as destructive or intrusive as possible! The solution is to parameterise all SQL input, using the "@parameter" notation; the line Dim param As New SqlParameter("@category", SqlDbType.VarChar) defines a parameter "@category" in which will be placed the text entered by the user. This text can be validated separately by the ASP.NET engine before being executed as SQL. Use of Stored Procedures can also mitigate SQL Injection attacks.

XSS attacks hijack unfiltered input echoed to a page by the webserver, often using query strings in URLs. The following code demonstrates this:

The naive search page takes whatever is passed in the query string for the "Search" parameter and processes it directly. This means that the <script>-tagged code will execute, and the attacker (in this case) steals the cookie generated by the search page. To avoid these attacks, always validate input, and reject unwanted embedded tags. Also, HTML-encode input strings, so that "<script>" becomes "&lt;script&gt;". In ASP.NET, use Server.HtmlEncode to achieve this.

Labels: