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.
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
The code in Library that can send and receive SOAP messages.
The configuration metadata that is required by Library to function.
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>
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.
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.
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.
Related
I have a WinForm project in Visual Studio 2017 where I have created a WCF endpoint reference from a service's wsdl file.
My project also uses several 3rd party dlls.
I want my project to be a standalone exe file that does not require installation, so I use ILMerge to package my dll files into a single exe file.
When running my compacted exe, I am getting exceptions about missing references to the WCF project endpoint:
Could not find default endpoint element that references contract in the ServiceModel client configuration section.
I tried looking up how to add WCF references via ILMerge, but I couldn't find anything relevant.
I also cannot find anything WCF related in my project's bin output folder.
My current usage of ILMerge is via cmd:
ILMerge.exe /t:winexe /out:target.exe /targetplatform:v4,<.net v4 path> output.exe dll1.dll ... dlln.dll
I am looking for a way to add the WCF references to the standalone exe via ILMerge, or locating the WCF reference outputs generated by Visual Studio in my project's bin out directory.
Solution
Following Abraham's comment, I found a way around the 'service reference' issue.
I used Svcutil.exe to generate the definitions to my service, and manually set the binding to it like so:
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
EndpointAddress myEndpoint = new EndpointAddress(SERVICE_URL);
SoapServiceClient client = new SoapServiceClient(myBinding, myEndpoint);
Now everything gets packed when using ILMerge.
By adding service reference, there are also some extra configurations generated in the configuration files. Therefore, it might cause the failure of packing the project. Alternatively, we manually copy the System.servicemodel section to the new project.
I suggest you change the way to consume the service. your project seems that you call the service by adding service reference. this will bring some other class libraries and references, which resulted that it is difficult to pack the project.
Please consider the below way to call the service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/channel-factory
it fully encapsulates the required class library in the main project.
Feel free to let me know if there is anything I can help with.
The VS solutions I often work with consist of a single executable project (console app, web app) and many class library projects that are all referenced by the executable.
When working with NuGet and installing packages, there's often an app.config file created for each project, usually containing nothing else than a list of binding redirects that consolidate versions of referenced assemblies. Sometimes there's some third-party library-specific content (like Entity Framework config section), but let's leave that aside for now.
When I build the solution and use the binaries of the main executable project, I see all the class library project assemblies in the build output together with the corresponding *.config files (the app.config file gets renamed to AssemblyName.config when built).
When launching the main executable, do the config files of the class library assemblies take any effect? Or is it just the app.config file of the executable that has an effect in this case? What if there are some binding redirects set up on some of the class library projects, and some different binding redirects set up on the main executable project — How are these combined, which take priority?
I've tried to research this online and from what I've read, it looks to me like the app.config files for non-executable assemblies are useless (with regards to binding redirects). Can someone confirm this or elaborate a bit more on the topic?
If it is that way, is it actually undesirable to have these app.config files created by NuGet in class libraries if they contain just the binding redirects? It feels to me that NuGet shouldn't create those binding redirects for class library projects, as it will only increase the confusion about what settings are actually applied.
I found these existing Stack Overflow questions on the topic, but their accepted answers are actually contradictory even when they're marked as duplicates of each other.
Why NuGet adds app.config with assemblyBinding to LIBRARY projects during a NuGet package update?
Is the bindingRedirect .config file needed or all assemblies in an application?
The accepted answer to the first question mentions that app.config files are actually used during compile-time, which means they could have effect. Sources like MSDN and MSBuild source code are cited there as a proof it's used during compile-time. Unfortunately, I'm not proficient enough in MSBuild to understand how it's being used, and if it's really a valid argument.
Can anybody describe an example scenario to prove that an app.config with binding redirects for a class library can do anything?
I have multiple applications with similar setup - Web application referencing multiple library projects each having their own nuget packages etc., Based on my personal experience the assembly bindings in the library projects are not considered during run time.
The bindings specified web or app config in the root application (web/console) is that only matters. All my library projects are setup with "Copy to Output Directory" setting as "Do not copy" for the app.config file - that way my output folder is not cluttered with dll and their config files.
Here is the link which says how the assembly is loaded and where is it being searched and the sequence of it. No where in the article they talk about individual project config files.
Hope that helps.
According to this old msdn article:
An application configuration file is an XML file used to control assembly binding. It can redirect an application from using one version of a side-by-side assembly to another version of the same assembly. This is called per-application configuration. An application configuration file applies only to a specific application manifest and dependent assemblies. Isolated components compiled with an embedded [ISOLATIONAWARE_MANIFEST_RESOURCE_ID] manifest require a separate application configuration file. Manifests managed with CreateActCtx require a separate application configuration file.
So only dll's with the ISOLATIONAWARE_MANIFEST_RESOURCE_ID set actually use an independent application config, otherwise it's deferred to the main process config file.
For more info on what ISOLATIONAWARE is you can read this other MSDN article that goes more in depth.
ISOLATIONAWARE_MANIFEST_RESOURCE_ID is used primarily for DLLs. It
should be used if the dll wants private dependencies other than the
process default. For example, if an dll depends on comctl32.dll
version 6.0.0.0. It should have a resource of type RT_MANIFEST, ID
ISOLATIONAWARE_MANIFEST_RESOURCE_ID to depend on comctl32.dll version
6.0.0.0, so that even if the process executable wants comctl32.dll version 5.1, the dll itself will still use the right version of
comctl32.dll.
The answer is maybe. Depending on the type of project the library file is. Some library projects run in contexts where the library's config file is respected (e.g. Azure Web Roles), but that is not the norm.
See my answer here for more details.
Generally there is only one configuration file and thats the configuration file of the executeable (.exe.config, web.config).
Any assembly redirects have to be placed in the configuration file of the executable.
Configuration files of dlls need to be loaded manually using the ConfigurationManager class. See also this question Equivalent to 'app.config' for a library (DLL)
No, only the app.config of the executable will have effect. For example, if you have a console app hosting a WCF service, and in your WCF service you make use of, for example, ConfigurationManager.AppSettings, the AppSettings will come from the console host app.config file. If you spin up another console application (ConsoleClient) to try connecting to the ConsoleHost, then in the parts where the ConsoleClient can be said to be "executing" (for example in its main method), it will use ConsoleClient's app.config, but as soon as it begins using the WCF service, the WCF service will delegate to use ConsoleHost's app.config. (Note that this last point is more relevant to the details behind WCF though.)
Surprisingly, msdn provided this great source:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e13194df-6308-4cbe-973c-f6a462f43eae/how-can-wcf-library-dll-access-application-settings?referrer=http://social.msdn.microsoft.com/Forums/vstudio/en-US/e13194df-6308-4cbe-973c-f6a462f43eae/how-can-wcf-library-dll-access-application-settings?referrer=http://social.msdn.microsoft.com/Forums/vstudio/en-US/e13194df-6308-4cbe-973c-f6a462f43eae/how-can-wcf-library-dll-access-application-settings?forum=wcf
I always see that there are app.config's in dlls and then website has web.config.
At the run time mostly web.config passes data to all the portable libraries.
These configuration are passed as properties of portable library class. ConfigurationManager is used to get the values from config file.
Now the problem, In my current project they have configsectionhandler in webapp project/folder.
and my project folder structure is like
Main
WebApp
BusinessObject
ThirdPartyWebserviceCall
and as usual webapp project has reference to BusinessObject and BusinessObject has reference to ThirdPartyWebserviceCall.
Now if I want to use configsectionhandler in ThirdPartyWebserviceCall I will have add a circular reference to
webapp.
Does this design seem ok? It looks realy flawed to me.
Is there other standard pattern to access configuration values in the libraries.
I am a bit confused on this subject.
The situation I have is I have two separate projects in C#:
are service (A)
a helper project (B)
Both are in seperate solution files. (A) has reference (B)
What i am confused about is that e.g. I have app.config file in (A), so when I refer to:
ConfigurationManager.AppSettings["XYZ"]
in project (B). does that mean I am using project (A)'s app.config file?
Yes, the ConfigurationManager class and the underlying configuration file is available to the whole AppDomain instance. Since your library will be getting used by the service, it becomes part of the service's AppDomain and inherits access to that configuration file.
If you want the other binary (project B) to have it's own, then you need to create an instance of it in it's own AppDomain. It's more trouble than it's worth, so I wouldn't try to look into doing this.
Any AppDomain that will use this library will be providing it's config settings. This means that if the library has it's own settings the service itself does not use, then you need to ensure any executable that uses the library has the settings present.
So if you have a solution that has ProjA (Console app), ProjB (WinForms app), and they both use ProjC (shared library), make sure the settings ProjC is looking for are in both ProjA and ProjB's config files since ProjA and ProjB are their own AppDomain instances when run.
The answer to your question is YES
And another point to note here is that the app.config file of your main project is always deployed (not the referenced project) unless you explicitly copy the app.config of referenced project. Therefore it is always better to do all your work on app.config of your main project which in your case is A
If i understand correctly you have two projects in ur solution
Project A (WebService)
Project B (Class library)
if that's the case - Yes. ConfigurationManager.AppSettings will read from the config file of the startup project i.e Project A in ur case.
However if you have different project which run independently for e.g. two different service projects Service1 and Service2 both will refer to their respective app.config/web.config files.
I have standard class library infrastructure assembly which i reference in my main application.
The infrastructure assembly uses a webservice internally and exposes functionality to my main application.
To get it to work i need to add a reference in my main app to the webservice otherwise i get a Endpointexeption. If i add it everything works fine. It seems to me that the infrastructure dll reads information in the main applications app.config so the entry has to be there. But it seems strange that i cant expose the web service throug an external dll as the main application does not call the webservie directly. Whats even stranger is that the webservice ignores the main applications security mode and reads it from the external dll's app.config.
If im correct in my assumptions, how do i expose a webservice in an external dll withot the main app knowing about the webservice.
in your class library project when you add the service reference you have to make sure the generated proxy is Internal.
for more info:
C#, WCF, Hide web service through dll
This will hide the WCF interface to the client.
if you don't want that the client that uses your class library project needs to add the WCF configuration key in its app/web.config your library has to configure the EndPoint/address/binding in the code (hard coded) but I won't recommend you to go down this road as if something changes on the WCF side your class library won't work anymore
You don't need to add the service reference to your main app, but you must copy the relevant configurations to the main app.config