Wednesday, October 29, 2008

Really Strange C# Scope Syntax

Did you know you can define a separate variable scope within a C# method? I'm not sure why you would ever want to use this syntax, but it's there if you want it. Simply open a set of squiggly brackets within your method, and define variables within the brackets. The variables will be out of scope when you leave the brackets. Thus, the following code compiles just fine:


public void Run()

{

    int value = 0;

 

    {

        int innervalue = 2;

        Console.WriteLine(innervalue);

    }

 

    {

        string innervalue = "string";

        Console.WriteLine(innervalue);

    }

 

    Console.WriteLine(value);

}

It's important to note that there's nothing especially different about how the C# compiler compiles this code. The declared variables aren't popped from the stack until the method leaves, and nothing unusual happens to them during the execution of the method. All of these values remain on the stack (or the heap) until the method returns. In fact, in the example above, the compiler actually renames the second "innervalue" local variable as "V_2", and references it that way in the IL. So this is just a feature of the language.

Nevertheless, it's a fun trick to show your friends at all your coding parties.

This just goes to show that scope is as simple as knowing that any variables declared within squiggly brackets in C# are unavailable outside the squiggly brackets.

Tuesday, October 21, 2008

Extension Methods Don't Throw NullReferenceException!

Did you know that an extension method will not throw a NullReferenceException unless you explicitly tell it to? Because an extension method is technically not part of an instance of an object, they won't throw NullReferenceExceptions when the value from which they're called is null. Here's an example:


class ExtensionMethodTest

{

    public void Run()

    {

        string value = null;

        value = value.IfNull("Other");

        Console.WriteLine(value);

    }

}

 

static class StringExtensions

{

    public static string IfNull(this string value, string alternate)

    {

        if (String.IsNullOrEmpty(value))

            return alternate;

        return value;

    }

}


Add this to your code and call the Run() method. You'll notice that even though the variable value is null, it won't throw a NullReferenceException at runtime.

Wednesday, October 8, 2008

Ajax calls, Internet Explorer, and Caching

Tip of the day: Internet explorer caches HTTP GET requests when called through AJAX.

Now, why does this apply to you?

The reason this is important is in situations where you rapidly call an HTTP GET method from javascript. If you make the calls too rapidly in succession, you'll get the same information from each call, regardless of the .NET implementation of your web service. In fact, if you call them too quickly in succession, IE doesn't even make the call to the web service, but instead returns the cached data.

Let's say you have a web method called "GetNewRandom()". (This is definately an ironic name, given that calls to the Random class repeats the same values when called in rapid-fire succession.) Now, let's say you've decorated your GetNewRandom class like this:



[WebMethod(true)]

[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]

public Int32 GetNewRandom()

{

    Byte[] bytes = new Byte[4];

    new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(bytes);

    return BitConverter.ToInt32(bytes, 0);

}



Now, let's say you need to call this repeatedly over and over again quickly. Apparently, since the header for this call is identical each time you call it, Internet Explorer will actually cache the value on the client, assuming that the data that will be returned will be the same as it was the time before, and you'll get the same value repeated, until IE deems the cached data worthy of deletion and refreshing. This can be extremely problematic.

The solution?

Set UseHttpGet to "false" if you absolutely, positively need new data every single time. IE doesn't cache the HTTP POST.

Tuesday, October 7, 2008

A Simple DocBrowser Control

I feel like giving away things for free today! Here's a simple DocBrowser user control that does nothing but display a Word Document in a WebBrowser Control. I've documented the code to enable you, my reader, to understand exactly what's going on. I encourage you to take this, use this, and enjoy it.

Make sure you add a reference to Microsoft.Office.Interop.Word in your project in order for this to work. I used the Office 2007 Libraries for this.


using System;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Office.Interop.Word;
using System.IO;

namespace WordControls
{
public partial class DocBrowser : UserControl
{
private System.Windows.Forms.WebBrowser webBrowser1;

delegate void ConvertDocumentDelegate(string fileName);

public DocBrowser()
{
InitializeComponent();

// Create the webBrowser control on the UserControl.
// This code was moved from the designer for cut and paste
// ease.
webBrowser1 = new System.Windows.Forms.WebBrowser();

webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
webBrowser1.Location = new System.Drawing.Point(0, 0);
webBrowser1.MinimumSize = new System.Drawing.Size(20, 20);
webBrowser1.Name = "webBrowser1";
webBrowser1.Size = new System.Drawing.Size(532, 514);
webBrowser1.TabIndex = 0;

Controls.Add(webBrowser1);

// set up an event handler to delete our temp file when we're done with it.
webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted;
}

string tempFileName = null;

public void LoadDocument(string fileName)
{
// Call ConvertDocument asynchronously.
ConvertDocumentDelegate del = new ConvertDocumentDelegate(ConvertDocument);

// Call DocumentConversionComplete when the method has completed.
del.BeginInvoke(fileName, DocumentConversionComplete, null);
}

void ConvertDocument(string fileName)
{
object m = System.Reflection.Missing.Value;
object oldFileName = (object)fileName;
object readOnly = (object)false;
ApplicationClass ac = null;

try
{
// First, create a new Microsoft.Office.Interop.Word.ApplicationClass.
ac = new ApplicationClass();

// Now we open the document.
Document doc = ac.Documents.Open(ref oldFileName, ref m, ref readOnly,
ref m, ref m, ref m, ref m, ref m, ref m, ref m,
ref m, ref m, ref m, ref m, ref m, ref m);

// Create a temp file to save the HTML file to.
tempFileName = GetTempFile("html");

// Cast these items to object. The methods we're calling
// only take object types in their method parameters.
object newFileName = (object)tempFileName;

// We will be saving this file as HTML format.
object fileType = (object)WdSaveFormat.wdFormatHTML;

// Save the file.
doc.SaveAs(ref newFileName, ref fileType,
ref m, ref m, ref m, ref m, ref m, ref m, ref m,
ref m, ref m, ref m, ref m, ref m, ref m, ref m);

}
finally
{
// Make sure we close the application class.
if (ac != null)
ac.Quit(ref readOnly, ref m, ref m);
}
}

void DocumentConversionComplete(IAsyncResult result)
{
// navigate to our temp file.
webBrowser1.Navigate(tempFileName);
}

void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
if (tempFileName != string.Empty)
{
// delete the temp file we created.
File.Delete(tempFileName);

// set the tempFileName to an empty string.
tempFileName = string.Empty;
}
}

string GetTempFile(string extension)
{
// Uses the Combine, GetTempPath, ChangeExtension,
// and GetRandomFile methods of Path to
// create a temp file of the extension we're looking for.
return Path.Combine(Path.GetTempPath(),
Path.ChangeExtension(Path.GetRandomFileName(), extension));
}
}
}

Here's a simple form I built with the control. The button's event handler simply calls LoadDocument on the DocBrowser control, which is the main portion of the screen. I opened some notes from when I was studying for the 70-536 exam.

Saturday, October 4, 2008

Changing Attribute Parameters at Runtime

A question was asked on the C# forums yesterday regarding how to set a field in a PropertyGrid to readonly during runtime. Just in case you're not familiar with the PropertyGrid in C#, it's the control you use to set items in the "Properties" window in Visual Studio. Unfortunately, the .NET implementation of this control for use in Windows Forms is pretty basic and doesn't provide much functionality in the way of setting certain fields to readonly, etc. Instead, it depends on the attributes applied to the object it's editing to determine it's behavior. For instance, to make a property reaonly within the PropertyGrid, the ReadOnlyAttribute needs to be applied to that property within the object the PropertyGrid is editing. This makes things a little more difficult from a runtime perspective, because attribute values cannot easily be set at runtime. Nevertheless, what follows are detailed instructions on how to do just that, and have the PropertyGrid update itself accordingly.

Follow along with my example:

1. Create a new Windows Forms project.

2. Add the following class to your project:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
 
namespace WindowsFormsApplication1
{
public class Employee
{
string name;
bool isMarried;
string spouseName;
 
public string Name
{
get { return name; }
set { name = value; }
}
 
public bool IsMarried
{
get { return isMarried; }
set
{
isMarried = value;
 
// set the spouseName to empty if the employee is not married.
if (!value)
spouseName = string.Empty;
}
}
 
public string SpouseName
{
get { return spouseName; }
set { spouseName = value; }
}
}
}
3. Add a PropertyGrid to your form, leaving the default name of "propertyGrid1".

4. Add the following line to the form's constructor, just after the call to InitializeComponent():


propertyGrid1.SelectedObject = new Employee();
5. Run the project.

You should see a screen like this:



Add some text in the SpouseName field, and then double click on the IsMarried value a couple of times. Notice that when the IsMarried property is set to true, the SpouseName field is set to an empty string. This is because we're changing the value within our class to an empty string if the IsMarried property is false. We really don't want a spouse for the employee, if the employee isn't married. Here's the problem however: you could set the IsMarried field to false, and still have a SpouseName value, simply by setting the SpouseName field after setting the IsMarried value to false. Of course, this isn't what we want. It would be far more user friendly to simply disable that entire field, and prevent the user entirely from changing the SpouseName in the PropertyGrid.

Let's add the ReadOnlyAttribute to the SpouseName property in the object:


[ReadOnly(true)]
public string SpouseName
{
get { return spouseName; }
set { spouseName = value; }
}
Now, rerun the application. The form now looks like this:



Notice the SpouseName is readonly, but it's permanently readonly. That's not what we want either. We only want SpouseName to be readonly when IsMarried is set to false. So here's the solution. We need to manually change the ReadOnly value of this specific ReadOnlyAttribute at runtime. I grabbed a copy of Lutz's .NET Reflector and browsed the internal workings of the ReadOnlyAttribute class. I found that there's actually an internal field called "isReadOnly" that determines whether the ReadOnly property of the ReadOnlyAttribute is true or false. Using TypeDescriptor, PropertyDescriptor and Reflection, I can set this value at runtime, and then I can notify the PropertyGrid to refresh all the data.

Change your IsMarried property to this:


[RefreshProperties(RefreshProperties.All)]
public bool IsMarried
{
get { return isMarried; }
set
{
isMarried = value;
 
// set the spouseName to empty if the employee is not married.
if (!value)
spouseName = string.Empty;
 
// Create a PropertyDescriptor for "SpouseName" by calling the static GetProperties on TypeDescriptor.
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this.GetType())["SpouseName"];
 
// Fetch the ReadOnlyAttribute from the descriptor.
ReadOnlyAttribute attrib = (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];
 
// Get the internal isReadOnly field from the ReadOnlyAttribute using reflection.
FieldInfo isReadOnly = attrib.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
 
// Using Reflection, set the internal isReadOnly field.
isReadOnly.SetValue(attrib, !value);
 
}
}
Now run your application again. You should notice now, that when you set the IsMarried property to false, the SpouseName becomes readonly, but when the IsMarried property is set to true, you can edit the field. There's two reasons for this:

1. We've added the RefreshPropertiesAttribute to the property. This ensures that the PropertyGrid is refreshed whenever that particular property is changed, forcing the PropertyGrid to reload all the property attributes on the object.

2. We've manually changed the ReadOnly property on the ReadOnly attribute of the SpouseName property to false within the setter for IsMarried. The PropertyGrid will reload this attribute now when refreshing itself.

There are several applications for this, the biggest of which being conditional readonly properties on certain user controls that can be designed within Visual Studio. Other applications could be for applications that want to use the built-in functionality of PropertyGrid to edit business objects at runtime.