Software Development

Updating Angular: Why do I get the error Prerendering failed because of error: TypeError: Object prototype may only be an Object or null: undefined at setPrototypeOf (native)

Do I win an award for the longest, most boring blog title in the world?

I’ve been doing some work with Angular recently, using Steve Sanderson’s excellent templates for ASP.NET Core.

It’s been interesting, since I’m not a client-side type, so a lot of the ceremony involved is a little alien to me. That mostly means that when things go wrong, it’s a bit harder to diagnose where I’ve made a mistake, but I’ve been doing OK.

Where I’ve been really struggling, for several days now, is in trying to update the Angular package versions I’ve been using.

In my innocence, I had wondered if all I needed to do was change the version numbers in the package.json to the new version. I needed to bump up the minor version to take advantage of improvements in the animation APIs.

But this naive approach left me with an application that was just broken, but broken in a way that gave almost no clue as to the reason.

The error that I was seeing, generated by the pre-rendering being done by the javascript services that are part of the template site, was this:

Exception: Call to Node module failed with error: Prerendering failed 
because of error: TypeError: Object prototype may only be an Object 
or null: undefined at setPrototypeOf (native)

This is about the most generic, information-free error you could imagine. Even with the associated stack trace, I didn’t have a clue what it meant, nor how to track it down.

But I did, just now, discover what I think is the core reason why the build was failing.

The reason is that the template does some clever stuff under the hood, to enable hot module replacement as you’re developing, but if node modules change, that’s not enough, and the key part of the build isn’t happening – webpack isn’t packaging up the code again.

I seem to have fixed the build by invoking webpack by hand using the following two commands:

  • webpack --config webpack.config.vendor.js
  • and then
  • webpack

This rebuilds the files that contain the code for the site, in the dist folder in ClientApp and wwwroot. They’re also not tracked by source control, so they can end up missing if you’re cloning a repo.

Important safety tip: If you’re updating version numbers in Package.json, either do it with the solution closed, or let Visual Studio run the npm install. I’ve made the mistake of editing the packages, then trying to npm install from the command line, and that means there’s two installs happening, and they end up fighting with each other.

I still don’t know why these webpack rebuilds weren’t happening with the default setup of the project. I’m assuming it’s only something that should happen when packages update, but it does have the nasty effect of leaving your project badly broken, such that even if you revert the package version changes, often your dist files are still really broken.

Advertisements

Silverlight Grid Row Gradients

I just had to implement a design where a table of data, in Silverlight, had to have cell backgrounds where each cell is slightly darker than the cell above. Here it is in situ:

As you can see, not only does each row have a descending gradient, but each column has a different gradient.

The easy way

The simple way is to just put in a border or background rectangle into each cell. This is what I did originally. But it’s a lot of work no matter how you do it. Neither Blend nor Visual Studio lend themselves to this kind of thing, and even hand-editing the Xaml can lead to cut&paste errors.

The even easier way

I decided to have some kind of automated way to do this. I needed something that you could call that would put in the right rectangles in the right places with the right colours but was easy to manage, so I wrote a behavior. If you’re unfamiliar with Silverlight Behaviors (apologies for the American spelling, but that’s what they’re called) then read this post by Christian Schormann from the Blend team.

I realised that all I needed was something where I can specify which column I’m interested in, and what the start and end colours are. So this is the code I came up with:


/// <summary>
 /// A behaviour which targets a Grid to put background rectangles
 /// into column cells creating a gradient.
 /// </summary>
 public class GridGradientBehavior : Behavior<Grid>
 {
   /// <summary>
   /// Somewhere to keep track of the items we've added to the grid
   /// </summary>
   List<Rectangle> rectangles = new List<Rectangle>();

   /// <summary>
   /// Called when this behaviour is attached to the grid.
   /// </summary>
   protected override void OnAttached()
   {
     base.OnAttached();

     /// Just in case, clear any rectangles we've already put in
     foreach (var rect in rectangles)
       {
         AssociatedObject.Children.Remove(rect);
       }
       rectangles.Clear();

       // Check the RowDefinitions. If there aren't any, just put in a single rectangle
       if (AssociatedObject.RowDefinitions == null
           || AssociatedObject.RowDefinitions.Count <= 1)
       {
         InsertRectangle(new SolidColorBrush(StartColour), 0);
       }
       else
       {
         // We need to interpolate between the two colours. I make use
         // of the SolidColorBrushInterpolator from System.Windows.Controls.DataVisualization
         // since my project already uses the toolkit.
         var interpolator = new SolidColorBrushInterpolator();
         interpolator.From = StartColour;
         interpolator.To = EndColour;
         interpolator.DataMinimum = 0;
         interpolator.DataMaximum = AssociatedObject.RowDefinitions.Count - 1;
         for (int i = 0; i < AssociatedObject.RowDefinitions.Count; i++)
         {
           InsertRectangle((Brush)interpolator.Interpolate(i),i);
         }
       }
     }

     /// <summary>
     /// For each grid row, insert a rectangle of the appropriate colour into the ]
     /// appropriate row and column slot.
     /// </summary>
     /// <param name="color">The brush to use, interpolated between Start and End</param>
     /// <param name="i"></param>
     private void InsertRectangle(Brush color, int i)
     {
       Rectangle rect = new Rectangle();
       rect.HorizontalAlignment = HorizontalAlignment.Stretch;
       rect.VerticalAlignment = VerticalAlignment.Stretch;
       rect.Fill = color;
       Grid.SetRow(rect, i);
       Grid.SetColumn(rect, Column);

       // This should ensure these rectangles are behind everything else in the grid
       Canvas.SetZIndex(rect, -1);

       // and if it doesn't, we insert our rectangles at the lowest point
       // in the visual tree
       AssociatedObject.Children.Insert(0, rect);
       rectangles.Add(rect);
     }

     /// <summary>
     /// Called when the behavior detaches. Remove all our rectangles from
     /// the grid.
     /// </summary>
     protected override void OnDetaching()
     {
       base.OnDetaching();
       foreach (var rect in rectangles)
       {
         AssociatedObject.Children.Remove(rect);
       }
       rectangles.Clear();
     }

     /// <summary>
     /// Dependency property telling us which column to apply this behaviour to
     /// </summary>
     public int Column
     {
       get { return (int)GetValue(ColumnProperty); }
       set { SetValue(ColumnProperty, value); }
     }
     public static readonly DependencyProperty ColumnProperty =
       DependencyProperty.Register("Column", typeof(int), typeof(GridGradientBehavior),
         new PropertyMetadata(0));

     /// <summary>
     /// Dependency property for the start colour of our gradient
     /// </summary>
     public Color StartColour
     {
       get { return (Color)GetValue(StartColourProperty); }
       set { SetValue(StartColourProperty, value); }
     }
     public static readonly DependencyProperty StartColourProperty =
       DependencyProperty.Register("StartColour", typeof(Color), typeof(GridGradientBehavior),
         new PropertyMetadata(Colors.White));

     /// <summary>
     /// Dependency property for the end colour of our gradient
     /// </summary>
     public Color EndColour
     {
       get { return (Color)GetValue(EndColourProperty); }
       set { SetValue(EndColourProperty, value); }
     }
     public static readonly DependencyProperty EndColourProperty =
       DependencyProperty.Register("EndColour", typeof(Color), typeof(GridGradientBehavior),
         new PropertyMetadata(Colors.Black));

   }

The easiest way to apply this to a grid is to drag and drop it from the Behaviors section of the Assets pane. Then set the three parameters (StartColour, EndColour and Column) as appropriate. If (as in my example) you have two columns you want this to affect, you ust have to drop a second behavior onto the same grid.

There are a million ways you might want to extend this – letting you style rows instead of columns, or changing the rectangle to a border and having the ability to define different borders for top and bottom for example. Or you could use this to do alternating row colours. There’s quite a lot of scope for such a simple idea.

What I really want, though, is a way to get the same effect in an ItemsControl, but that’s a whole different problem.

Feel free to use this if it’s helpful.

Expression Blend 3 and Visual Studio 2010 RC

I installed VS2010 RC several weeks ago, and I’m now using it as my principal Silverlight dev environment. However, the sacrifice I made was that I could no longer use Blend 3 on my Silverlight 3 projects because the solution version number had changed.

I was wrong.

True, when you load your solution into Blend, it does complain that it’s a newer version, and might not work, but if you continue, Blend will successfully load a Silverlight 3 project. I tried two different projects, one which had been converted from VS2008 to VS2010 – which loaded properly – and one which I had created from scratch in VS2010. This one failed to load the web project, probably because VS2010 had created a .NET 4 web project, which Blend can’t load. But since Blend doesn’t care about the web project, this wouldn’t prove a problem.

So that’s useful – I can now use Blend again without resorting to weird hackery.

Of course, in just over a week, we might well have new versions of all the Silveright tools, as Mix10 opens in Las Vegas (I’ll be there!) and, if Microsoft follow their usual pattern, they’ll announce Silverlight 4 RTW. I think a lot of people will be disappointed if the tools aren’t available as soon as the announcement happens, although it won’t coincide with the RTM of Visual Studio 2010, because that launch isn’t scheduled until April (and that’s a launch, not necessarily the RTM date).

InvalidOperation_EnumFailedVersion when binding data to a Silverlight Chart

This one was a pain.

We’re releasing an analytics application in Silverlight to people inside the BBC. Today is release day, and we had some last-minute tweaks we wanted to roll out. Unfortunately, some of our customers were reporting a strange error when they tried this new version.

[InvalidOperation_EnumFailedVersion]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=3.0.40723.0&File=mscorlib.dll&Key=InvalidOperation_EnumFailedVersion

Nice.

I could identify roughly where it was coming from from the stack trace, but the real pain was, this didn’t happen on my development machine, nor on any other machine in our immediate vicinity. But it happened on the machines of both our main stakeholders.

We narrowed it down to the version of the runtime. All the errors were happening on machines with version 3.0.40723.0 while I was running 3.0.40818.0 (and others in my department were running an even newer version).

The problem happened when binding data to a Silverlight Toolkit chart. It worked fine when using a pie chart, but we’d changed that chart to be a bar chart, which is when the errors appeared. Playing with it, Pie Charts work fine but Line, Bar or Column charts would throw this error.

The stack trace showed a lot of  NotifyDataContextChanged event handling before the error hit. The binding wasn’t complex. I’d set the chart’s DataContext to a list of keyvalue pairs, and set the BarSeries ItemsSource property to {Binding Mode=OneWay}.

To fix this (well, work around it, really) I stopped setting the DataContext of the chart in the code altogether, and in place of that, set the ItemsSource property of the BarSeries directly to the list of pairs. This worked fine, and seemed to avoid the error.

The really mysterious thing is why we never come across issues like this until we’re actually launching it? There’s clearly a Universal law at work.

<!–[if gte mso 9]> Normal 0 false false false EN-GB X-NONE X-NONE MicrosoftInternetExplorer4 <![endif]–><!–[if gte mso 9]> <![endif]–> <!–[endif]–>[InvalidOperation_EnumFailedVersion]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=3.0.40723.0&File=mscorlib.dll&Key=InvalidOperation_EnumFailedVersion

‘Cannot register duplicate name ‘XXX’ in this scope’ in VS 2010

Here’s a gotcha that was puzzling me yesterday.

I’ve just installed Visual Studio 2010 RC, and was trying it out on my current project. It’s a Silverlight Navigation-style project, but that’s not important to the bug.

I found one page where the Xaml designer wouldn’t handle the page properly – it was throwing exceptions, and the editor was showing an error in the Xaml. The line looked like this:


<local:SimpleConverter x:Name="SimpleConverter"/>

This is a value converter, designed to convert bindings from one type to another. The error it was showing was ‘Cannot register duplicate name ‘SimpleConverter’ in this scope’. This foxed me for a while – I thought perhaps because I was throwing exceptions when I didn’t recognise the type being converted, but even removing that and simplifying didn’t remove the error.

Then I noticed the key word in the error message: ‘Name’.

In Xaml you can use x:Name if you want something in the Xaml linked up to a class variable in your code-behind. But that was clearly causing issues with whatever the designer was doing behind the scenes. However, if you don’t need code-behind access (as I don’t in this case) you can use x:Key – and that’s the usual mechanism for naming resources.

Changing the resource to:


<local:SimpleConverter x:Key="SimpleConverter"/>

then the errors from the visual designer stop happening.

Of course, I’ve no idea if the errors are a bug in the designer, or if it’s just wrong to use x:Name in resources, but since I didn’t need the autowiring up of objects, it’s no problem to change it.

My Presentation to the Bing Maps UK User Group

Here’s the video of my presentation to the first Bing Maps UK User Group earlier this month. There’s a short piece missing during the Ambleside walking demo, which is a shame, but otherwise it’s fine.

Sorry about saying ‘umm’ a lot.

(Update: The original host for the video has long-since ceased running, but I had downloaded the original, so now it’s hosted on YouTube.)

Why can’t I use Linq on a CaptureCollection?

Doing some Regular Expression work, and I wanted to get a simple enumeration of multiple captures in a match group. I tried this:

var caps = from capture in match.Groups[2].Captures select capture.Value;


but Intellisense told me “Could not find an implementation of the query pattern for source type ‘System.Text.RegularExpressions.CaptureCollection’.  ‘Select’ not found.  Consider explicitly specifying the type of the range variable ‘capture’.”

This is because Captures is a specialised collection, not a generic collection, and it doesn’t therefore support IEnumerable<T>. The solution (which I found here) is:

var caps = from capture in pathmatch.Groups[2].Captures.Cast<Capture>() select capture.Value;

adding the Cast to a Capture allows the rest of the Linq query to work.

I love Linq, but just sometimes, it can be a bit impenetrable.