0
votes

I'm building a web service in C#. On this web service I have the following code:

    public class Service1 : System.Web.Services.WebService
        {

            [WebMethod]
            public decimal GetTaxAmountx(decimal amount, int year)
            {
                decimal result;
                result = LB.GetTaxAmount(amount, year);
                return result;

            }
        }

LB is a static class providing a static method GetTaxAmount(decimal amount, int year). This class is in a dll which I reference from my web service. The LB.GetTaxAmount method uses linq to xml to load some data, like this:

    var name = from nm in XElement.Load("Taxes.xml").Elements("Year").Elements("Scale")
                   where nm.Parent.Attribute("id").Value == year.ToString()
                   && (decimal)nm.Element("MoreThan") <= amount
                   && (decimal)nm.Element("NotMoreThan") >= amount
                   select new 
                   {
                        TaxAmount =  nm.Element("TaxAmount"),
                        Percentage = nm.Element("Percentage"),
                        MoreThan = nm.Element("MoreThan")
                   };

Finally LB.GetTaxAmount returns a decimal.

When testing a call to LB.GetTaxAmount by referencing the dll from code in a plain vanilla class, it all works. But when I test the web service by entering the parameters and clicking the INVOKE button, it finds the dll but cannot find the XMl file which I put in the same folder as the ddl file. I get the following error message:

System.IO.FileNotFoundException: Could not find file 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Taxes.xml'. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize) at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials) at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn) at System.Xml.XmlReader.Create(String inputUri, XmlReaderSettings settings, XmlParserContext inputContext) at System.Xml.XmlReader.Create(String inputUri, XmlReaderSettings settings) at System.Xml.Linq.XElement.Load(String uri, LoadOptions options) at System.Xml.Linq.XElement.Load(String uri) at AtYourServiceSoftware.LB.GetTaxAmount(Decimal amount, Int32 year) at sxm3.Service1.GetTaxAmountx(Decimal amount, Int32 year) in C:\Documents and Settings\user\My Documents\Visual Studio 2008\Projects\sxm3\sxm3\Service1.asmx.cs:line 29

Hope someone knows an answer, thanks in advance. Joost

Oh and btw, I want the xml to be external and not embedded, so it can be updated from time to time by my client (client as in the guy who pays me).

UPDATE: Found it thanks to Mike and Kyle and this post: http://www.stackoverflow.com/a/283917/243557

I changed it to:

    static public string AssemblyDirectory
           {
               get
               {
                   string codeBase = Assembly.GetExecutingAssembly().CodeBase;
                   UriBuilder uri = new UriBuilder(codeBase);
                   string path = Uri.UnescapeDataString(uri.Path);
                   return Path.GetDirectoryName(path);
               }
           }

           public static decimal GetTaxAmount(decimal amount, int year)
            {

                var name = from nm in XElement.Load(AssemblyDirectory +         @"\Taxes.xml").Elements("Year").Elements("Scale")
                           where nm.Parent.Attribute("id").Value == year.ToString()
                           && (decimal)nm.Element("MoreThan") <= amount
                           && (decimal)nm.Element("NotMoreThan") >= amount
                           select new 
                           {
                                TaxAmount =  nm.Element("TaxAmount"),
                                Percentage = nm.Element("Percentage"),
                                MoreThan = nm.Element("MoreThan")
                           };
2
Can you still continue? As .net might handle exceptions in the frame work internally. And you can't do anything about those exceptions but ignore them. What if you disable first change exception? Does your program continue? - Mike de Klerk
Thanks for your answer. I'm not sure what you mean, Mike. I'm a relative noob to C# anf the whole .net environment. But anyways, whether I can continue or not is not really the issue. The routine needs the data from the external XML file to do some calculations and give the result back. - Joost Stolk
Read about first chance exceptions. I highly doubt you are using a file C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Taxes.xml in your application yourself when you just start programming in C#. Oh I see now. You only added the name, instead of the whole path like Kyle answered. - Mike de Klerk
Thanks, I learned something new, I posted the solution in my original Question. - Joost Stolk

2 Answers

1
votes

You need to fully qualify the path to taxes.xml. something like c:\somefolder\anotherfolder\taxes.xml

0
votes

This is working: The XML file resides in the same folder as the executing dll. First get the fully qualified path to the executing assembly and pass that in to XElement.Load()

      static public string AssemblyDirectory
       {
           get
           {
               string codeBase = Assembly.GetExecutingAssembly().CodeBase;
               UriBuilder uri = new UriBuilder(codeBase);
               string path = Uri.UnescapeDataString(uri.Path);
               return Path.GetDirectoryName(path);
           }
       }

       public static decimal GetTaxAmount(decimal amount, int year)
        {

            var name = from nm in XElement.Load(AssemblyDirectory +         @"\Taxes.xml").Elements("Year").Elements("Scale")
                       where nm.Parent.Attribute("id").Value == year.ToString()
                       && (decimal)nm.Element("MoreThan") <= amount
                       && (decimal)nm.Element("NotMoreThan") >= amount
                       select new 
                       {
                            TaxAmount =  nm.Element("TaxAmount"),
                            Percentage = nm.Element("Percentage"),
                            MoreThan = nm.Element("MoreThan")
                       };