Category Archives: .NET

How to create a Custom Debug Visualizer in Visual Studio

In this screencast, I talk through the process of creating a simple custom debug visualizer to view a System.Drawing.Image image.

Essentially, the visualizer is a class library that references the Microsoft.VisualStudio.DebuggerVisualizers and System.Windows.Forms assemblies. The project has a class, ImageVisualizer, that inherits the .NET framework DialogDebuggerVisualizer class, and overrides its Show method:

class ImageVisualizer : DialogDebuggerVisualizer
{
    protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
    {
        Image image = (Image)objectProvider.GetObject();
        ImageForm form = new ImageForm { DebugImage = image };
        windowService.ShowDialog(form);
    }
}

This converts the variable that’s being debugged to an Image type using the objectProvider parameter’s GetObject method call. This is then assigned to the dialog’s DebugImage property, and the dialog is shown using the windowService parameter’s ShowDialog method.

The actual dialog is very simple indeed, comprising of just a PictureBox to show the image, and a close button to, well, close the dialog.

public Image DebugImage
{
    set
    {
        this.pictureBoxImage.Image = value;
        this.pictureBoxImage.SizeMode = PictureBoxSizeMode.Zoom;
    }
    get
    {
        return this.pictureBoxImage.Image;
    }
}

The dialog class’ DebugImage property simply assigns the picture box’s Image property and zooms. I kept things simple for the screencast, but there’s no reason why the dialog couldn’t be extended to show other image properties such as image location, image type, and dimensions.

To use the visualizer, simply build the project and copy the dll to the Visualizers directory, which on my machine is:

C:Program Files (x86)Microsoft Visual Studio 10.0Common7PackagesDebuggerVisualizers

This particular path relates specifically to my machine, since I’m running 64 bit windows, and Visual Studio 10. Once the dll has been copied, it can be used on the next debug session. In the screencast, I use a simple console program example that loads an image from file. Clicking on the magnifying glass opens up the visualizer’s dialog, and the image can be seen.

5 things you may not know about ASP.NET

Since its release in early 2002, Microsoft’s ASP.NET platform has gone from strength to strength. Despite its strong uptake from Microsoft-centric software houses, there may be a few people who have hesitated in adopting ASP.NET for their web development platform. Here I present some things you might not know about ASP.NET. Perhaps it’ll encourage you to take a look at it.

Cost

There once was a time when the standard IDE for developing ASP.NET apps, Visual Studio, was prohibitively expensive for the average Joe. In late 2007, Microsoft released its first versions of ‘Express’ software, aimed at students and hobbyists. Though Express incarnations have fewer features than their full version cousins, they do offer the possibility of exploring ASP.NET. The Microsoft website offers a download page for Visual Web Developer 2008 Express Edition. An express version of SQL Server is also available, and can be downloaded from the SQL Server 2008 download page.

MVC Support

The MVC pattern is an established and well-recognised way of building web applications, and is familiar to RoR, Java and PHP developers. For many years, MVC was not available as a standard approach to developing ASP.NET websites, but Microsoft has recognised the deficiency and have (at the time of writing) released version 1.0 Release Candidate of ASP.NET MVC. The release has had a mixed response from the ASP.NET community, many of whom are used to the traditional code-behind model. Despite the inevitable squabbles as to which way is best, many have welcomed the MVC approach for its separation of concerns and finer control over JavaScript and markup. To find out more about the release candidate, head over to Scott Guthrie’s blog post.

Learning Resources

A big advantage for anybody learning a new technology is the wealth of learning material that is available. Although you can rely on a large number of books, the ASP.NET learn website contains many videos on both traditional and MVC ASP.NET as well as data access.

Intrinsic jQuery Support

The lightweight open source JavaScript library that’s taken the web by storm is now fully supported by Microsoft. As well as full intellisense support in Visual Studio, Microsoft will be using the library as-is, without forking or changing the code from the main jQuery branch. What’s more, Microsoft will be using jQuery as a basis for future ASP.NET and ASP.NET AJAX features. I feel this counters the argument of Microsoft not supporting open-source software.

Career Prospects

Microsoft’s ubiquity means that learning ASP.NET and supporting technologies will do no harm to your career prospects. .NET skills are ranked as some of the most in-demand in the UK.

masks

Programmatic impersonation in C#

Impersonation

I recently deployed a WPF app on a server that allowed the user to stop and start some application-related services. The purpose of the app was to allow users with administrative rights an easy way to manage the services that they needed to manage. Granted, they could manage the services through the services MMC, but the little WPF app was a requirement, and it’s our job as developers to make things easier for our clients – right?

All went well until a change of requirements meant that a user without administrative rights needed to use the program to stop and start the required services. When I tried to use the app, I got an exception – quite rightly, stopping and starting the services required admin rights. We needed the restricted user to be able to log on and use the app, but still needed to restrict their permissions.

So – step in programmatic impersonation in C# – a way to give restricted users the power that that’s required, all within the confines of your application.

The first thing to point out is that I got quite a bit of this code from a google search, but I had to do a bit of work to get things in a state that I found really useful.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Linq;
using System.Security.Principal;
using System.Text;
namespace ServiceControllerApp.Security
{
    public class Impersonator : IDisposable
    {
        private WindowsImpersonationContext _impersonatedUser = null;
        private IntPtr _userHandle;
        public Impersonator()
        {
            _userHandle = new IntPtr(0);
            string user = "servicecontroller";
            string userDomain = ConfigurationManager.AppSettings["MachineDomain"];
            string password = "yourpassword";
            bool returnValue = LogonUser(user, userDomain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);
            if (!returnValue)
                throw new ApplicationException("Could not impersonate user");
            WindowsIdentity newId = new WindowsIdentity(_userHandle);
            _impersonatedUser = newId.Impersonate();
        }
        #region IDisposable Members
        public void Dispose()
        {
            if (_impersonatedUser != null)
            {
                _impersonatedUser.Undo();
                CloseHandle(_userHandle);
            }
        }
        #endregion
        #region Interop imports/constants
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_LOGON_SERVICE = 3;
        public const int LOGON32_PROVIDER_DEFAULT = 0;
        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool LogonUser(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
        #endregion
    }
}

Impersonator is a simple class that uses interop to call Win32 LogonUser and CloseHandle functions. We have to use interop because .NET doesn’t provide the equivalent methods.

The code shown above has a user, domain and password actually in the code – for some situations this is a security risk, so the credentials should be obtained in another manner, but for my needs, it was satisfactory, and their direct inclusion simplifies this example.

The class has a WindowsImpersonationContext to manage the impersonation, and the constructor sets up the required logon rights using the LogonUser interop.

Crucially, the impersonation must end, with an equivalent Log Off – and the class implements IDisposable to call the required log off code. Using the class is easy.

using (Impersonator impersonator = new Impersonator())
{
    // code in here
}

The good thing is that because the class implements IDisposable, you don’t have to pepper your code with the log off code equivalent. I hope it’s of use to somebody wishing to implement impersonation.

ASP.NET Gravatar Control Update – Full Source Included

Gravatar ASP.NET Control

With gravatars now becoming ubiquitous in blogs and forums, I have developed an ASP.NET Control that encapsulates their functionality in a simple, reusable component. It’s so easy to use, you can download and be using it on your ASP.NET sites within minutes.

I introduced the control in February of 2008, and updated the functionality in March of 2008.

I’ve since had a lot of interest in the source code for the control, and so this post describes how the control works, as well as providing a download containing the control, as well as the full control source and example website that uses the control.

OK, let me download it already!

Download the Control and get started. Note that the demo projects included in the ZIP were written in Visual Studio 2005, so if you’re using Visual Studio 2008, you’ll need to convert the solution. If you’ve not done a conversion before, just follow the instructions that Visual Studio provides. Please also note that the solution will not open in Express Editions, since they do not support control projects. However, you can still use the control that’s included in the ZIP file.

Unzip the .zip download, and you’ll have the following folder structure:

Unzipped Folder structure

The root contains a small readme file, Visual Studio solution, FreshClickmedia.dll – the gravatar control assembly, Freshclickmedia.Web control project and GravatarSite website, which contains a few control examples.

Opening the solution in visual studio will give you this solution structure:

Gravatar Solution

Fire up the website, and you should see something like this:

Gravatar Demo Website

Examining the Code

    <h1>Gravatar Examples</h1>
    <h2>My email address, size of 80 pixels:</h2>
        <fcm:Gravatar ID="Gravatar1" runat="server" Email="youremailaddress@domain.com"
             OutputGravatarSiteLink="true" Size="80" />
    <h2>No email address, with default image (absolute url) specified:</h2>
        <fcm:Gravatar ID="Gravatar2" runat="server" Size="80" DefaultImage="http://farm3.static.flickr.com/2375/2552064340_192825f989_o.jpg" />
    <h2>Email address not associated with Gravatar, with no default image:</h2>
        <fcm:Gravatar ID="Gravatar3" runat="server" Email="thisemaildoesnotexist@freshclickmedia.com" Size="80"  />

The control requires an email address:

<fcm:Gravatar ID='Gravatar1' runat='server' Email='username@domain.com' />

For my email address, I get the following generated HTML:

Output for my email address

And if we look at the generated source:

<a id="Gravatar1" href="http://www.gravatar.com" title="Get your avatar"><img width="80" height="80" src="http://www.gravatar.com/avatar.php?gravatar_id=ccf3b8c638f15d005e5d070aeb1a3923&rating=G&size=80" alt="Gravatar" /></a>

The default produces a hyperlink off to the Gravatar site with a title “Get your avatar”. The image contains the MD5 email hash, a rating of “G” (suitable for all audience types), and a size of 80.

Customisation

The control supports a number of properties supporting the customisation of its output.

Size

The size property of the control can be in the range 1 to 80. If it is outside this range, a default of 80 will be used.

MaxAllowedRating

The ‘highest’ allowed rating of image.

  • A G rated gravatar is suitable for display on all websites with any audience type.
  • PG rated gravatars contain may contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence.
  • R rated gravatars may contain such things as harsh profanity, intense violence, nudity, or hard drug use.
  • X rated gravatars may contain hardcore sexual imagery or extremely disturbing violence.

OutputGravatarSiteLink

True by default, determines whether a hyperlink linking to the gravatar website will be output around the image.

LinkTitle

“Get your avatar” by default, allows the customisation of the ‘title’ attribute of the link (obviously doesn’t apply if OutputGravatarSiteLink property is set to false.)

DefaultImage

URL encoded URL, protocol included, of a GIF, JPEG, or PNG image that should be returned if either the requested email address has no associated gravatar, or that gravatar has a rating higher than is allowed by the “MaxAllowedRating” property.

The code snippet below shows the associated properties.

<fcm:Gravatar ID="Gravatar1" runat="server"
    Email="username@domain.com"
    DefaultImage="http://www.site.com/default.jpg"
    OutputGravatarSiteLink="true" Size="40" />

Examining the control code

The Gravatar control derives from System.Web.UI.WebControls.WebControl and overrides the Render method.

The various properties such as Email are all implemented as simple C# properties, with various attributes depending on the property.

[Bindable(true), Category("Appearance"), DefaultValue("80")]
public short Size
{
	get
	{
		return _size;
	}
	set
	{
		_size = value;
	}
}

These properties are then used in the Render method to write out HTML using the method’s HtmlTextWriter parameter.

The Render method begins by adding the default attributes to the render, ensuring that the size is within the valid range of 1 to 512, and initialises the gravatar URL:

AddAttributesToRender(output);
// if the size property has been specified, ensure it is a short, and in the range
// 1..512:
try
{
    // if it's not in the allowed range, throw an exception:
    if (Size < 1 || Size > 512)
        throw new ArgumentOutOfRangeException();
}
catch
{
    Size = 80;
}
// default the image url:
string imageUrl = "http://www.gravatar.com/avatar.php?";

If an Email address has been supplied, the MD5CryptoServiceProvider hashes the email and a StringBuilder converts this to the required format:

if( !string.IsNullOrEmpty( Email))
{
    // build up image url, including MD5 hash for supplied email:
    MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
    UTF8Encoding encoder = new UTF8Encoding();
    MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
    byte[] hashedBytes = md5Hasher.ComputeHash(encoder.GetBytes(Email));
    StringBuilder sb = new StringBuilder(hashedBytes.Length * 2);
    for (int i = 0; i < hashedBytes.Length; i++)
    {
        sb.Append(hashedBytes[i].ToString("X2"));
    }
    // output parameters:
    imageUrl += "gravatar_id=" + sb.ToString().ToLower();
    imageUrl += "&rating=" + MaxAllowedRating.ToString();
    imageUrl += "&size=" + Size.ToString();
}

The final part of the method assigns a default image, if one has been specified, outputs the site ink, if required, outputs the required attributes and tags.

// output default parameter if specified
if (!string.IsNullOrEmpty(DefaultImage))
{
    imageUrl += "&default=" + HttpUtility.UrlEncode(DefaultImage);
}
// if we need to output the site link:
if (OutputGravatarSiteLink)
{
    output.AddAttribute(HtmlTextWriterAttribute.Href, "http://www.gravatar.com");
    output.AddAttribute(HtmlTextWriterAttribute.Title, LinkTitle);
    output.RenderBeginTag(HtmlTextWriterTag.A);
}
// output required attributes/img tag:
output.AddAttribute(HtmlTextWriterAttribute.Width, Size.ToString());
output.AddAttribute(HtmlTextWriterAttribute.Height, Size.ToString());
output.AddAttribute(HtmlTextWriterAttribute.Src, imageUrl);
output.AddAttribute(HtmlTextWriterAttribute.Alt, "Gravatar");
output.RenderBeginTag("img");
output.RenderEndTag();
// if we need to output the site link:
if (OutputGravatarSiteLink)
{
    output.RenderEndTag();
}

Using the control on your own projects

As previously mentioned, the download solution will not open properly in Express versions of Visual Studio, since it does not support control projects, but the control, included in the download is supported by all versions of Visual Studio, 2005 and later.

The easiest way to use the control is to add the control to the toolbox. To do this, ensure that you are in design mode (looking at a web page), and right click on the ‘Standard’ group header of the Toolbox. From the context menu, select “Choose Items” and browse to the assembly (Freshclickmedia.Web.dll), and click “OK” to add.

Adding the control to the toolbox

Once you’ve added the assembly, you should see the following:

Gravatar Toolbox Item

From there, you can drag the control onto your page and start having fun!