.Net Development


.Net Development20 Sep 2010 06:35 am

I have always had a love/hate relationship with ResXFileCodeGenerator and the StronglyTypedResourceBuilder and the code it generated. Simplified access to string resources and the elimination of string literals in user code is a great thing, but what if I need slightly different generated code? Generated code that you can’t modify is very often a two edged sword.

The only alternative that I have seen offered is to write your own Visual Studio plug in to replace ResXFileCodeGenerator as Dmytro Kryvko has done in his CodeProject article.

I have not had good luck with writing my own VS Pug-ins. All those methods that return object and you have to know what to cast them to, the undocumented property bags, etc. It is just not the kind of framework I like to work with. Moreover, an installed plug-in is harder to use on a distributed team, and what if you want different customizations for different projects?

Stealing shamelessly from the T4MVC template by David Ebbo, my solution to all of this is T4resx.tt. What it does is find all the .resx files in a project and generate output nearly identical to what the Microsoft tools generates. I say nearly identical because, I have of course tweaked it to my liking.

Specific changes I have made:

  • I have neglected to include the attributes marking the code and auto-generated and non-user code. (Since the generated code can now become as complex as you like, its good to be able to step into it.)
  • The accessor members are public vs. internal to make them easy to reference from MVC Views.
  • I have added support for named tokens in the resource strings.
  • I have added support for returning HtmlString wrapped strings.
  • Defined constants for each resource name (for use as attribute parameters such as are needed to work with the validation attributes in the System.ComponentModel.DataAnnotations namespace). These constants are defined in the “Names” inner class within each resource accessor class.

I will talk more about some of these changes below. Many of them are very similar to what Dmytro did in his plug-in. The real advantage to the T4 approach though is that, being a text template, the code is highly accessible to the developer and easily modified to support generating the code that you want. Moreover, each project gets its own template (or you can share one among all projects in a solution if you like). Your are not locked into the same generated code for each project. Lastly, the template is part of the project source code tree so distributing it and keeping it up to date across a team becomes a simple function of source control.

Token Replacement Coolness

The biggest change to the generated code is the ability to do things like this: Create a resource string named OrderSuccessMessage with a value of “Thank you for your order. Your order confirmation number is {OrderNumber}. You will receive an e-mail shortly with this informaiton.” ResXFileCodeGenerator will create a property like so:

public static string OrderSuccessMessage { get { return ... ; } }

The T4resx template will generate the following method:

public static string OrderSuccessMessage(string OrderNumber)  
{ 
    return ... ; 
}

If the string has no tokens in it, the template will generate a property instead of a method. This is because the DataAnnotation validation attributes when used with resource accessor types use reflection to call the member and they expects the member to be a property. This means you cannot embed tokens in resources that are intended to be used by the DataAnnotations framework. But that is okay. How would the framework know what values to provide in the first place?

Support for HTML strings

If a resource string value is prefixed with the token “HTML:”, it is presumed to contain formatted HTML. In this case, you presumably don’t want the MVC framework to encode it. To fix that problem, if the HTML: tag is found, the template strips it off but returns the string wrapped in an HtmlString so that MVC will not HTML encode it. This is very handy for putting bulk page content into a resource and then emitting it as follows:

<%@ Import Namespace="Localized=MyWebSite.Resources.Views.Home.Index" %>
<div id="mainContent">
    <%: Localized.PageConent %>
</div>

Note that the “Localized” alias for the resource accessor class is not part of the template (yet) but is my convention for making things more readable and reduce typing.

Some Caveats

Of course one disadvantage of T4 templates is that, unlike a VS plug in, they are not language independant. My template generates C# code. It wouldn’t take too much to come up with a VB version but if you needed to maintain VB and C# versions, this could be a headache.

Also, because the template emits classes that are named identically to the ones that ResXFileCodeGenerator creates, it is necessary, after creating each resource file in your project, to go into its properties and remove the reference to ResXFileCodeGenerator by clearing the “Custom Tool” property. Otherwise, the two tools will generated competing class declarations and your build will fail.

I find that getting rid of ResXFileCodeGenerator, because it eliminates the plus signs and child .designer.cs files in the solution explorer has the added aethetic advantage of making the solution tree all that much cleaner.

As with most T4 templates, the generated code now becomes a child file of the template itself. So if you want to find the generated code, look for the T4Resx.cs file as a child of the T4Resx.cs file, wherever you put that.

Lastly, this is my first attempt at writing a T4 template. I am very open to critique. Please leave comments.

Future Plans

Eventually, if people like the “Localized” alias convention, I may set the template up to insert these import statements (or using statements as appropriate) in each class for which there is a matching .resx class.

I would also like to add support for tags of the format {AmountDue=decimal:C} where decimal is the type of the input argument into the method and “C” is the string format to use when converting it to text. I am not settled on the best syntax for these tags though.

Another feature I would like to add is the comparison of the default .resx file and localized versions (.de.resx, etc.) to ensure that any tokens specified in the default version are specified in the localized ones. Right now if a token is missing in the localized version, the value passed to the accessor method is simply ignored. Conversely, if the localized resource file contains tokens not in the default file, they are not processed and remain in the returned string.

I thoroughly tested the code generated against all the scenarios outlined by Alexander Adamyan in his thorough article ASP.NET MVC 2 Localization complete guide to make sure I have all the bases covered. Following on his example of subclassing the DisplayName attribute, I am considering subclassing all the DataAnnotation validation attributes to use a by-convention approach to finding the appropriate resource strings. This doesn’t have so much to do with the T4 template itself but it strikes me as a good next step in reducing the redundant code needed to perform localization.

Download the Template

Download the template here: T4resx.zip

.Net Development11 Jun 2010 05:34 pm

I spent a few hours yesterday piecing together the needed code to create a single instance (non-re-entrant) WPF desktop application. There are lots of examples out there of how to do this.  All the ones I could find fall short however, in that, if they detect that a prior instance is open, the just display a message box telling the user that another instance is already running. I wanted something more user friendly, namely to bring the running instance to the foreground. In my experience, this is the expected behavior for non-reentrant applications.

I discovered that the reason all the examples take the easy way out is that it can’t be done in .Net directly. To bring another window to the foreground, you have to make native Win32 API calls. Ugh!

I finally found this worth-while article on how to do what I wanted in WinForms, and combining that with the information found in this StackOverflow post, I updated the solution for Windows Presentation Foundation and encapsulated it all in a the following handy class.

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
 
namespace SIPC.SLS.ClaimsProcessing.ProcessorWpfApp.Application
{
    internal class SingleInstanceEnforcementUtility : IDisposable
    {
        private Mutex _mutex;
        private Window _mainApplicationWindow;
        private bool _isDisposed;
 
        #region Win32 API Interop
        private const int HWND_BROADCAST = 0xffff;
        private const string UNIQUE_MUTEX_NAME = "{490D60C5-A51C-4c10-ADDE-47B4EECF9EE0}";
        private static readonly int WM_MOVE_TO_TOP = RegisterWindowMessage("WM_MOVE_TO_TOP" + UNIQUE_MUTEX_NAME);
 
        [DllImport("user32")]
        private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
        [DllImport("user32")]
        private static extern int RegisterWindowMessage(string message);
        #endregion
 
        public void EnforceSingleApplicationInstance()
        {
            bool isOwned;
            _mutex = new Mutex(true, UNIQUE_MUTEX_NAME, out isOwned);
 
            if (isOwned) return;
 
            //Broadcast to all open windows the custom move to top command
            //(Will be ignored by any window that does not recongize it);
            PostMessage((IntPtr)HWND_BROADCAST,
                        WM_MOVE_TO_TOP,
                        IntPtr.Zero,
                        IntPtr.Zero);
 
            Environment.Exit(0);
        }
 
        public void RegisterMainApplicationWindow(Window window)
        {
            //Hook into window message processing loop to watch for our custom message
            _mainApplicationWindow = window;
            var source = PresentationSource.FromVisual(window) as HwndSource;
            if (source != null) source.AddHook(HandleWindowsMessage);
        }
 
        private IntPtr HandleWindowsMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_MOVE_TO_TOP)
                MoveWindowToTopOfDesktop();
 
            return IntPtr.Zero;
        }
 
        private void MoveWindowToTopOfDesktop()
        {
            if (_mainApplicationWindow.WindowState == WindowState.Minimized)
            {
                _mainApplicationWindow.WindowState = WindowState.Normal;
            }
 
            // get our current "TopMost" value
            var top = _mainApplicationWindow.Topmost;
            // make our form jump to the top of everything
            _mainApplicationWindow.Topmost = true;
            // set it back to whatever it was
            _mainApplicationWindow.Topmost = top;
        }
 
        public void Dispose()
        {
            if(_isDisposed) return;
            _isDisposed = true;
 
            if(_mutex != null) _mutex.ReleaseMutex();
        }
    }
}

With this class in place, you can a create a non-reentrant WPF application like so:

[System.STAThreadAttribute()]
static void Main()
{
	using(var sieu = new SingleInstanceEnforcementUtility())
	{
		sieu.EnforceSingleApplicationInstance();
 
		var app = new MyApplication();
		app.InitializeComponent();
 
		sieu.RegisterMainApplicationWindow(app.MainWindow);
 
		app.Run();
	}
}

You will probably also want to change the UNIQUE_MUTEX_NAME, just in case you application ever gets installed on the same machine as mine! 🙂

Happy coding!
–Ken

.Net Development10 Mar 2010 09:50 pm

I have found that the DefaultModelBinder, when binding to arrays, has an irritating quirk; dare I say bug? If the array is already instantiate in the model, the model binder will attempt to call .Clear() and then .Add() on the array (because all arrays support the IList interface). However arrays are fixed size lists. (IList.IsFixedSize returns true.) As a result, calling .Clear() throws a NotSupportedException as shown in the following stack trace:

System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
--System.NotSupportedException : Collection is read-only.
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, ref SignatureStruct sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at System.Web.Mvc.DefaultModelBinder.CollectionHelpers.ReplaceCollection(Type collectionType, Object collection, Object newContents)
at System.Web.Mvc.DefaultModelBinder.UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at ArrayModelBinderTests.DefaultModelBinder_should_sould_fail_to_bind_to_non_null_arrays_in_model() 
--NotSupportedException
at System.SZArrayHelper.Clear()
at System.Web.Mvc.DefaultModelBinder.CollectionHelpers.ReplaceCollectionImpl(ICollection`1 collection, IEnumerable newContents)

In my humble opinion, what the model binder should do in the case of arrays is to ignore any already instantiated model and instead always create a new one and return it. This is what it does when there is no pre-existing instance. (i.e the model is null).

Why is this important you may ask? I mean, in general when binding to a model, the binder is creating the model from scratch anyway so won’t the array always be null? Well not always. Consider the following model:

public class FamilyModel
{
    public string MyName { get; set; }
    public string MyWifesName { get; set; }
 
    private string[] _myChildrensNames;
    public string[] MyChildrensNames
    { 
        get 
        { 
            return _myChildrensNames 
                ?? (_myChildrensNames = new string[0]);
        }
        set { _myChildrensNames = value; }
    }
}

In this case, in order to avoid the need to check MyChildrensNames for null every time it is accessed, we ensure that it is never null. If I have no children, the property reasonably returns an empty collection. This is an example of the null object pattern.

Given such a model, we will encounter the described problem every time we attempt to bind to it.

To resolve this, I have written the following model binder which can be registered for any type of array. It uses something akin to a decorator pattern to wrap the default model binder. The decorator simply forces the model to null before invoking the default binder, effectively sidestepping the problem.

public class ArrayModelBinder : DefaultModelBinder
{
	public override object BindModel(
            ControllerContext controllerContext, 
            ModelBindingContext bindingContext)
	{
		var originalMetadata = bindingContext.ModelMetadata;
 
		bindingContext.ModelMetadata = new ModelMetadata(
			ModelMetadataProviders.Current,
			originalMetadata.ContainerType,
			() => null,  //Forces model to null
			originalMetadata.ModelType,
			originalMetadata.PropertyName
			);
 
		return base.BindModel(controllerContext, bindingContext);
	}
}

You can download the complete source and unit tests here.

« Previous PageNext Page »