2

[C# .NET 4.0 WinForm LINQ]

I had an XML file that I added to my project as Content, but I'm now having to make it an internal, embedded resource so it will compile with the executable and I won't have to create an install/deployment package for the app.

However, I have existing code that uses LINQ to query the XML file that won't work now that I've made the file an embedded resource. What do I need to do differently to be able to query the XML file if it's an embedded resource compared to when it's a content resource? I've seen some

Once I query the XML file, I loop through the results and load them into a list box. Here's the code I'm using to query the XML file when it's set to Content and my loop to add to the listbox:

var computers = from e in XElement.Load(@"MyXML.xml").Elements("computer")
        select (string)e.Element("name");

foreach (var c in computers)
{
    if (!IsNullOrEmpty(computer))
    {
        lstComputer.BeginUpdate();
        lstComputer.Items.Add(computer);
        lstComputer.EndUpdate();
    }
}

I've seen some other examples, like this one, that use the assembly to read the file into a string...is this what I would have to do? Not to further reveal my inner noob, but if that's the case, does the example in the link above return a delimited string that I can loop through so I can add the items to my listbox?

Thanks...

Community
  • 1
  • 1
user2063351
  • 503
  • 2
  • 13
  • 31

2 Answers2

3

Open the embedded resource as a stream:

XElement doc;
using (var stream = typeof(SomeTypeInTheAssembly).Assembly
                        .GetManifestResourceStream("MyXML.xml"))
{
    doc = XElement.Load(stream);
}

There's no need to go via an intermediate string representation.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This requires a reference to the IO and Reflection namespaces, right? Also, could you give a little more detail about `SomeTypeInTheAssembly`? – user2063351 May 22 '13 at 12:56
  • @user2063351: Nope, no `using` directives required. The point of `SomeTypeInTheAssembly` is just that you pick *any* type which is in the right assembly - you're just trying to specify which assembly you want to fetch the stream from. So the type that this code occurs in is probably fine, but I didn't know what that was called... – Jon Skeet May 22 '13 at 12:59
  • I'm sorry for being dense...would a valid `typeof(SomeTypeInTheAssembly)` be "XML"? If I'm creating a Windows Form, would I be best suited to use `this.GetType().Assembly` instead of `typeof(SomeTypeInTheAssembly).Assembly`? – user2063351 May 22 '13 at 13:05
  • @user2063351: Well I don't know - do you have a class called `XML` in the right assembly? You could use `this.GetType()` if it's in an instance method, sure. – Jon Skeet May 22 '13 at 13:07
  • Okay, I don't have either of those. How can I find the type to use in the assembly? When I set the XML file to be an embedded resource, should Visual Studio have added something to the AssemblyInfo.cs file? – user2063351 May 22 '13 at 13:16
  • @user2063351: What do you mean "you don't have either of those"? You're writing this code within a class, right? So use the name of that class. And no, nothing will be added to AssemblyInfo.cs. – Jon Skeet May 22 '13 at 13:28
  • I just meant that I don't have a separate class/instance method I'm using to query the XML and I don't have a class called XML in the assembly. – user2063351 May 22 '13 at 13:30
  • I added your code and put `using (var stream = typeof(testForm).Assembly.GetManifestResources("MyXML.xml")) { xDoc = XElement.Load(stream); }`, but it throws an 'ArgumentNullException' error on `xDoc = XElement.Load(stream);` saying to use the "new" keyword to create an object instance. I tried `XElement xDoc = new XElement();`, but XElement doesn't have a zero argument constructor. What am I missing? – user2063351 May 22 '13 at 13:38
  • @user2063351: That will happen if `GetManifestResourceStream` (not `GetManifestResources`) returns null... which may be because the name is slightly different. Open the assembly with Reflector or ILDASM to check the exact resource name. You *don't* want to be creating a new XElement directly. – Jon Skeet May 22 '13 at 14:44
  • Sorry...I'm using `GetManifestResourceStream`. I typed the wrong thing, but my code matches yours in that regard in Visual Studio. Okay, so I used ILDASM and it says MyXML.xml is in the assembly at `.mresource public NewComputerForm.MyXML.xml { // Offset: 0x000013B0 Length: 0x0000051A`. However, when I try `using (var stream = typeof(NewComputerForm).Assembly.GetManifestResourceStream("MyXML.xml"))`, I still get the ArgumentNullException error. I also tried `typeof(NewComputerForm.Properties.Resources)`, but it returned the same error. Any ideas? – user2063351 May 22 '13 at 15:28
  • @user2063351: Yes - you can see the name right there: "NewComputerForm.MyXML.xml" - so make that the resource name that you ask for. – Jon Skeet May 22 '13 at 15:29
  • Oh...okay! I was so caught up in the `typeof(SomeTypeInTheAssembly)`, that I wasn't thinking that I should change the name in the `GetManifestResourceStream` (even though that's what you were obviously saying in your last comment). Thanks for being patient with me and for all your help. – user2063351 May 22 '13 at 15:41
0

Based on Jon Skeet's answer, you could use Assembly.GetExecutingAssembly() to make things a little bit easier:

using System.Reflection;

XElement doc;
using (var stream = Assembly.GetExecutingAssembly().
                    .GetManifestResourceStream("MyNameSpace.MyXML.xml"))
{
    doc = XElement.Load(stream);
}
Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62