3

Fill the blank:

If a piece of code on a DLL is used from different contexts and we need to identify which context are we running on, we have to use:

Web Application -> System.Web.HttpContext.Current != null

WCF Web Service -> System.ServiceModel.Operationcontext.Current != null

Windows Service || ConsoleApp -> ______________________________________________________

Also, if you know a better option for checking one of the first two, tell us please.

About the fact that it could be a duplicate from another question: I don't need to differentiate between a windows service and a console application (user interactive or not).

EDIT: Why do I need that?

I need to open the configuration file for the running application from a library that can be running on different contexts. This is what I currently have:

Configuration appConfig = null;

if (System.Web.HttpContext.Current != null || System.ServiceModel.OperationContext.Current != null)
{
    // The call was originated from a web application or from a WCF web service.
    appConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
}
else
{
    // The call may have been originated from a console application or a windows service.
    // THE ANSWER TO MY SO QUESTION WOULD ALLOW ME TO INSERT AN IF HERE!!
    appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
}

The else part is assuming I'm running on a exe like environment (windows service, console app). I would like to include an if there to be sure that OpenExeConfiguration won't throw an exception.

I already considered using try blocks but that's not suitable for my case.

Community
  • 1
  • 1
daniloquio
  • 3,822
  • 2
  • 36
  • 56
  • @user2893289 I edited my question to indicate why it's not a duplicate. – daniloquio Dec 09 '15 at 14:08
  • perhaps you should explain why you need to know that. – Daniel A. White Dec 09 '15 at 14:09
  • Almost always better to expose extension points so that your consumer can plug in and choose the most appropriate behaviours, rather than your DLL "magically" deciding on the best way to do things. – Damien_The_Unbeliever Dec 09 '15 at 14:18
  • 1
    Aren't you just looking for [`ConfigurationManager.AppSettings`](https://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.appsettings(v=vs.110).aspx), which _"Gets the AppSettingsSection data for the current application's default configuration"_? – CodeCaster Dec 09 '15 at 14:23
  • @Damien_The_Unbeliever I definitively don;t want any magic on my code; I rather use some .NET code ;) Seriously, I get your suggestion and agree that would be a fine way to achieve this. Even though, that's not an alternative in this case because of backward compatibility requirements. I just cannot go and modify every call to my library. – daniloquio Dec 09 '15 at 14:23
  • @CodeCaster AppSettings is just a section on the config file. AS you see appConfig is of type Configuration which is not the same as the Key Value collection that AppSettings exposes. My final objective doing this is to get the binding configurations for WCF services. – daniloquio Dec 09 '15 at 14:30
  • Well then the question is: do you really want to be reading the configuration from your class library? Can't you add a constructor parameter of type `Configuration` that the consuming application provides? Otherwise your library will have to reference both `System.Configuration` and `System.Web`. AFAIK there is no fool-proof way to detect whether you're running on a web.config or an .exe.config, so you will have to use `try-catch` to try both. – CodeCaster Dec 09 '15 at 14:39
  • @CodeCaster That was already suggested by damien_the_unbeliever; I told him that I have backwards compatibility requirements that just make it impossible for me to modify every call to this library. I already put in place a couple mechanisms to use default values in case the proper config wasn't identified, but I'd love for someone to answer this question, either explaining how to do it or explaining why isn't possible do achieve. – daniloquio Dec 09 '15 at 14:48
  • `OpenExeConfiguration`? Why are you grabbing the configuration like this. Just have a clean and clear interface that expects the caller to cough up the data you need? Incidently, backward compatablity is already broken, you've just moved it from compile time to run time (hoorah... said no-one). – Nathan Cooper Dec 09 '15 at 14:48
  • You're saying "using try blocks is not suitable", so there really is no solution then. Can you perhaps update your question (and especially its title) to include all relevant details? :) – CodeCaster Dec 09 '15 at 14:49
  • @CodeCaster you can check the edit history for this question. I've already edited it in several ways to make it more understandable. I already spent more time than I should on this question. – daniloquio Dec 09 '15 at 14:57
  • But your question is not anymore _"if the context is a windows service"_, right? You just want to read either a `web.config` or an `.exe.config` as a `Configuration` object? – CodeCaster Dec 09 '15 at 14:58
  • @NathanCooper You are wrong about the backwards compatibility issue. Sorry I can't change my real world coding scenario to a different one where I'm allowed to 'just' do what I 'just' should do, a lot like on school. Wouldn't that be nice? – daniloquio Dec 09 '15 at 15:00
  • 1
    @CodeCaster I already know how to identify and open the config file for webapp and wcf contexts. The only missing piece is how to identify if I'm running on a windows service context. With that, my problem would be solved. I'm going to update the title to reflect the fact that on this case a windows service context would be equivalent to a console app context. Thanks for your comments :) – daniloquio Dec 09 '15 at 15:03
  • Thanks. Anyway, `System.ServiceModel.OperationContext.Current` is not `null` in a WCF service hosted inside a Windows Service, causing your code to assume it is running in a web context. If you want fool-proof, working code, I think you _need_ to use `Configuration config; try { config = ..WebConfigurationManager.. } catch { try { config = ..ConfigurationManager.. } catch { } }`. – CodeCaster Dec 09 '15 at 15:05
  • @CodeCaster you are right, that would do it. Unfortunately, there's a exception handling framework going on the background and introducing these try here would go against it. – daniloquio Dec 09 '15 at 15:09
  • If your constraints are that you cannot let exceptions be thrown (even if you catch them), then you'll have to introduce hacks that will break at a later moment. You could for example check whether `AppDomain.CurrentDomain.SetupInformation.ConfigurationFile` ends in `web.config`. – CodeCaster Dec 09 '15 at 15:29
  • @CodeCaster I was getting to something similar. Checking if 'System.AppDomain.CurrentDomain.FriendlyName' ends with exe. I like your suggestion because it actually asks for the configuration file. Wuold you add it as an answer, I think it's a valid solution. – daniloquio Dec 09 '15 at 15:37

1 Answers1

2

I think it is a pretty fragile construction, but if you check whether AppDomain.CurrentDomain.SetupInformation.ConfigurationFile ends in the string web.config you can verify that the current application domain is running in a web server, so then you can call System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~"); to obtain a Configuration instance.

The reverse is true as well: if it ends in .exe.config you can use ConfigurationManager.OpenExeConfiguration(...).

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • I like this approach because it would actually work, but you are presenting the answer in terms of how to identify that you need to open a web.config, whereas the question is about how to identify that you need to use OpenExeConfiguration because we are on an exe like context. So, one could check if `AppDomain.CurrentDomain.SetupInformation.ConfigurationFile` ends with '.exe.config'. Do you agree? – daniloquio Dec 09 '15 at 15:47
  • And yes, I agree it's fragile, not ideal, but sometimes you don't have an alternative. – daniloquio Dec 09 '15 at 15:49