2

I have a WCF service library that reads a xml file that's located in the WCF publish location. The project is not client profile.

When I debug in the WCF test client it works fine with:

XDocument xDoc = XDocument.Load(@".\PaymentAvailability.xml");

But when consuming the service from a website it says it cannot find PaymentAvailability.xml ... it looks like its trying to get the location of the xml file from the consuming app.

I've tried the answers posted here but no luck How to get working path of a wcf application?

System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath returns null

With AspNetCompatability HttpContext.Current.Server.MapPath("."); also doesn't return anything

Community
  • 1
  • 1
Chris Klepeis
  • 9,783
  • 16
  • 83
  • 149

3 Answers3

3

This is a really bad practice, you should place the configuration for your library in the .config file for the application that is using your library, using custom section handlers (which the Configuration Section Designer does very well for you) if you want strongly typed XML configuration.

The reasoning being that it's your application that you are configuring; if your library really operated so independently of your application, then you should reconsider whether or not the library should not be it's own application.

One option that you have to mitigate this to create a custom config section handler and then use the configSource attribute. While you won't be able to use one single file (the attribute does not allow for absolute paths), you can copy the one file into the bin directory of each application.

Note that you'll have to explicitly get the config section, but you have to do that anyway now to load your file, but at least you'll be more in line with the configuration manager.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • What should go in the consuming app? The XML file path? - but every app that consumes that WCF service will read from the same xml file. Nevertheless, I'll definately read into config sections as I'm not familiar with that (newbie to WCF). The PaymentAvailability xml file tells the consuming app if other WCF payment services are available (for example, if PayPal has scheduled downtime, I can list that in the xml file and the consuming site will disable PayPal as a payment option) -> this would be used my multiple sites and easily allow me to disable payments across a bunch of sites with 1 file – Chris Klepeis Sep 30 '11 at 12:43
  • So really, I suppose it could be considered a configuration, but it has to be shared across multiple sites.... I'm not going to manually update 10 web.configs :p – Chris Klepeis Sep 30 '11 at 12:52
  • @Chris Klepeis: Yes, if you have N sites, then those N sites should have their own configuration, and it should be copied into the config file. You can also use the `configuSource` attribute; see my updated answer for more info. – casperOne Sep 30 '11 at 14:24
  • I agree that it's perhaps a bad practice, however, (correct me if I'm wrong here) but if I update that file in the bin directory, since its part of the config then the application will restart - killing our sessions (we don't have session persistence between restarts). Since its a high traffic site, we want to minimize that as much as possible until we can get that session persistence setup – Chris Klepeis Oct 01 '11 at 04:39
  • 2
    @ChrisKlepeis: If you are hosting in an ASP.NET session, and you use the `configSource` attribute, yes, it will cause a new app domain to be created and the old one (with it's session state) to go away. However, in-memory session state will kill you if you ever have load balancing (you should use something like a session state server, or sql server as your session state manager to prevent this). – casperOne Oct 01 '11 at 13:36
2

In general

System.Reflection.Assembly.GetExecutingAssembly().Location

gives you the phyisical path of the executing assembly.

On the msdn page you can see the difference between GetExecutingAssembly, GetEntryAssembly and GetCallingAssembly.

That said, it may not be a good idea anyways (see casperOne's answer).

Community
  • 1
  • 1
Francesco De Vittori
  • 9,100
  • 6
  • 33
  • 43
0

This works, but from the other answers, I'm going to see if this is indeed a bad practice and can be done a better way.

ServiceHostBase hostBase = OperationContext.Current.Host;
VirtualPathExtension virtualPathExtension = hostBase.Extensions.
    Find<VirtualPathExtension>();

XDocument xDoc;

if (virtualPathExtension != null)
{
    /// It’s hosted.
    xDoc = XDocument.Load(Path.Combine(
        HostingEnvironment.ApplicationPhysicalPath, AvailabilityFileName));
}
else
{
    /// It’s not hosted.
    xDoc = XDocument.Load(AvailabilityFileName);
}
casperOne
  • 73,706
  • 19
  • 184
  • 253
Chris Klepeis
  • 9,783
  • 16
  • 83
  • 149
  • 1
    This is an even worse practice; functions like this should not be self-aware; what they need should be passed to them and the library should use that. In this case, if the caller is calling the library, it knows it's in a host (if it doesn't then there's something wrong with *that* code), if it's not in a host, it knows it's not. Then, the caller should tell the library where to look for the file. – casperOne Oct 03 '11 at 11:57