Thursday, 16 September 2010

MVC Bug: The virtual path '[path]' maps to another application, which is not allowed

I’ve being doing a lot of work on Asp.Net MVC (now v2) over the past few months and, firstly, I have to say that it totally rocks.

I will not go into any real detail about MVC here – this post is about the method System.Web.Mvc.HtmlHelper.AntiForgerytoken and that it highlights a bug in an internal class TokenPersister that you’re potentially going to get if you ever use spaces in your virtual directory names.  Ironically, the class in question is marked with a comment that says it’s difficult to unit test because of the way it fakes Asp.Net requests – ironic that it should be such a class in which we find a bug!  A better argument for unit-testing you’re unlikely to find.

Detail – Reproduce that bug

Using MVC it’s very easy to reproduce.  I should start by declaring my system configuration:

  • Windows 2008 R2
  • IIS 7.5 installed and configured
  • Visual Studio 2008 with all service packs etc
  • .Net 3.5 sp1 plus security patches

VS2010 and .Net 4 are also on this machine – and I would welcome anybody following the same steps to confirm that i:

  1. Create a new Asp.Net MVC2 Web Application (from the template) called ‘Asp Net Bug 2008’
    • Don’t bother with the unit tests project
  2. Open the project web properties, and set the project to use the Local IIS Web Server, the location should automatically be set to http://localhost/Asp Net Bug 2008/ (you might need to add the trailing slash here) – the spaces here are important so leave them in.
    • Create the Virtual Directory
    • Don’t forget to save the project file afterwards (like I just did as I created this walkthrough!)
  3. Open the view Views/Account/Register.aspx
  4. Just after the line
    1. <% using (Html.BeginForm()) { %>
    Add the following:
    1. <%= Html.AntiForgeryToken() %>
  5. Compile and run
  6. Navigate to the [Log On] link at the top of the page
  7. Hit the ‘Register’ link

You will see this exception helper:

 mvcexception

And then on the Asp.Net error page, you’ll see this stack trace:

[ArgumentException: The virtual path '/Asp%20Net%20Bug%202008/Account/Register' maps to another application, which is not allowed.]
System.Web.CachedPathData.GetVirtualPathData(VirtualPath virtualPath, Boolean permitPathsOutsideApp) +11193138
System.Web.HttpContext.GetFilePathData() +61
System.Web.Configuration.HttpCapabilitiesBase.GetBrowserCapabilities(HttpRequest request) +124
System.Web.HttpRequest.get_Browser() +168
System.Web.UI.Page.SetIntrinsics(HttpContext context, Boolean allowAsync) +207
System.Web.UI.Page.ProcessRequest(HttpContext context) +232
System.Web.Mvc.TokenPersister.CreateFormatterGenerator() +459
System.Web.Mvc.FormatterGenerator..cctor() +10

[TypeInitializationException: The type initializer for 'FormatterGenerator' threw an exception.]
System.Web.Mvc.AntiForgeryDataSerializer.get_Formatter() +38
System.Web.Mvc.AntiForgeryDataSerializer.Serialize(AntiForgeryData token) +181
System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path) +405
System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path) +13
System.Web.Mvc.HtmlHelper.AntiForgeryToken() +17
ASP.views_account_register_aspx.__RenderregisterContent(HtmlTextWriter __w, Control parameterContainer) in c:\Users\andras.zoltan\documents\visual studio 2008\projects\aspnetbug2008\aspnetbug2008\Views\Account\Register.aspx:17
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +115
ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\Users\andras.zoltan\documents\visual studio 2008\projects\aspnetbug2008\aspnetbug2008\Views\Shared\Site.Master:26
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +115
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +240
System.Web.UI.Page.Render(HtmlTextWriter writer) +38
System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +89
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4240

A closer look at this, you’ll see that the method GetBrowserCapabilities, called from the accessor of the HttpRequest.Browser is the culprit.  Opening Reflector, we see that this method is attempting to load the site configuration (web.config presumably) – which is where GetVirtualPathData comes in.  When I was confronted with this issue, it was obvious that the check which determines if the current request is in the current application root was failing.  So the first thing I thought was to change our app root to be something more friendly.


The Fix


Take the spaces out of the virtual directory name; perhaps replacing with hyphens, or just zeroing them down completely.  It’ll now work perfectly.


The Cause


Well, of course I haven’t analysed down to the last IL opcode here, but the first thing I thought was whether or not this was an Asp.Net bug, since the last few items in the call stack are from there.  So you can try another test, if you simply add a standard WebForm to the project (making sure it’s hosted in a vdir again that has spaces in it), and put in the following:





  1. <%= (Request.Browser!=null).ToString() %>

Compile and run that, and you’ll correctly get ‘True’ output in the page.  So, when the current HttpRequest is produced from the normal Asp.Net pipeline, everything works correctly.


So, let’s take another look at that stack trace – we have the call to

System.Web.Mvc.TokenPersister.CreateFormatterGenerator
Which the yields a call to
System.Web.UI.Page.ProcessRequest

But we’re already in that method further down, so why?


The reason can be found if you open CreateFormatterGenerator, either by getting the source code from CodePlex or by opening reflector.  Let’s take a look at the method body (which I have ripped straight out of the published project from CodePlex):





  1. public static Func<IStateFormatter> CreateFormatterGenerator()
  2. {
  3.     // This code instantiates a page and tricks it into thinking
  4.     // that it's servicing a postback scenario with encrypted
  5.     // ViewState, which is required to make the StateFormatter
  6.     // properly decrypt data. Specifically, this code sets the
  7.     // internal Page.ContainsEncryptedViewState flag.
  8.     TextWriter writer = TextWriter.Null;
  9.     HttpResponse response = new HttpResponse(writer);
  10.     HttpRequest request = new HttpRequest("DummyFile.aspx",
  11.         HttpContext.Current.Request.Url.ToString(), "__EVENTTARGET=true&__VIEWSTATEENCRYPTED=true");
  12.     HttpContext context = new HttpContext(request, response);
  13.  
  14.     Page page = new Page()
  15.     {
  16.         EnableViewStateMac = true,
  17.         ViewStateEncryptionMode = ViewStateEncryptionMode.Always
  18.     };
  19.     page.ProcessRequest(context);
  20.  
  21.     return () => new TokenPersister(page).StateFormatter;
  22. }

Well, the embedded comment there explains what’s going on – and it’s this fake request that’s causing the problem, clearly.  Whatever it is that Asp.Net does to make sure we don’t get this error on a standard WebForm is not being done properly – although I’m not sure what that could be.  My initial guess is that the %20 is being compared to the space in the path name, rather than being url-decoded first – and therefore a simple fix might be to change the call to HttpContext.Current.Request.Url.ToString() on the fourth code line above to pass in the url-decoded string.  If I was feeling ambitious, I’d hack into the project and pursue a fix.  However, my primary feeling is to report it to the Mvc team – which I have done here.

Serializing to attributes in WCF with DataContractSerializer

It’s a common problem – you want to return an object from a WCF service as XML, but you either want, or need, to deliver some or all of the property values as XML Attributes instead of XML Elements; but you can’t because the DataContractSerializer doesn’t support attributes (you’re most likely to have seen this StackOverflow QA if you’ve done a web search).  Most likely you’ve then migrated all your WCF service code to using the XmlSerializer (with all the XmlElement/XmlAttribute/XmlType attributes et al) – and you’ve cursed loudly.

Well, I’m here to rescue you, because it is possible – and the answer to the problem is actually inferred from the MSDN article entitled ‘Types supported by the Data Contract Serializer’.

The example I’m going to give is purely for illustration purposes only.  I don’t have a lot of time, so work with me!

  • Create a new Asp.Net WCF service application, you can use Cassini as your web server (probably easier – otherwise you might have to enable Asp.Net compatibility mode).
  • Open the web.config and delete the <service> element that was created for the new service.
  • The interface and implementation model for this example is overkill.  Move the [ServiceContract] and [OperationContract] declarations from the interface that was created for you new service to the class that was also created.  Delete the interface.
  • Open the .svc markup file and add the following at the end: Factory="System.ServiceModel.Activation.WebServiceHostFactory" – this enables the zero-configuration WCF model for this service (we’re going to create a RESTful service).
  • Paste the following class declarations into your svc codebehind:
public interface IExampleData
{
	string Description { get; set; }
	string Name { get; set; }
	int ID { get; set; }
}
public class ExampleData : IExampleData
{
	public string Description { get; set; }
	public string Name { get; set; }
	public int ID { get; set; }
}
public class ExampleDataAttributed : ExampleData, IXmlSerializable
{
	#region IXmlSerializable Members
	public System.Xml.Schema.XmlSchema GetSchema()
	{
		return null;
	}
	public void ReadXml(System.Xml.XmlReader reader)
	{
		//implement if remote callers are going to pass your object in
	}
	public void WriteXml(System.Xml.XmlWriter writer)
	{
		writer.WriteAttributeString("id", ID.ToString());
		writer.WriteAttributeString("name", Name);
		//we'll keep the description as an element as it could be long.
		writer.WriteElementString("description", Description);
	}
	#endregion
}

Just to demonstrate the point, the class that will be part-serialized to attributes simply derives from one that will be serialized as normal.



  • Now add the following two methods to your service class:
[OperationContract]
[WebGet(UriTemplate = "/test1")]
public ExampleData Test1()
{
	return new ExampleData() { ID = 1, 
Name = "Element-centric",
Description =
"The contents of this item are entirely serialized to elements - as normal" };
}
[OperationContract]
[WebGet(UriTemplate = "/test2")]
public ExampleDataAttributed Test2()
{
	return new ExampleData_Attributed() { ID = 2, 
Name = "Mixed",
Description =
"Everything except this description will be serialized to attributes" };
}

Cover, and bake for 40 minutes (that is – Build it).


If you left your service as Service1.svc, then run it and open up IE and browse to http://localhost:[port of cassini]/test1


The result should look something like this:

<JSLabs.ExampleData 
 xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace" 
 xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
	<Description>
		The contents of this item are entirely serialized to elements - as normal
	</Description>
	<ID>
		1
	</ID>
	<Name>
		Element-centric
	</Name>
</JSLabs.ExampleData>

Now browse to http://localhost:[port of cassini]/test2

<JSLabs.ExampleDataAttributed id="2" name="Mixed" 
  xmlns="http://schemas.datacontract.org/2004/07/JobServe.Labs.Web">
	<description>Everything except this description will be 
	serialized to attributes</description>
</JSLabs.ExampleDataAttributed>

It’s made a little less impressive by that nasty ‘orrible “xmlns=” attribute that the WCF data contract serializer automatically puts on the type – but, as you can see, the ‘ID’ and ‘Name’ properties have indeed been pushed out as attributes!


We could have made both methods return IExampleData and then used the KnownType attribute on that interface in order to get it to support either (according to what the code of the methods returned).


To support deserializing an object from the attributes, all you have to do is to implement the IXmlSerializable.ReadXml method.


Finally, as the aforementioned MSDN article says about the supported types – you should also be able to use XmlElement/XmlNode types as a way of representing XML directly – the DataContractSerializer, like in this case, take the short route and simply gets the Xml.


This also shouldn’t affect JSON formatting if you’re dual-outputting objects for either XML or JSON clients.

Enabling Custom Username/Password Authentication WCF in IIS

A couple of posts back I was bemoaning the inability to use custom username/password authentication for all endpoints (WsHttp, BasicHttp and WebHttp) for a WCF service hosted in IIS.  The problem arises when you get to the WebHttp binding, because you can’t use message-level authentication (since it’s just a JSON packet), therefore you have to use Transport-level authentication.  Then you get to the biggest issue - that using Transport-level means having to use Basic/Windows/Digest authentication and IIS always automatically intercepts those authentication headers and attempts to authenticate to the server’s default windows account store (typically the domain it’s on, or it’s own local user store).

In this case, even if you configure your Custom UserName Password validator, it’ll never fire.

My solution to do a full, roll-your-own solution using Message Inspectors etc.  This still wouldn’t have solved the JSON problem fully, but it did mean that I could use my own Http headers to transmit my secure credentials.

I had a thought, though – what if IIS’ authentication could be extended, so that Basic authentication headers could be used on a per-endpoint basis (meaning that I was still free to use message-level for SOAP and Ws-Http if need-be)?

My initial google results were poor, and so I decided to use the MSDN Forums to get some ideas.  Needless to say – the answer that Marco Zhou has been exactly the thing I was looking.  All I did was to download the source for the excellent CustomBasicAuth project from CodePlex, and by following Dominick’s walkthrough was then able to extrude my own implementation that I could then plug into any WCF service.

The extra upshot of doing all this was that I can now use Role-based security on all my WCF methods, and the client just has to know how to send the credentials according to the type of endpoint they are using.  With the JSON endpoints I’m using the trick I posted earlier on how to intercept web service calls from Asp.Net Ajax client code in order to inject extra headers, but with the SOAP endpoints (currently from Silverlight) I’m using message-level headers and a Message Inspector (TIP – if you follow the CustomBasicAuth walkthrough exactly, you’ll add an Authorization provider to your WCF service.  If you then implement a message inspector to extract authentication details from a SOAP message, you can set the current Principal in that code – but here’s the beauty of it – it happens before WCF security kicks in, so the same Authorization provider will also work!).

So while it is a bit of a pain – once you’ve got the skeleton up and running, it’s actually pleasingly simple.

WCF URI Template Url-Encoded Character Issues

I've been playing around with RESTFul services in WCF following by the MSDN topic, and have found the guide to be both extremely helpful, and the overall support provided to be excellent.  If you've been writing WCF services for your cloud service offerings, or even just AJAX methods for web-page code, you should find the migration over to RESTful services relatively easy to manage.

It also increases the accessibility of your services a huge amount - very basic jQuery code can be used, for example, to bind to these services.

However, there are some issues surrounding the types of values for parameters that can be bound in either a path or query string segment - and it's all down to some url-encoded characters, and how they get interpreted (or rather not interpreted) before being serialised into method parameters.

The following example is taken from a Microsoft Connect bug that I have posted:

Setup a project to host a WCF .svc and create a method with two parameters:

[WebGet(UriTemplate = "{willfail}?willwork={willwork}")]

[OperationContract]

public string Foo(string willfail, string willwork)

{

Trace.WriteLine("willfail: " + willfail);

Trace.WriteLine("willwork: " + willwork);

string toreturn = 

	string.Format("willfail: {0}. willwork : {1}", 

			willfail, willwork);

return toreturn;

}


In my example, I set the service to be hosted in Asp.Net under IIS (optional, as it turns out) - and I'm using the zero-configuration WebServiceHostFactory factory in the .svc file.


Now, after building, start up a browser and browse to the url that the service is configured on - e.g http://localhost/[baseuriofservice]/[svcfile.svc]/c%23?willwork=c%23.  '%23' is Url-Encoding-speak for '#'.


What you expect to see is "willfail: c#. willwork : c#".


What you actually see is "willfail: c. willwork: c#".


So, when url-encoded characters appear in path segments bound to parameters, they won't always be read correctly (incidentally '%20' is read correctly); but it appears that query-string ones will.


As I mentioned, I posted an Connect bug under the title 'WCF UriTemplate Strips Some UrlEncoded characters from bound path segment' - and it turns out that this behaviour doesn't just affect WCF, or even Asp.Net (since the MS investigator also tried self-hosting the service and it still fails).


Even better news, however, is that this bug has been marked as fixed - so hopefully in the next framework version, we can expect to be able to use path segments with the whole gamut of URL-encodings!


This is one in the eye for Ayende Rahien - who blogged very recently about Connect failing all over the place.

Adding custom HTTP headers with Sys.Net.WebRequestManager

Following from my last post bemoaning the lack of transport-level client crediential authentication when running inside IIS, I've started implementing my own encrypted session-transfer between clients and the server.

I want to to use Http Headers as a primary way of broadcasting session information, and also because it's difficult for a hacker to know exactly what value to add to the http headers if it's been encrypted left, right and centre.  I might extend this to using a cookie as well; but the advantage of relying on http headers is that it means clients other than web browsers will be able to access the services; so long as they can authenticate.

The primary focus of my proof of concepts at the moment are on the AJAX side, both Asp.Net Ajax and 'vanilla' Ajax (e.g. jQuery or direct XmlHttp) - since I know that in Silverlight, for example, I'll be using a different endpoint and can probably add the same authentication data to the message itself.

The scenario is this:

  • A service issues encrypted authentication 'tokens' which a client then sends to other protected services when it makes a request.  These tokens are time limited and have to be refreshed by the client within a certain time period (possibility to make it request-limited as well)
  • A protected service is called by Asp.Net AJAX through use of the auto-generated proxy code that you the ScriptManager control gets - via the /js or /jsdebug endpoint that is added to the webscript-enabled service.

Now, the issue with this is that the proxy code that Asp.Net AJAX is generating is so 'friendly' that the underlying Web requests are abstracted away from your method calls, giving you no direct way of adding any custom headers you might want to add when you make the call.

Never fear - the Sys.Net.WebRequestManager class (part of Microsoft's Asp.Net AJAX client library) provides a hook which gives you the opportunity to examine each and every web request it sends, and even modify it's contents before it leaves the browser.  In fact, setting up the handler is so simple, I'm almost embarrassed to have it sitting at the bottom of such a long preamble...

  1: //method which captures requests and adds headers etc

  2: function InterceptOutgoingRequest(sender, args)

  3: {

  4:   var currentRequest = args.get_webRequest();

  5:   currentRequest.get_headers()["MYCUSTOMHEADER"] = "MYCUSTOMVALUE";

  6: }

  7: 

  8: //adding the callback to the WebRequestManager

  9: Sys.Net.WebRequestManager.add_invokingRequest(InterceptOutgoingRequest);


The 'sender' parameter will be an instance of the Sys.Net.WebRequestManager, and the 'args' parameter will be an instance of Sys.Net.WebRequest.


Now, every single Asp.Net Ajax call made by the WebRequestManager will call your custom code.

WCF Transport-level Custom Username Authentication won't work in IIS

Update – I have found a way (with a little help from the community!) around the issues discussed in this post – please see this post

I'm working on some WCF stuff at the moment whereby I want to expose business layer functionality to multiple clients (Javascript, Silverlight and WSHttp) and I want to have a security model that can be supported on all of them.  My authentication is totally custom, since we have all of our users in a custom database.

Logically I want to be able to use the WCF security model since it is very rich, and automatic once you've done the configuration.  However - it's a nightmare - because when you expose AJAX - friendly endpoints, you're doing it with WebHttpBinding, and it's security modes are, well, frankly crap; in fact, in almost every way WebHttpBinding should be thought of as a 'special case', which goes against everything that WCF seeks to achieve.

The problem is this - if you have a custom user name and password store, then you have to use either a membership provider (therefore relying on Asp.Net authorisation, and also in my case having to implement or stub out a whole host of features that our user store doesn't itself support), or you can write an entirely custom validator.

Once that's done your options - taken as a whole - are to use user name client credentials on either the transport or message security (using the 'clientCredentialType' attribute available on the <transport> and <message> security elements of a binding).  You also need to wire up the custom username validator - which is done at the service behaviour level:

  1: <serviceBehaviors>

  2:   <behavior name="MyServiceBehavior">

  3:   <serviceCredentials>

  4:     <userNameAuthentication userNamePasswordValidationMode="Custom" 

  5:                             customUserNamePasswordValidatorType="YourType, AssemblyName"/>

  6:   </serviceCredentials>

  7:   </behavior>

  8: </serviceBehaviors>

In a wsHttp environment you can do anything - so I'll leave that one out.


In a SOAP environment, too, it's fine: You'd probably use Message-based security, so that you also have a way clear to enable transport-level security as well.  Not to mention being also able to lock down the transport to further credentials if need be.


When, however, you hit the WebHttpBinding you also hit a massive brick wall.  You can only enable Transport security or TransportCredentialOnly security.  The first is just SSL, the second is no-SSL, but also gives space for the client credentials to be sent, using one of the Http authentication mechanisms, such as Basic, Digest etc (the same ones available on the IIS security tab).


This is where it gets really amusing - custom user name/password combos with Http Transport-based security do not work when hosted in IIS - because IIS steps in and authenticates against the windows user store (AD, local machine etc) automatically.  For a double-kick in the teeth, it's not supported at all when the service is not self-hosted:


For confirmation of this - see this blog article, and this link on MSDN about the UserNamePasswordValidationMode property.


I'm now having to circumvent WCF security and am rolling my own based on an IDispatchMessageInspector implementation, and custom authentication headers.


The next post will be about how Asp.Net Ajax makes it super-easy to add extra headers to requests as they go out of the WebRequestManager class.

Using WPF to Render Bitmaps

There are a few posts around the net about this, but a lot of them focus on taking XAML controls or pages, and turning parts of them into bitmaps.

This is fine, but I want to be able to use WPF entirely off-screen in order to create rich graphical content.

What I'm going to present here is a way of doing just that, in a console application just to press home the point.

This is the image that you're going to produce - it's a little bit, well, crap - but it does the job.

wpfinabitmap

So, it's an Ellipse with a RadialGradientFill (off-centre, white-to-blue gradient stops), and a TextBlock in Arial Black/Bold font of around 40px size.

The edges around the ellipse are going to be output as transparent (open up this file in Photoshop or Paint.Net and notice the checkerboard patterns around the edge - useful for web images!

Step 1: Create the project

Open a new Visual Studio, and create a new Console Application Project.  Make sure it targets .Net 3.5.

Add references to:

  • PresentationCore
  • PresentationFramework
  • WindowsBase

These are the core WPF libraries that are going to be required.

Warning - if you're going to be repeating this code in a Windows Forms application, you should be careful - because many of the classes in WPF clash with those in the standard windows forms framework.

Step 2: Basic setup

Now, a quick google or MSDN search will show that the main class you're going to need is called RenderTargetBitmap.  This class has a method called Render, to which you pass a Visual.  Anything that can be displayed in a WPF window is a visual (in fact the window itself is) which means, in theory, that anything you can do in WPF to screen can be done to a bitmap.

To produce the image file you're going to use one of the BitmapEncoder-implementing classes (there are classes for creating PNGs, Gifs, JPGs and more).

Open up Program.cs file and add the following usings:

using System.Windows.Media.Imaging;

using System.Windows.Media;

using System.Windows.Controls;

using System.Windows.Shapes;

using System.Windows;

using System.IO;

Modify the Main() method in Program.cs so it looks like this:

  1: [STAThread]

  2: static void Main(string[] args)

  3: {

  4: 	int height, width;

  5: 

  6: 	height = 300;

  7: 	width = 400;

  8: 

  9: 	//going to place all our stuff in here - same as on a standard WPF form.

 10: 	Grid mainContainer = new Grid();

 11: 	mainContainer.HorizontalAlignment = HorizontalAlignment.Stretch;

 12: 	mainContainer.VerticalAlignment = VerticalAlignment.Stretch;

 13: 

 14: 	Ellipse e = new Ellipse();

 15: 	e.Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255));

 16: 	//setup an off-centre gradient fill for a 3D effect

 17: 	//Of course - we could instead use a Viewport3D with Visual3D elements :)

 18: 	RadialGradientBrush rFill = new RadialGradientBrush();

 19: 	GradientStopCollection gradientStops = new GradientStopCollection(new GradientStop[] { 

 20: 		new GradientStop(Color.FromArgb(255, 255, 255, 255), 0.0),

 21: 		new GradientStop(Color.FromArgb(255, 60, 90, 255), 1.0)

 22: 	});

 23: 	rFill.GradientStops = gradientStops;

 24: 	rFill.GradientOrigin = new Point(0.65, 0.25);

 25: 	rFill.Center = new Point(0.5,0.5);

 26: 	rFill.RadiusX = 0.5;

 27: 	rFill.RadiusY = 0.5;

 28: 	e.Fill = rFill;

 29: 

 30: 	e.HorizontalAlignment = HorizontalAlignment.Stretch;

 31: 	e.VerticalAlignment = VerticalAlignment.Stretch;

 32: 

 33: 	mainContainer.Children.Add(e);

 34: 

 35: 	TextBlock message = new TextBlock();

 36: 	message.Text = "WPF In a Bitmap!";

 37: 	message.HorizontalAlignment = HorizontalAlignment.Stretch;

 38: 	message.TextAlignment = TextAlignment.Center;

 39: 	message.VerticalAlignment = VerticalAlignment.Stretch;

 40: 	//use margin for placement

 41: 	//could use canvas instead - but don't like the static 'Canvas.SetLeft/SetTop'

 42: 	//methods.

 43: 	message.FontFamily = new FontFamily("Arial Black");

 44:    	message.FontSize = 40.0;

 45: 	message.FontWeight = FontWeights.Bold;

 46: 	message.Margin = new Thickness(0.0, 120, 0.0, 0.0);

 47: 	mainContainer.Children.Add(message);

 48: 

 49: 	PngBitmapEncoder encoder = new PngBitmapEncoder();

 50: 	RenderTargetBitmap render = new RenderTargetBitmap(

 51: 		width, 

 52: 		height, 

 53: 		96, 

 54: 		96, 

 55: 		PixelFormats.Pbgra32);

 56: 	render.Render(mainContainer);

 57: 	encoder.Frames.Add(BitmapFrame.Create(render));

 58: 	using (Stream s = File.Open("outputfile.png", FileMode.Create))

 59: 	{

 60: 		encoder.Save(s);

 61: 	}

 62: }

Notice a few things:


1) [STAThread] is applied to the Main method as WPF requires this.  If you omit it, an exception is raised telling you as much.


2) Transparency is enabled in the output image by using a pixel format that includes an alpha channel.  Line 55 specifies 32-bit rgba - same as most people's desktop.


3) Horizontal/Vertical Alignment being set to stretch in most places - has the same effect as it would on a XAML form.


Run the app and open up outputfile.png in the output folder.


Oops...


What's that?  The image is empty?


What's happened is that, although the grid, ellipse and textblock are all present and, in theory, ready to be rendered, they haven't actually been told to lay themselves out according to their visual container.  Of course, they don't actually have one, since they are just objects in memory, so what do we do?


We have to take the place of the layout engine that is usually wired up automatically by a real WPF form; which it achieves through the use of all the events that WPF elements expose (i.e. for when controls get added or updated etc).


On line 48 (or at least between 47 and 49) you need to add this line of code:

mainContainer.Arrange(new Rect(0, 0, width, height));

Thankfully, this is recursive.


Save and run again, and this time the image should be as above.


Animation


If you're going to try and create pre-rendered animations using WPF, there are a couple of gotchas - and one outright brick wall if animated gifs are your thing.


The brick wall is that GifBitmapEncoder is not capable of producing correct animatable gifs.  While you can successively call the AddFrame method of it's Frames collection property, and create a single gif file containing all the individual frames, you can't (out of the box) add the necessary timing information and looping information that most browsers/image viewers require.  You'll get a non-looping default-speed animation in IE7, for example, but in other browsers (apparently IE8 is one of them) it just won't animate at all.


It is possible to add this functionality into the Gif encoder - but it's not a job I want to take on (see this MSDN forum post and it's answer).  In the meantime, it's still possible to use .Net and WPF to generate the intermediate gif frames on disk, and then either manually stitch the animation together with timing in a dedicated tool.


The gotchas for animating in this way are:



  1. Once a BitmapEncoder has saved a file, it cannot be used to save another; so you'll need to create a new encoder for each frame.
  2. You can re-use the RenderBitmapTarget between each frame, but...
  3. In the same way that we had to manually call the 'Arrange' method of the Grid (or whichever root container we're going to be using), we also have to manually Invalidate any controls whose visual state changes between frames.  You can achieve this, by sticking this line before the next call to the Render(Visual) method of the RenderBitmapTarget object:
mainContainer.InvalidateVisual();

Now, in theory it might be possible to use the story-boarding animation features of WPF, but since they rely on animation timers (which will not be present since there's no actual WPF app or window here) I'm not sure how effective it'll be.  My guess is that you would manually visit the timeline, explicitly setting the current position from 0 -> 1, then invalidate anything that might be affected, and then do the Invalidate/Render code.


If that were possible, then it would certainly make animating rotations etc a lot easier.


In any case - the ability to render stills using WPFs frankly rather swish rasterisation layer is, in itself, a real boon if looking to create dynamic images on a web page, for example, or even for any other scenario.  Automatic anti-aliasing and transparency, for example, being two of the biggest boons.

Passing ref parameters in a params object[] array

Ever wanted to call a method that takes a ref something in a generic (but not using generics!) way, say through a params object[] parameter array?

I did, and was most frustrated that you can't.

The Scenario

Firstly - the scenario I encountered is pretty specialist - I'm dynamically generating types which override/implement base/interface methods with methods provided by XML files.  The target methods of the implementations are static methods, and therefore cannot use the 'base' keyword when calling 'up' the virtual call chain.  As a result, I have to have a common delegate through which the next method can be called.  My solution to this is to have two standard delegates:

public delegate void ActionWithParameters(params object[] parms)

public delegate object FuncWithParameters(params object[] parms)

I like the params object[] route because it then means I can provide a public layer of methods, which are generics, which allow the developer to be more expressive with the types that they are passing to the next method, e.g:

//overload for two parameters

public void CallNext<T1, T2>(T1 p1, T2 p2)

{

	ActionWithParameters del = [Some Method to Get Delegate];

	//call it.

	del(p1, p2);

}

//the great thing being - for no parameters, it's the same code:

public void CallNext()

{

	

	ActionWithParameters del = [Some Method to Get Delegate];

	del();

}

However, this breaks down if one of the parameters is a 'ref'.  We can overload the generic method with one or more 'ref' versions for each of the parameters coming in (lots of copying and pasting!), but then we get stuck when trying to invoke the delegate, which expects a params object[] array (incidentally, the same is true when using the InvokeMethod of MethodInfo).


Now, we can declare a delegate thus:

delegate void FooDelegate(ref string something);

Then we can bind new instance of the delegate to a method with the same signature, and call it:

public void MyFoo(ref string input)

{

	input = "Hello world!";

}

public void BindADelegateAndCallWith(ref string input)

{

	FooDelegate foo = new FooDelegate(MyFoo);

	foo(ref input);

}

So, obviously the inability to pass parameters by reference is not a limitation of the Delegate itself, it's a limitation of the means by which we can call it when not using it directly as a function (note - in the above example, the C# compiler redirects the 'foo(ref input)' call to 'foo.Invoke(null, ref input)' - calling a method which the compiler is auto-generating - open up Reflector and switch to IL mode on the 'FooDelegate' type).


Why?


Let's look at why we can't pass these reference parameters into a params object[] array - if you already know why, then just skip this bit!


All types in the .Net framework inherit from System.Object, right?  Wrong.  Typed references created using the C# keywords ref and out (i.e. 'System.String&' or 'System.Int32&') do not.  In fact, they inherit from nothing, nor do they have any public/private members that can be discovered through reflection.  Nevertheless, they are still discreet types in their own right.  Indeed, to construct the 'Type' for a typed reference, would require something like the following code:

Type refstring = typeof(string).MakeByRefType()

Similarly, to get from the reference type back to the type to which it references you use the method:

//assuming that we still have the type from

//the previous example

Type nonref = refstring.GetElementType();

So, 'typed reference' types are not really part of the class hierarchy of a type and it's subtypes - but special types that exist in parallel to each class in that hierarchy - but which are only connected back to their non-reference bigger brothers.  The same is also true for pointer types.  So, for example, 'ref string' does not inherit from 'ref object' which is also the reason why, given a method like this:

public void PassObjectByRef(ref object obj)

{

}

You cannot call it with a line of code like this:

string mystring = "hello world!";

PassObjectByRef(ref mystring);

Again, the compiler will say something like "No overload which takes an argument 'ref string'", in addition to the other error "Cannot convert parameter 1 from 'ref string' to 'ref object'".  The number of times I've been frustrated by that I can't count - you can of course sidestep this problem by having a temporary reference to the base class of the same object (i.e. declare an 'object' local variable, assign it to the local string, and then pass the object by reference instead).


So this explains why you can't pass a 'ref string' to a method whose signature is 'params object[]' - that notation indicates that the caller can pass zero or more parameters that have System.Object as a base-class and, as we've just seen, Type& does not.


The Solution


Now, the technique I'm about to show here is probably not the safest in the world - however so long as your code is tightly controlled it should be fine.  It does require you to have an assembly somewhere which at least has the attribute:

[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification=true)]

And if you're going to use this code, I'd suggest you place this attribute on the assembly in which you paste the code, because when it creates the DynamicMethods it associates them with the parent module of the type itself.


What we want to achieve is to be able to convert our typed reference parameter into a non-typed reference parameter on the caller side, push it through a params object[] function, convert that value back into a typed reference again, before passing it to the actual method - or even modifying the target reference indirectly through that value.


The code exploits the fact that a .Net typed reference is just a platform pointer under the hood and is, therefore, a value that can be stored in a System.IntPtr structure.  It also exploits the fact that there are some things that we can do in IL that cannot be done in C# - like pushing typed reference's value on to the stack, and simply returning it without dereferencing it back to an object reference or value(the C# compiler automatically dereferences 'ref' parameters whenever they appear on the left or right hand side of an expression- either using OpCodes.LdInd_Ref or OpCodes.StInd_Ref, or similar, use Reflector or IL DASM to see what I mean).


Anyway, here's the magic generic class:

// Static class uses dynamic methods to do all the funky stuff, and

// because these are static they only get generated once for each type

// passed into the Type parameter T.

// Means that the first call will be a little slow, but the subsequent 

// calls should be lightning fast.

public static class RefParam<T>

{

	/*************************************************************/

	// The delegate types - these have to be declared using the

	// 'proper' delegate-keyword mechanism because only that

	// supports ref parameter types.  Would be nice to use

	// Func<T, IntPtr>, but we can't

	// Delegate which returns the actual object reference caused 

	// by passing the input parameter by reference.

	private delegate IntPtr MakeDelegate(ref T input);

	// Delegate which can be used to dereference an object 

	// reference and get the value currently stored in it.

	private delegate T GetValueDelegate(IntPtr objref);

	// Delegate which can be used to modify an object reference

	private delegate void SetValueDelegate(IntPtr objref, T newvalue);

	/*************************************************************/

	// this is the method that we actually call to turn a ref T

	// into an IntPtr.

	private static MakeDelegate _Make;

	// this method 

	private static GetValueDelegate _GetValue;

	private static SetValueDelegate _SetValue;

	static RefParam()

	{

		CompileDelegates();

	}

	private static void CompileDelegates()

	{

		//the dynamic method is targetted at the module that this

		//class is placed - that assembly needs to have the 

		//SkipVerification security permission.

		DynamicMethod dm = new DynamicMethod(

			string.Format("MakeRef_{0}", typeof(T).TypeHandle.Value), 

			typeof(IntPtr), 

			new Type[] { typeof(T).MakeByRefType() }, 

			typeof(RefParam<T>).Module);

		//method simply loads the reference value and returns it as

		//an IntPtr - if you were to disassemble any other method that

		//sucks in a ref parameter and returned it, you'd see a couple of

		//other opcodes - to do with dereferencing the reference - an 

		//operation that cannot be performed in straight C#

		ILGenerator gen = dm.GetILGenerator();

		gen.Emit(OpCodes.Ldarg_0);

		gen.Emit(OpCodes.Ret);

		_Make = (MakeDelegate)dm.CreateDelegate(typeof(MakeDelegate));

		dm = new DynamicMethod(

			string.Format("GetValue_{0}", typeof(T).TypeHandle.Value), 

			typeof(T), 

			new Type[] { typeof(IntPtr) }, 

			typeof(RefParam<T>).Module);

		gen = dm.GetILGenerator();

		gen.Emit(OpCodes.Ldarg_0);

		gen.Emit(OpCodes.Ldind_Ref);

		gen.Emit(OpCodes.Ret);

		_GetValue = (GetValueDelegate)dm.CreateDelegate(typeof(GetValueDelegate));

		dm = new DynamicMethod(

			string.Format("SetByRef_{0}", typeof(T).TypeHandle.Value), 

			typeof(void), 

			new Type[] { typeof(IntPtr), typeof(T) }, 

			typeof(RefParam<T>).Module);

		gen = dm.GetILGenerator();

		gen.Emit(OpCodes.Ldarg_0);

		gen.Emit(OpCodes.Ldarg_1);

		gen.Emit(OpCodes.Stind_Ref);

		gen.Emit(OpCodes.Ret);

		_SetValue = (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));

	}

	public static void SetValue(IntPtr reference, T newvalue)

	{

		_SetValue(reference, newvalue);

	}

	public static T GetValue(IntPtr reference)

	{

		return _GetValue(reference);

	}

	public static IntPtr Make(ref T value)

	{

		return _Make(ref value);

	}

}

Some people might find bits of this code scary - from the point of view of safety (indeed, unless you associate the dynamic methods with a module within an assembly that has the aforementioned 'SkipVerification' permission enabled, these dynamic methods simply do not compile).


Now that we've got our static class, we can look at using it:

//copy this code into a standard unit test

[TestMethod]

public void TestRefPassing()

{

	//hello world!

	string input = "";

	TakesAParamsObject(RefParam<string>.Make(input));

	Assert.AreEqual("Hello world!", input);

}

//expects a single parameter to be passed of type IntPtr

//that can be converted back into a String&

public void TakesAParamsObject(params object[] parms)

{

	RefParam<string>.SetValue((IntPtr)parms[0], "Hello world!");

}

Run the test - it should pass.


So what if your params object[] method needs to take a parameter that is known to be a typed reference, and pass it to another method that expects a 'ref T'?  This is a problem I've encountered in my project: even though I'm emitting the IL that wires this params object[] method to a 'proper' method with 'proper' parameters, I've not been able to produce IL that can safely turn an IntPtr back into a ref T without the runtime going monkey-poo (that's 'ape-shit') on me.  I'm sure it can be done, but until I can figure it out, the simplest solution is to declare a local, copy the value of the object referenced by the IntPtr, pass the local by reference to the target method, and then write the local value back to the IntPtr reference afterwards.  You can write C# to do the same - here's a slight modification of the above code:

[TestMethod]

public void TestRefPassing2()

{

	string input = "";

	TakesAParamsObjectAndForwardsItOn(RefParam<string>.Make(input));

	Assert.AreEqual("Hello universe!", input);

}

//same again, except this time the modification is being done in a method that

//actually expects a ref string, and the params object[] method simply cracks it

//out.

public void TakesAParamsObjectAndForwardsItOn(params object[] parms)

{

	//declare a string local, and use the 'GetValue' method on the 

	//RefParam<T> static type to retrieve the reference to copy into it.

	string topass = RefParam<string>.GetValue((IntPtr)parms[0]);

	//now pass the local string by reference

	TakesARefString(ref topass);

	//copy the reference back

	RefParam<string>.SetValue((IntPtr)parms[0], topass);

}

public void TakesARefString(ref input)

{

	input = "Hello universe!";

}

Now then, anybody out there who is also dynamically generating code to bind to methods like the 'TakesARefString' method through a similar params object[] method should be able to see how easy it would be to write the IL body for the middle method, given the target method's MethodInfo (being able to reflect the parameters and get their types).


Incidentally, I'm also using the same strategy for Value types passed by reference, and it all works fine.


What about garbage collection?


I'm pretty sure that, whilst this code might not be type-safe, it isn't 'unsafe' in the same way as using pointers.  A typed reference in .Net incorporates information about an object within the managed heap (unlike a pointer which goes directly to the actual unmanaged heap) - so if the underlying storage is moved, the typed reference is still valid.  If this wasn't the case, then any code which uses 'ref T' would also have to be unsafe, which it plainly does not.  All we've done is to take the underlying data for the typed reference - which is basically just a smart pointer from what I can gather - and get it's actual value.  There's no way that .Net writes back to these typed reference values if objects get moved about (far too much overhead, .Net would be a lot slower than it is), so we must consider the underlying value as sacrosanct.


Playing with fire might get you burned


Using this code is not without risks!  I'm not going to bother with a disclaimer on this code; I'd be here forever.  A few points of note, though:


We can now take that reference and pass it around outside of the call stack of the method that originally declared that reference - which the standard 'ref' mechanism prevents us from doing.  Effectively, this can mean holding on to a reference to something that has since gone out of scope - usually a problem that you don't have to think about in .Net.  Any attempt to do this (and then dereference the typed reference using the RefParam<T> class) is likely to end up with an ExecutionEngineException or something similar - and to get an idea of just how potentially dangerous that can be for the health of your application - consider the opening sentence for the remarks of the class from the documentation:


"Execution engine errors are fatal errors that should never occur"


Nuff said, really.  When one of these occurs, you can't even 'catch' them they're that bad.


Also - DO NOT take an IntPtr reference made with, say, RefParam<int> and attempt to read or write it through RefParam<string> - that's really bad medicine.  And don't even try to write to base types through a reference to the derived type - which as explained earlier the standard mechanism prevents you from doing.  That said - I've not tried it... so it might work ;)


Beyond that, so long as you are diligent and ensure that use of this class is only used in place of typed references into method calls, you should not get any problems whatsoever.


Stopping the caller from passing in a reference type that you don't expect is another matter - however this can be achieved instead by wrapping the IntPtr in another type that encodes the original type of reference (something that the data referenced by the value of the typed reference encodes itself, but is unfortunately not something that you can get hold of), and then having your code check that before dereferencing it - throwing a much more friendly exception if it's the wrong one.


And finally...


If anybody's got any ideas how to inline the conversion from IntPtr back to 'ref T' for the purposes of passing to a 'proper' method, rather than having to use an intermediate variable, I'd love to hear from you - I have a feeling that I've missed something glaringly obvious.


Update (29th October 2008)


On this final point - I have solved the problem.  This code is only going to be of interest if you are also code-generating a params object[] method which in turn calls a method with 'real' parameters - of which some could be ref params.


Here's a snippet of the IL I was using originally to load the original ref parameter (that was turned into an IntPtr using the RefParam<T> class) and store it in a local variable which then gets passed to the target method by reference in place of the reference that was passed (assuming that arg.0 is the params object[] array, and the IntPtr for the reference is the first item in it).  I have not included the IL which synchronises the value back to the passed reference (using RefParam<T>::SetValue):


.locals init(
   [0] paramelementtype param)
ldarg.0
ldc.i4.0
ldelem.ref
unbox native int
ldobj native int
call RefParam<paramelementtype>::GetValue(native int) //abbreviated the method name here for ease of reading
stloc.0 //storing the value in the local variable
ldloca.s param
//now call the target method


Now, when I originally tried to avoid using a local variable, I was experimenting with the refanytype and refanyval opcodes - thinking they would be of help.  But no, they weren't, and so I just abandoned the idea in favour of that one above.


However, this morning I decided to take a look at it again - feeling sure that I could inline the conversion from IntPtr back to the Type&.  My reasoning being that my GetValue method in RefParam<T> relies on this ability in order to work.  Embarrassingly enough, the solution was simple - do away with all the extra code after the 'ldobj':


ldarg.0
ldc.i4.0
ldelem.ref
unbox native int
ldobj native int

//now call the target method


Why?  Because after the ldobj instruction the 4/8 bytes of the managed pointer are now on the stack, and it is exactly that which the function call expects.