[SOLVED] NullReferenceException when making a content importer

So im trying to make a content importer for a class in my game and i have managed to solve most issues, however i cant seem to solve this null reference exception.

The game class is empty as i was just testing but here it is

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using MagieMonoExtension;
using MagieMonoExtension.Framework.Mapping;

namespace Magie
{
    public class Magie : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        TileGrid Map;
        
        public Magie()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();


        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Map = Content.Load<TileGrid>("Maps/MapTemplate");

            Map.Init(Content);
        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            #region Update code:

            #endregion
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            #region Draw code:
            spriteBatch.Begin();
            Map.Draw(spriteBatch);
            spriteBatch.End();
            #endregion
            base.Draw(gameTime);
        }
    }
}

The content importer

using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;

using TInput = System.String;

namespace MagieMonoExtension
{
    [ContentImporter(".xml", DisplayName = "Tile map Importer", DefaultProcessor = nameof(TileMapProcessor))]
    public class TileMapImporter : ContentImporter<TInput>
    {

        public override TInput Import(string filename, ContentImporterContext context)
        {
            return File.ReadAllText(filename);
        }

    }

}

The processor

using System.Xml;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Content.Pipeline;
// TODO: replace these with the processor input and output types.
using TInput = System.String;
using TOutput = MagieMonoExtension.Framework.Mapping.TileGrid;

using MagieMonoExtension.Framework.Mapping;

namespace MagieMonoExtension
{
    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to apply custom processing to content data, converting an object of
    /// type TInput to TOutput. The input and output types may be the same if
    /// the processor wishes to alter data without changing its type.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    ///
    /// TODO: change the ContentProcessor attribute to specify the correct
    /// display name for this processor.
    /// </summary>
    [ContentProcessor(DisplayName = "Tile Map Processor")]
    public class TileMapProcessor : ContentProcessor<TInput, TOutput>
    {
        public override TOutput Process(TInput input, ContentProcessorContext context)
        {
            XmlDocument Doc = new XmlDocument();
            Doc.LoadXml(input);

            Dictionary<int, string> textures = new Dictionary<int, string>();

            XmlNodeList ResNodes = Doc.SelectNodes("//Map/Resources/Texture");

            foreach (XmlNode n in ResNodes)
            {
                textures.Add(int.Parse(n.Attributes["id"].Value), n.Attributes["content"].Value);
            }

            TOutput.MapResources resources = new TOutput.MapResources(textures);

            TOutput.Grid grid = new TOutput.Grid();

            XmlNodeList RowNodes = Doc.SelectNodes("//Map/Grid/Row");

            foreach (XmlNode n in RowNodes)
            {
                TOutput.Grid.Row r = new TOutput.Grid.Row();
                XmlNodeList TileList = n.SelectNodes("Tile");

                foreach (XmlNode t in TileList)
                {
                    r.Tiles.Add(new Tile(int.Parse(t.Attributes["textureid"].Value), Tile.GetTileType(t.Attributes["tiletype"].Value)));
                }

                grid.Rows.Add(r);
            }

            /*XmlNodeList EventTileList = Doc.SelectNodes("//Map/EventTiles/OnTile");

            foreach (XmlNode n in EventTileList)
            {

            }*/

            int Size = int.Parse(Doc.SelectSingleNode("//Map/Resources/TextureSize").InnerText);

            return new TOutput() { MapGrid = grid, Resources = resources, TexSize = Size };
        }
    }
}

The writer

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

using TWrite = MagieMonoExtension.Framework.Mapping.TileGrid;

namespace MagieMonoExtension
{
    [ContentTypeWriter]
    public class TileMapWriter : ContentTypeWriter<TWrite>
    {
        protected override void Write(ContentWriter output, TWrite value)
        {
            output.Write(value.TexSize);
            output.Write(value.Resources.temp.Count);
            foreach (var tex in value.Resources.temp)
            {
                output.Write(tex.Key);
                output.Write(tex.Value);
            }
            output.Write(value.MapGrid.Rows.Count);
            output.Write(value.MapGrid.Rows[0].Tiles.Count);
            foreach (TWrite.Grid.Row row in value.MapGrid.Rows)
            {
                foreach (Framework.Mapping.Tile tile in row.Tiles)
                {
                    output.Write(tile.TileTexture);
                    output.Write(tile.ThisType.ToString());
                }
            }
        }

        public override string GetRuntimeReader(TargetPlatform targetPlatform)
        {
            return "MagieMonoExtension.Framework.Mapping.TileGrid, MagieMonoExtension";
        }
    }
}

The reader

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using MagieMonoExtension.Framework.Mapping;

using TRead = MagieMonoExtension.Framework.Mapping.TileGrid;

namespace MagieMonoExtension
{
    public class TileMapReader : ContentTypeReader<TRead>
    {
        protected override TRead Read(ContentReader input, TRead existingInstance)
        {
            int texsize = input.ReadInt32();
            int resources = input.ReadInt32();
            Dictionary<int, string> RES = new Dictionary<int, string>();
            for (int res = 1; res <= resources; res++)
            {
                RES.Add(input.ReadInt32(), input.ReadString());
            }
            int rows = input.ReadInt32();
            int TilesPerRow = input.ReadInt32();
            TRead.Grid grid = new TRead.Grid();
            for (int row = 1; row <= rows; row++)
            {
                TRead.Grid.Row r = new TRead.Grid.Row();
                for (int col = 1; col <= TilesPerRow; col++)
                {
                    r.Tiles.Add(new Tile(input.ReadInt32(), Tile.GetTileType(input.ReadString())));
                }
                grid.Rows.Add(r);
            }
            TRead.MapResources Resources = new TRead.MapResources(RES);
            return new TRead() { MapGrid = grid, Resources = Resources, TexSize = texsize };
        }
    }
}

Lastly the class that its meant to create from the imported content

using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using MagieMonoExtension.Framework.Exceptions;

namespace MagieMonoExtension.Framework.Mapping
{
    public class TileGrid 
    {
        public TileGrid(/*Grid grid, MapResources mapResources, int s*/)
        {
            //MapGrid = grid;
            //Resources = mapResources;
            //TexSize = s;
        }

        public void Init(ContentManager content)
        {
            if (!Ready)
            {
                Resources.Init(content);
                Rectangle Position = new Rectangle(0, 0, TexSize, TexSize);
                foreach (Grid.Row row in MapGrid.Rows)
                {
                    Position.Y = 0;
                    foreach (Tile tile in row.Tiles)
                    {
                        tile.Position = Position;
                        Position.Y += TexSize;
                    }
                    Position.X += TexSize;
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            if (Ready)
            {
                foreach (Grid.Row row in MapGrid.Rows)
                {
                    foreach (Tile tile in row.Tiles)
                    {
                        tile.Draw(spriteBatch, Resources.GetResource(tile.TileTexture));
                    }
                }
            }
        }

        public Grid MapGrid;
        public MapResources Resources;
        public int TexSize;

        private bool Ready = false;

        public class MapResources
        {
            public MapResources(Dictionary<int, string> Res) { temp = Res; }

            public void Init(ContentManager content)
            {
                foreach (var item in temp)
                {
                    Textures.Add(item.Key, content.Load<Texture2D>(item.Value));
                }
            }

            private Dictionary<int, Texture2D> Textures = new Dictionary<int, Texture2D>();
            internal Dictionary<int, string> temp;

            public Texture2D GetResource(int id)
            {
                return Textures[id];
            }
        }

        public class Grid
        {
            public List<Row> Rows = new List<Row>();

            public List<TileEvent> EventTiles = new List<TileEvent>();

            public class Row
            {
                public List<Tile> Tiles = new List<Tile>();
            }
        }
    }
}

I am by no means an expert in xna or monogame, so im certain most of this code looks bad.

If anyone can help figure out how to resolve this issue then that would be great.

As a temporary fix i am just setting the content pipeline to copy the file and using the processors code to create the object, however as this is not able to make the files encoded it wont be usefull in the release.

What is that? Where is it happening? When is it happening? You need to be more specific for anyone to help out here. If this is happening when the asset is built you can can activate debugging by opening the MGCB Editor, press “Build” > “Debug Mode”, trigger a build from the MGCB editor and this should fire some dialogs that helps you to attach a debugger to a IDE

Well the content builds just fine, but when it runns the moment it hits Map = Content.Load<TileGrid>("Maps/MapTemplate"); it gives a null reference exception.

Here is the console output btw

'Magie.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Magie.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\Users\Theo\source\repos\Magie\bin\DesktopGL\AnyCPU\Debug\Magie.exe'. Symbols loaded.
'Magie.exe' (CLR v4.0.30319: Magie.exe): Loaded 'C:\Users\Theo\source\repos\Magie\bin\DesktopGL\AnyCPU\Debug\MonoGame.Framework.dll'. Module was built without symbols.
'Magie.exe' (CLR v4.0.30319: Magie.exe): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
AL lib: (EE) UpdateDeviceParams: Failed to set 44100hz, got 192000hz instead
'Magie.exe' (CLR v4.0.30319: Magie.exe): Loaded 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'Magie.exe' (CLR v4.0.30319: Magie.exe): Loaded 'C:\Users\Theo\source\repos\Magie\bin\DesktopGL\AnyCPU\Debug\MagieMonoExtension.dll'. Symbols loaded.
Exception thrown: 'System.NullReferenceException' in MonoGame.Framework.dll
Object reference not set to an instance of an object.

That narrows it down a lot. Now we have to find out exactly what’s Null on that line you posted. NullReferenceException is thrown when you attempt to use a variable that hasn’t been assigned a value yet. Is Content null for some reason? If not set a breakpoint in your content reader and see if something is null in there

I can check once im in school, my laptop died on me

Hmm, it apears like it throws the error when it made the TileGrid. But that makes no sense as it loaded fine with a similar approach… Could it be trying to access things things in a different order?

The steps i saw done in the TileGrid class was first to the Ready boolean that i use to make sure it wont throw errors before it has had the chance to load the map resources. then it went to the TileGrid constructor class (its empty since it had some problem) and then it threw a nullref error…

I will check that it didint do something wierd when it built the content

Huh, i set a breakpoint in TileMapReader and nothing it does not even enter it… Have i missed some step in code?

Is Content null or not? I can’t think of a good reason it should be, but it throws nullref exception at that line and and it doesn’t even enter the reader then it makes sense

I think I see the problem here. You’re referencing the reader wrong. You matched the namespace with the datatype you’re loading when you’re supposed to match it the namespace and classname of the reader

Ah i see, thank you. I will apply this right away and check

Yes it worked, now its only some pesky errors i made in data.

Thank you.