Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

23 March 2016

.NET Native, SilverlightSerializer, MakeGenericType and MissingMetadataException

Recently I have ported my app Map Mania to the  Universal Windows Platform, and at the moment of this writing it is being certified. (that, I least I hope). It’s the first UWP app I actually submit to the Store. I have been doing quite some IoT Core stuff and that does not require much submitting. But it had to happen at one time, if only to dogfood my WpWinNl port to UWP, and it was an educating experience.

I learned the hard way that stuff that does work with debug settings, does not necessarily work when you compile stuff ‘for real’. I ran into quite a serious issue with generics. As soon as I turned my app over to the .NET Native toolchain, it even crashed on startup. Mind you, most of the ‘business code’ in this app and large parts of the XAML were still the same as the original Windows Phone7 and 8 app, as was the WpWinNl base library – all ported to UWP, but largely unchanged.

The root cause of the problem turned out to be SilverlightSerializer. This is a serialization framework made by Mike Talbot that I have been using to store app state since 2011. It’s name quite dates it origins. Unfortunately the link to the original article is dead – actually the whole blog seems to have disappeared - but it’s code has been sitting in WpWinNl and it’s predecessors ever since that time. I have ported it to Windows Phone 8, Windows RT, and now to UWP.

Deep down in the core it uses the Type.MakeGenericType method to make a generic type with two type parameters to store types. So if I have ViewModel with a double property, it makes a GetSetGeneric<ViewModel, double>. This, now, does not go down well with .NET Native. Runtime, it will pop up the following error:

Exception thrown: 'System.Reflection.MissingMetadataException' in System.Private.CoreLib.dll

Additional information: Reflection_InsufficientMetadata_EdbNeeded: WpWinNl.Utilities.GetSetGeneric<BeautyOfMaps.Models.TileMapSource,System.Boolean>. For more information, visit http://go.microsoft.com/fwlink/?LinkId=623485

Now, in your app, in  the “Properties” folder, there is a Default.rd.xml file that allows you to instruct the compiler not to ‘optimize things away’, to make sure this code still works. The insidious part is that this code is in my libary, downloaded from NuGet, and since it uses generics there is no ‘'generic’ way for me to instruct the compiler in the libary’s rd.xml not to optimize away code in the app that is using it.

If I wanted to fix this particular problem, I have to add the following line to the app’s rd.xml:

<Type Name="WpWinNl.Utilities.GetSetGeneric{BeautyOfMaps.Models.ViewModel.MainViewModel,System.Boolean}" Dynamic="Required All"/>

And guess what – then you get the next error. Now it it’s complaining about missing

WpWinNl.Utilities.GetSetGeneric<LocalJoost.Maps.TileSources.Google,
LocalJoost.Maps.TileSources.GoogleType>

So it apparently needs a line like this for every class type and property type combination that goes past MakeGenericType. So while you already defined in code what these properties are, you have to declare (again) in XML which ones you want to keep. I have been in contact with the .NET Native team about the apparent lack of logic behind this, but is seems that according to their date very little people actually use this kind of reflection. While this is true without any doubt – Microsoft telemetry does not lie - I think the critical thinking error that was made here is that those people might be using libraries that do – like mine! - and then they are thoroughly in deep… er, manure.

Trying to add manually all class/property type combinations is where madness lies, my friends. I came to about the 6th type and then I was kind of done. I am a developer, so I am lazy by nature, and in stead of actually doing it manually I added a weird property to SilverlightSerializer called RdXmlEntries. It’s usage is as follows:

  • Run the app in DEBUG (so not .NET Native)
  • Serialize all objects you want to serialize
  • Directly behind the last serialization, add this code:
foreach (var entry in SilverlightSerializer.RdXmlEntries)
{
  Debug.WriteLine(entry);
}
  • Copy and paste the resulting data in your Default.rd.xml
  • Verify your code now runs under .NET Native.

This code is now in WpWinNlBasic version 3.0.5-alpha on NuGet and available for use. You now know why I keep this in the unstable branch – as long as I haven’t had the chance to dogfood all the stuff I have ported and created earlier, I want to thread carefully.

When I showed this solution to the .NET Native team I got feedback that I only needed to provide lines for when the second parameter is a value type, not when it’s a reference type. I have validated that in one case, but I serialize quite a complicated object graph and had spent more than enough time on it already, I did not really feel like experimenting further.

Bottom line – be very, very careful with advanced reflection in UWP apps. Don’t make the same mistake I made – test early under .NET Native and follow guidance provided here to maintain your sanity.

Special thanks to Tom Verhoeff for providing assistance based upon his earlier experience. And sorry, no code sample this time as this is more general guidance that a specific coding issue ;)

05 August 2010

Fixing CLSA property registration issues in child objects

AKA ‘avoiding the dreaded “Can not register property YourProperty after containing type (YourBaseType) has been instantiated” error message’

Somewhere between CSLA 3.0 en 3.6 a new way of registering properties has become into being:

// old skool CSLA
private string _oldProp = string.Empty;
public string OldProp
{
  get
  {return _oldProp;}	 
  set
  { if (value == null) value = string.Empty;
    if (!_oldProp.Equals(value))
    {
      _oldProp = value;
      PropertyHasChanged("OldProp");
    }
  }
}

//new skool CSLA
private static PropertyInfo NewPropProperty = 
  RegisterProperty(c => c.NewProp);
public string NewProp
{
	get { return GetProperty(NewPropProperty); }
	set { SetProperty(NewPropProperty, value); }
}

In CSLA 4.0 the last style is mandatory, so I started upgrading some objects (while currently using CSLA 3.8.3) in anticipation. So I upgraded my base object

using Csla;

namespace CslaInheritance
{
  public abstract class MyBaseClass : BusinessBase<MyBaseClass>
  {

    protected static PropertyInfo<string> MyProp1Property = 
        RegisterProperty<string>(c => c.MyProp1);
    public string MyProp1
    {
      get { return GetProperty(MyProp1Property); }
      set { SetProperty(MyProp1Property, value); }
    }

    protected static PropertyInfo<string> MyProp2Property = 
        RegisterProperty<string>(c => c.MyProp2);
    public string MyProp2
    {
      get { return GetProperty(MyProp2Property); }
      set { SetProperty(MyProp2Property, value); }
    }
  }
}
and then my child object
using Csla;

namespace CslaInheritance
{
  public abstract class MyConcreteClass1 : MyBaseClass
  {
    protected static PropertyInfo<string> ConcreteProp1Property = 
      RegisterProperty<string>(c => c.ConcreteProp1);
    public string ConcreteProp1
    {
      get { return GetProperty(ConcreteProp1Property); }
      set { SetProperty(ConcreteProp1Property, value); }
    }

    protected static PropertyInfo<string> ConcreteProp2Property =
      RegisterProperty<string>(c => c.ConcreteProp2);
    public string ConcreteProp2
    {
      get { return GetProperty(ConcreteProp2Property); }
      set { SetProperty(ConcreteProp2Property, value); }
    }
  }
}

And then I noticed something odd: according to the compiler, ConcreteProp1 and ConcreteProp2 were not defined. Even worse is the situation when you choose to upgrade your properties not using lambda expressions, but PropertyInfo objects, like this:

    protected static PropertyInfo<string> ConcreteProp3Property =
      new PropertyInfo<string>("ConcreteProp3Property");
    public string ConcreteProp3
    {
        get { return GetProperty(ConcreteProp3Property); }
        set { SetProperty(ConcreteProp3Property, value); }
    }
because this will compile - and run. Until you create a second child class MyConcreteClass2, instantiate it, then instantiate a MyConcreteClass1 – and then you will get a cryptical runtime error message saying “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated”.

Fortunately the CSLA framework comes with sources, and after some rooting around I found the culprit, if you can call it that, in Csla.BusinessBase:

protected static PropertyInfo<P> 
  RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
{
  PropertyInfo reflectedPropertyInfo = 
    Reflect<T>.GetProperty(propertyLambdaExpression);

  return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(
    typeof(T), reflectedPropertyInfo.Name));
}

Although MyConcreteClass1 inherits from MyBaseClass, MyBaseClass inherits in turn from templated class BusinessBase<MyBaseClass>. Therefore, in RegisterProperty called from MyConcreteClass1 T is still MyBaseClass. It does not matter that I actually called it from a child class. So what happens is that all the statics are defined in the base class MyBaseClass. If you are using the lambda variant to register, the compiler saves your *ss, but if you use the PropertyInfo method something weird happens. Remember, statics in a class are initialized as soon as you touch any one of statics. So what happens is: you instantiate your concrete child class, immediately the statics of both the concrete and the base class are initialized, and all the properties are registered in the base class. If you try to instantiate a second concrete child class, Csla finds that your base class properties are already initialized, and the dreaded “Can not register property ConcreteProp1Property after containing type MyBaseClass has been instantiated” error message appears.

Now you can of course change the way you implement classes. I might make MyBaseClass generic as well, then T changes along. But when upgrading an existing API out of a situation in which direct inheritance used to be perfectly legal, it’s a different story.

There are actually two ways out of this. The first one is: use PropertyInfo, but explicitly name the object type to which the property belongs

protected static PropertyInfo<string> ConcreteProp3Property =
  RegisterProperty(typeof(MyConcreteClass1), 
  new PropertyInfo<string>("ConcreteProp3Property"));
public string ConcreteProp3
{
    get { return GetProperty(ConcreteProp3Property); }
    set { SetProperty(ConcreteProp3Property, value); }
}

This works, but I like the solution below better, because that uses lambda expressions again and so your friend the compiler ;-) can help you catch typo’s. The only way I see to realize that is to add a static method at the bottom of your class

private static PropertyInfo<T> RegisterPropertyLocal<T>(
  Expression<Func<MyConcreteClass1, object>> propertyLambdaExpression)
{
  var reflectedPropertyInfo = 
  Reflect<MyConcreteClass1>.GetProperty(propertyLambdaExpression);
  return RegisterProperty(typeof(MyConcreteClass1),
    Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<T>(
    typeof(MyConcreteClass1),
    reflectedPropertyInfo.Name);
}
and then register your properties like this from now on:
protected static PropertyInfo<string> ConcreteProp1Property = 
  RegisterPropertyLocal<string>(c => c.ConcreteProp1);
public string ConcreteProp1
{
  get { return GetProperty(ConcreteProp1Property); }
  set { SetProperty(ConcreteProp1Property, value); }
}

The drawback of this solution is, of course, that you have to define a static RegisterPropertyLocal in every inherited class you define. But at least you will be saved from typos and weird runtime errors.

Now you are ready to upgrade, but I would recommend recording some macros to do the actual syntax change, unless you are very fond of very dull repetitive typing jobs ;-)

25 January 2010

A generic convertor for IEnumerable<T>

Apart from ForEach<T>, as I described in my previous post, I noticed the absence of ConvertAll<T> on everything but List<T> as well. Pretty annoying when I wanted to convert a list of business objects of So I extended my static class GenericUtilities with another extension methdo

using System;
using System.Collections.Generic;

namespace LocalJoost.Utilities
{
  public static class GenericExtensions
  {
    // previous code for ForEach omitted.

    public static IEnumerable<TC> ConvertAll<T, TC>(
      this IEnumerable<T> inputList, 
      Converter<T, TC> convert)
    {
        foreach( var t in inputList )
        {
            yield return convert(t);
        }
  }
}
This permitted me to do something like this:
return ListRubriek.Get()
  .ConvertAll(p => new CascadingDropDownNameValue(
        p.Omschrijving, p.Id.ToString()))
  .ToArray();
to easily convert a list of CSLA business objects into a list that could be used in an ASP.NET Ajax Cascading dropdown. Nothing special for the veteran functional programmer I guess but still, useful.

This is actually the 2nd version - thanks to Jarno Peschier for some constructive criticism

19 January 2010

One ForEach to rule them all

I ran into this when I was investigating functional programming in C#. That’s been around for a while, but apart from using it for traversing or modifying collections or lists, I never actually created something that was making use of a function parameter.

Anyway, one of my most used constructs is the ForEach<T> method of List<T>. I always thought it to be quite annoying that it is only available for List<T>. Not for IList<T>, ICollection<T>, or whatever. Using my trademark solution pattern – the extension method ;-)
I tried the following:

using System;
using System.Collections.Generic;

namespace LocalJoost.Utilities
{
  public static class GenericExtensions
  {
    public static void ForEach<T>(this IEnumerable<T> t, Action<T> action)
    {
      foreach (var item in t)
      {
        action(item);
      }
    }
  }
}

And that turned out to be all. IList<T>, ICollection<T>, everything that implements IEnumerable<T> – now sports a ForEach method. It even works for arrays, so if you have something like this

string[] arr = {"Hello", "World", "how", "about", "this"};
arr.ForEach(Console.WriteLine);
It nicely prints out

Hello
World
how
about
this

I guess it's a start. Maybe it is of some use to someone, as I plod on ;-)