23

I have a C# class library and a startup project (a console app). The class library includes a service reference to a web service. When I try to run the project, I get an InvalidOperationException because the startup project isn't reading the class library's app.config, and it's ignoring the service reference. To get it working, I'm forced to add the same service reference to the startup project. Is there any way I can avoid this? Can I make the startup project recognize the class library's service reference and app.config without having to copy it to the startup project?

I've tried adding a link to the app.config from the class library, but that doesn't work. The class library isn't very portable if it requires anyone who uses it to add that service reference to the startup project.

JR.
  • 5,840
  • 9
  • 31
  • 34
  • +1: Hey Zarjay, I was gonna ask the same question. While I agree with Andrew Hare, and understand why this isn't possible, I too agree the solution doesn't really make the Library very portable. I wonder, can the config settings be applied programatically? – andy Jun 15 '09 at 03:19
  • I'm not sure, but I doubt it. Awesome idea, though. I know it's possible to write to the config file, but I bet that by the time your code is able to, it's probably too late to add a service reference. – JR. Jun 15 '09 at 20:39

5 Answers5

15

Think about what you are trying to do - you have two assemblies that you are building:

Library
ConsoleApp

Both of these assemblies have configuration files - I would imagine they look something like this:

Library
    app.config
ConsoleApp
    ConsoleApp.exe.config

When you run ConsoleApp it has no way of reading from or knowing aboout app.config from your Library assembly. The only configuration file that it knows or cares about is ConsoleApp.exe.config. Now it is possible to have configuration files reference each other but this is not the proper solution for what you are trying to do.

Since your Library assembly has no entry point, it will never be loaded into an AppDomain. Since it will never be loaded into an AppDomain its application configuration file will never be used.

What you ought to do is reference Library in ConsoleApp via a project reference. Then move all the relevant configuration data from app.config into ConsoleApp.exe.config as this is the configuration file that will be used by your application.

This will allow you to have to two things you need to invoke methods on your web service

  1. The code in Library that can send and receive SOAP messages.
  2. The configuration metadata that is required by Library to function.
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • Thanks for the explanation; makes sense now why it wasn't working. I'm still new to .NET, and while I prefer the class library to be a self-contained module whose internal implementation is irrelevant to the code that's using it, I understand now why it doesn't work in this situation. – JR. Feb 09 '09 at 21:04
  • For what it's worth, the config data isn't internal implementation-- it's library configuration data that should be provided by the user of the library (your console app). My general practice is to provide the sample configuration text in an app.config with the library project when a config file is req'd, then to assume that the user of the library copies that config data into their own config file, making changes as appropriate. If the config file isn't req'd, those options just become programmatic config knobs on the library. – Greg D May 20 '09 at 12:11
  • 7
    Greg, I disagree. The library config data would equate to a web service URL that the developer would know, not the user. The user shouldn't have to care what that URL is; it's an internal implementation of a library, and as a user of the interface (the library), I shouldn't care the details of the implementation (the web service it's using). Thank God I can use Google's Java client libraries without caring what URLs it uses to perform its functions. Unfortunately, if there were a .NET version, I'd be forced to care. Not having this option is a big flaw in .NET in my opinion. – JR. Jun 15 '09 at 20:33
  • Excellent explanation which has just helped me figure this annoying issue out - thank you – wheelibin Jun 10 '11 at 09:13
3

An alternative to using a service reference in the class library and then copying the config would be to use build events that call svcutil.exe. The thing I like about this is that you don't have to make "update service reference" when the service changes. It will be updated automatically.

In the class library, use a build event that only generates the proxy code:

svcutil.exe net.tcp://localhost:3315/MyService/mex /noConfig

In the application, use a build event that generates the config. You can use the /mergeConfig option to merge it into an existing app.config.

svcutil.exe net.tcp://localhost:3315/MyService/mex 
            /config:App.config /mergeConfig

If you don't want to get a build error if the service is not running, put this in your project file and you will get a warning instead of an error:

<Target
    Name="PreBuildEvent"
    Condition="'$(PreBuildEvent)'!=''"
    DependsOnTargets="$(PreBuildEventDependsOn)">
  <Exec WorkingDirectory="$(OutDir)"
        Command="$(PreBuildEvent)"
        ContinueOnError="true" />
</Target>
D.H.
  • 1,083
  • 2
  • 11
  • 22
1

You just need to copy the config key, pointing to the service, from your class library config file to your console app's config file.

Martin Bring
  • 1,176
  • 1
  • 7
  • 17
  • My app.config doesn't have a config key. How do I specify one? – JR. Feb 09 '09 at 19:53
  • When reference a web service you can choose to use static or dynamic reference, see properties. Choosing dynamic makes the IDE generate code, in your web service proxy class, to read the url from the config file. Copy the values generated in the library's config to your console app's config. – Martin Bring Feb 09 '09 at 20:07
1

You can copy the relevant portions of the app.config from the class library's configuration into the app.config for the console application.

Alternatively, if you're really trying to make this truly portable, you'll need to think about another way of referencing the address for the specific service reference from within the class library.

David Morton
  • 16,338
  • 3
  • 63
  • 73
  • I've tried copying over the app.config, but the console app won't run unless I add the service reference as well. Portability really isn't a priority; I just find it annoying to redundantly include something in a project. The class library should be self-contained. – JR. Feb 09 '09 at 19:56
  • The class libraries that are WCF-clients are purposely not self contained. They're not typically meant for redistribution. They're meant to be configurable on the client end, which is why the app.config is typical for these. You can always hardcode the value, but thats... well... hard-coding. :) – David Morton Feb 09 '09 at 20:06
0

I'd think it more confusing if you had multiple configuration files running around.

If a library has configurable items, I would fully expect to have to put that configuration in my config file to properly consume the library.

Joe
  • 41,484
  • 20
  • 104
  • 125