This project has moved and is read-only. For the latest updates, please go here.
1
Vote

NullReferenceException during reading iFrame elements

description

Hello, I was trying to read all the iFrames from the site habrahabr.ru and code failed with NullReference exception. Here is my code:

public static IEnumerable DownloadHabrahabr()
    {
        using (WebClient webClient = new WebClient())
        {
            string html = webClient.DownloadString(new Uri("http://www.habrahabr.ru/"));
            HtmlDocument document = new HtmlDocument();
            document.LoadHtml(html);
            foreach (HtmlNode node in document.DocumentNode.SelectNodes("//iframe[@src]"))
            {
                yield return node.Name;
            }
        }
    }
Exception details:
System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=App1.Core
StackTrace:
   at App1.Core.Test.d__0.MoveNext() in c:\Users\Eugene\Documents\Visual Studio 2012\Projects\App1\App1.Core\Test.cs:line 21
   at MS.Internal.Data.EnumerableCollectionView.LoadSnapshotCore(IEnumerable source)
   at MS.Internal.Data.EnumerableCollectionView..ctor(IEnumerable source)
   at MS.Internal.Data.ViewManager.GetViewRecord(Object collection, CollectionViewSource cvs, Type collectionViewType, Boolean createView, Func`2 GetSourceItem)
   at MS.Internal.Data.DataBindEngine.GetViewRecord(Object collection, CollectionViewSource key, Type collectionViewType, Boolean createView, Func`2 GetSourceItem)
   at System.Windows.Data.CollectionViewSource.GetDefaultCollectionView(Object source, Boolean createView, Func`2 GetSourceItem)
   at System.Windows.Data.CollectionViewSource.GetDefaultCollectionView(Object source, DependencyObject d, Func`2 GetSourceItem)
   at System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable value, Func`2 GetSourceItem)
   at System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Controls.ItemsControl.set_ItemsSource(IEnumerable value)
   at App1.WinUI.MainWindow.MainWindow_OnLoaded(Object sender, RoutedEventArgs e) in c:\Users\Eugene\Documents\Visual Studio 2012\Projects\App1\App1.WinUI\MainWindow.xaml.cs:line 31
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
   at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
   at MS.Internal.LoadedOrUnloadedOperation.DoWork()
   at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.Resize(ICompositionTarget resizedCompositionTarget)
   at System.Windows.Interop.HwndTarget.OnResize()
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
InnerException:

comments

paulirwin wrote Sep 19, 2014 at 3:37 PM

This is because of a very frustrating design decision that I feel needs to be corrected. If SelectNodes doesn't match any nodes for your XPath expression, it returns null instead of an empty HtmlNodeCollection. This means you can't safely do a foreach over the result of SelectNodes, and instead have to write messy code like this:
    IEnumerable<HtmlNode> nodes = (IEnumerable<HtmlNode>)doc.DocumentNode.SelectNodes(_myXPath) ?? new HtmlNode[0];
    
    foreach (HtmlNode node in nodes)
    { ... }
I would greatly prefer if SelectNodes returned an empty HtmlNodeCollection.