I have a method that is suppose to edit a xml file:
public void EditItem(Item item, string xml)
{
Data = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/Items/" + xml + ".xml"));
XElement node = Data.Root.Elements("item").Where(i => (string)i.Element("ID") == item.ID).FirstOrDefault();
node.SetElementValue("ID", item.ID);
node.SetElementValue("Name", item.Name);
node.SetElementValue("Type", item.Type);
node.SetElementValue("Kr", item.Kr);
node.SetElementValue("Euro", item.Euro);
Data.Save(HttpContext.Current.Server.MapPath("~/App_Data/Tables/" + xml + ".xml"));
}
I get this validation error thru a try/catch in my controller: "Object reference not set to an instance of an object." Through some debugging, I found that "node" is null, even though "Data" contains all the right data from the xml, and the model.ID is correct.
the wierd thing is, that I have it working in another repo where the xml isnt dynamic, and the XDocument obj is loaded in the constructor.
Any ideas what causes it? Or maybe some ideas on a workaround.
Update. Xml snippet:
<?xml version="1.0" encoding="utf-8"?>
<catagory id="0">
<module>
<item>
<ID>101</ID>
<Name>ClassicoTable(35x100x100)</Name>
<Type>Model</Type>
<Kr>0</Kr>
<Euro>0</Euro>
<DataType>ClassicoTableA</DataType>
</item>
<item>
<ID>100</ID>
<Name>ClassicoTable(102x100x140)</Name>
<Type>Model</Type>
<Kr>0</Kr>
<Euro>0</Euro>
<DataType>ClassicoTableB</DataType>
</item>
......
</module>
</catagory id="0">
Should this line:
XElement node = Data.Root.Elements("item").Where(i => (string)i.Element("ID") == table.ID).FirstOrDefault();
be this (not sure where table.ID
comes from):
XElement node = Data.Root.Elements("item").Where(i => (string)i.Element("ID") == item.ID).FirstOrDefault();
I would also check if node is null:
public void EditItem(Item item, string xml)
{
Data = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/Items/" + xml + ".xml"));
XElement node = Data.Root.Elements("item").Where(i => (string)i.Element("ID") == item.ID).FirstOrDefault();
if (node != null)
{
node.SetElementValue("ID", item.ID);
node.SetElementValue("Name", item.Name);
node.SetElementValue("Type", item.Type);
node.SetElementValue("Kr", item.Kr);
node.SetElementValue("Euro", item.Euro);
Data.Save(HttpContext.Current.Server.MapPath("~/App_Data/Tables/" + xml + ".xml"));
}
}
Okay found a solution. I started wondering why @Kim wanted a snippet from my xml. So it made me think that Data.Root.Element()
maybe wasnt the right way. So I tried with Descendants()
instead, and that actually works. Why? I have no clue. Heres why:
In another repo I have the XDocument.load()
in the constructor of the repo. I thought that would be good, because then I wouldnt have to repeat the same code in all the CRUD methods. But, as I wanted the xml dynamic, and the constructor doesnt accept parameters, I thought this way (original question) would be fine. Here the code from the "static" repo:
//Constructor
public CubeRepository()
{
allCubes = new List<Cube>();
CubeData = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/Cubes/Cubep10p11.xml"));
var cubes = from cube in CubeData.Descendants("item")
select new Cube(cube.Element("ID").Value,
cube.Element("Name").Value,
cube.Element("Type").Value,
(int)cube.Element("Kr"),
(int)cube.Element("Euro"));
allCubes.AddRange(cubes.ToList<Cube>());
}
And in my edit method of that repo:
public void EditCube(Cube cube)
{
XElement node = CubeData.Root.Elements("item").Where(i => (string)i.Element("ID") == cube.ID).FirstOrDefault();
node.SetElementValue("ID", cube.ID);
node.SetElementValue("Name", cube.Name);
node.SetElementValue("Type", cube.Name);
node.SetElementValue("Kr", cube.Kr);
node.SetElementValue("Euro", cube.Euro);
CubeData.Save(HttpContext.Current.Server.MapPath("~/App_Data/Cubes/Cubep10p11.xml"));
}
And that works like I charm, even though im using CubeData.Root.Elements("item")
. Note: Elements
insted of Descendants
. The structure of the xml files are identical.