tl;dr – Forget any form of dynamic code emitting in Metro-style. It’s not going to happen.
Over the past week or so I’ve been trying to get Moq (the popular open source TDD mocking framework) to work on WinRT. Irritatingly, the day before Release Preview was released it was actually working on Consumer Preview. However in Release Preview (RP) the System.Reflection.Emit namespace is gone. Forget any form of dynamic code generation and/or MSIL injection.
This kills off any project based on the popular Castle Project Dynamic Proxy component, of which Moq is one example. You can at this point in time not perform any form of mocking using dynamic injection in your Metro-style unit testing endeavours.
So let me take you through my journey on this, so that other’s don’t have to…
The headline fact is that you cannot load any assembly that you create at runtime. WinRT supports one Assembly.Load method, and that takes the name of an assembly. That has to be placed within the deployment folder of your app. You cannot give it a filename, or stream. The methods are there, but private. Try to invoke them using Reflection and you’ll be met with a caspol exception.
You can, in theory, use Rotor to replace SRE. It’s all there, but again, you can’t load anything you create.
You can’t write to your deployment folder from within your Metro-style app. But, can you use another service on the machine to move a file that you create into the deployment folder and load it? Not really.
The networking stack in Metro-style is intentionally “damaged” to prevent socket communication from Metro-style to any end-point on the local machine. (It just times out.) This militates against an approach where your Metro-style app can signal a properly installed service on the machine to create proxies on its behalf. If you wanted to do this, you’d have to route the calls through a C&C server somewhere.
The reason why Microsoft has done this is obvious – taking out SRE know means they don’t have to do it in an emergency later. The collateral damage in removing SRE is that you can’t do mocking in test mode, but you also can’t do any form of injection in production mode. There are plenty of reasons why enterprise apps might want to do this last point particularly. At CP, the assumption was that their inspection tools would prevent SRE being used as a malware vector – it now seems they are less confident about that. (For clarity, the risk here is in allowing a nefarious program to download instructions from a C&C server and make up executable code on the fly to run, getting around the marketplace restrictions.)
So, two things:
– System.Reflection.Emit is gone in Metro-style/WinRT. Get over it – dynamic, on-the-fly code generation is not going to to happen.
– I’ve more or less got a version of Moq working in Metro-style. This is based on the idea of “baking” the dynamic proxies before you use them. You can find more information here: https://github.com/mbrit/moqrt
Update: Oren Novotny emailed me about using an “extension SDK” to link into Moq. Extension SDKs allow you to reference assemblies that use the full .NET profile from within Metro-style apps. (Roughly speaking, anyway. You can reference them, but you can’t go outside of the sandbox.) The idea here that you can take the normal Moq and Castle.Core assemblies and package them as an extension. (Check out Oren’s blog post on extension SDKs.)
This gets you to a point where you can build it, but you can’t actually run it. Specific caspol security exists around the serialization and SRE APIs. Here’s an example of an exception that you get using this approach:
System.InvalidOperationException: The API ‘System.Reflection.Emit.TypeBuilder.DefineProperty(System.String, System.Reflection.PropertyAttributes, System.Reflection.CallingConventions, System.Type, System.Type[], System.Type[], System.Type[], System.Type[][], System.Type[][])’ cannot be used on the current platform. See http://go.microsoft.com/fwlink/?LinkId=248273 for more information.
Result StackTrace:
at System.Delegate.CreateDelegateInternal(RuntimeType rtType, RuntimeMethodInfo rtMethod, Object firstArgument, DelegateBindingFlags flags, StackCrawlMark& stackMark)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at Castle.DynamicProxy.Generators.Emitters.PropertyEmitter..ctor(AbstractTypeEmitter parentTypeEmitter, String name, PropertyAttributes attributes, Type propertyType, Type[] arguments)
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateProperty(String name, PropertyAttributes attributes, Type propertyType, Type[] arguments)
(etc.)
- Share This Post:
- Short Url: http://wblo.gs/cyX
Print | posted on Tuesday, June 05, 2012 8:19 AM