How to merge the applicationSettings of a class library into the host executable's config file - visual-studio

I am reading articles, forum posts about applicationSettings for almost a week now.
In almost every thread there was someone that appears to have correctly pointed out that the class libraries cannot have config files when deployed and their applicationSettings configured at design must be specified/merged in the executable.exe.config configuration file of the application that host/consumes the dll.
Not necessarily true.
You can but you don't need to merge them class library settings unless you want to provide the user with a way to "overwrite" the default values - the ones that are specified using the DefaultValueAttribute hard coded in the assembly.
So, for a very simple, practical example. Let's use VB.NET
1. I created a Class Library project called ClassLibrary.
2. Showing all files, expand MyProject, double click Settings.settings.
3. Adding a setting called Message, application scoped whose value is "Hello!".
4. Create a property in Class1.vb (the automatically added class)
Public Class Class1
Public Shared ReadOnly Property Message As String
Get
Return My.Settings.Message
End Get
End Property
End Class
Create a VB WinForms project and call it WinForm.
Add a reference to the ClassLibrary project.
Add a button to the already created Form1 and double click on it.
8 Add the some code to the the Button1_Click handler. Should look like this.
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
MessageBox.Show(ClassLibrary.Class1.Message)
End Sub
End Class
Have WinForm "Set as Startup project"
Now, while in the IDE everything works beautifully. Run the solution and you'll get the expected Hello! when you press the button. If you go and change the setting in the app.config of the library to say "Good bye!" and you run the solution again you get a "Good bye!"
However, right click on the WinForm project and "Open in Explorer" and get to the Debug folder. There's no WinForm.exe.config file yet. Let's create one quickly.
Switch back to VS and while the WinForm project is selected click to Show All Files.
Expand MyProject, open Settings.settings, create a setting (doens't matter what) and save.
There we go, an App.config was created and if I build this solution, the Debug folder will contain a WinForm.exe.config.
Tell me how I merge my Message setting from the class library config
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="ClassLibrary.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<ClassLibrary.My.MySettings>
<setting name="Message" serializeAs="String">
<value>Hello!</value>
</setting>
</ClassLibrary.My.MySettings>
</applicationSettings>
</configuration>
into the WinForm's config
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="WinForm.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
</startup>
<applicationSettings>
<WinForm.My.MySettings>
<!--<setting name="A" serializeAs="String">
<value>A</value>
</setting>-->
</WinForm.My.MySettings>
</applicationSettings>
</configuration>
so I can change the Message setting's value in the WinForm.exe.config to something else and the application will display this new value overriding the DefaultValueAttribute.

I have done some research lately for this applicationSettings problem.
I found two relatively convenient ways of doing what I was asking for.
I put my thoughts about it together and wrote a blog entry here.
assemblies that your main assembly depend on can and will use settings you define in their individual projects but only during development just because they are build on the fly and contain whatever values you set last time. However when you deploy and think that you can place .config for each assembly they won't work if you expect to change a setting's value and have that reflected at runtime, that's because the last values are set as default values and are hardcoded in.
So you have to either move all your settings to the appSettings in the .config file of the main assembly and inject them at runtime as needed to the assemblies needing them (passing them as arguments).
Otherwise let's say these are your config files while in development:
2
3
For deployment you will have to create a configuration section in the main config file and point to
your modified "ClassLibrary.dll.config":
You don't have to point to external files though, the config sections declarations can point to their definitions further down in the main config file like this.

Related

XML put constant settings in App.config file

I have a class called Constants.cs that contains app settings. I want to add an App.config file and put the settings from Constants.cs to App.config file in order to be able to run my application in different environments with same settings.
If my constants.cs class looks like this:
public class Constants
{
public static string LoginSubmitText => "Submit";
public static string LoginBackBtnText => "Back";
public static string SettingsPageTitleSize => "25";
}
Should then the App.config file look like this?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key ="LoginSubmitText" value="Submit"/>
<add key ="LoginBackBtnText " value="Back"/>
<add key ="SettingsPageTitleSize" value="25"/>
</appSettings>
</configuration>
And in that case, must I put this App.config file in all three environments, .Android, .IOS and UWP?
Thanks in advance!
You don't have to have App.config in all three platfroms. You can add this class to project with shared code.
I just finished working on similar issue. This is described here in this article. They don't use App.config file and if you insist on having App.config you can write your own implementation of parsing App.config to AppSettings object. I am talking about the method LoadAppSettings. The last part of this method converts json file appsettings.debug.json to AppSettings obejct.
In my case I needed to inject different connection strings regarding to build configuration in my azure pipelines. I use the powershell script to edit appsettings.[build configuration].json file and that solves my issue.

'The ADO.NET provider with invariant name 'Devart.Data.Oracle' is either not registered in the machine or application config file

Ok, there already is a similar issue. It is, however not exactly the same and the solution I got was not derived from the other issue's solution.
Here's my Web.Config setup:
<connectionStrings>
<add name="ADOEntities" connectionString="metadata=res://*/ADOModel.csdl|res://*/ADOModel.ssdl|res://*/ADOModel.msl;provider=Devart.Data.Oracle;provider connection string="User Id=dbUser;Password=*****;Server=oracleserver;Persist Security Info=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
Everything runs fine on my machine (sic), but when I tried to set the ws up on the quality server, I got the error on the title.
I got it working by following the steps in this ADO.NET link. Particularly,
You need to remove the defaultConnectionFactory registration and to add the Entity Framework provider registration by registering it in the entityFramework section
So the line defaultConnectionFactory must go
<entityFramework>
<providers>
<provider invariantName="Devart.Data.Oracle" type="Devart.Data.Oracle.Entity.OracleEntityProviderServices, Devart.Data.Oracle.Entity.EF6, Version=9.6.696.0, Culture=neutral, PublicKeyToken=09af7300eec23701" />
</providers>
</entityFramework>
Then, add the System.Data section. In my case it looks like this:
<system.data>
<DbProviderFactories>
<remove invariant="Devart.Data.Oracle" />
<add name="dotConnect for Oracle" invariant="Devart.Data.Oracle" description="Devart dotConnect for Oracle" type="Devart.Data.Oracle.OracleProviderFactory, Devart.Data.Oracle, Version=9.6.696.0, Culture=neutral, PublicKeyToken=09af7300eec23701" />
</DbProviderFactories>
</system.data>
If that still doesn't do the trick for you -- And it didn't for me -- try adding the following line to your context class:
[DbConfigurationType(typeof(Devart.Data.Oracle.Entity.OracleEntityProviderServicesConfiguration))] //Add this line
public partial class ADOEntities : DbContext
You might want to create a partial class, incase you're using ADO, Devart, or other auto-generated entity model, to avoid having this piece of code in an auto-generated class

What is in a mysql provider?

I have been toiling with an issue with mysql connector on and off for the past 3 months using a workaround. I even filed a bug report recently. However, I have found multiple instances of mysql connector failing in situations of advanced linq use. Some dating back to 2009 ( 3 years ) and still unresolved. In almost every instance, the user switched connectors.
I am considering doing the same. However, I came across looking at where mysql connector exists inside of my project. From what I can tell, it is only an included .dll (mysql.data and mysql.data.entity). After that, it is referenced only in web.config.
The first reference to the connector is in the connection string, providerName = "MySql.Data.MySqlClient".
The second reference is the definition of the provider
<system.data>
<DbProviderFactories>
<clear />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient"
description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, mysql.data, Version=6.5.4.0,
Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
The third is inside of the assemblies
<add assembly="mysql.data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
And the last is another assembly reference
<dependentAssembly>
<assemblyIdentity name="MySql.Data" publicKeyToken="c5687fc88969c44d" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.5.4.0" newVersion="6.5.4.0" />
</dependentAssembly>
Is this really the whole footprint of the connector?
Is this really the whole footprint of the connector?
Yes and no.
Yes
As far as the project which references the connector is concerned, this is the whole footprint. The only configuration that needs to be made is to have MySql.Data and MySql.Data.Entity added as references to the project. Usually these are inside of the packages folder, and are then copied into the bin folder once a reference has been added.
No
The connector has a lot of internal code going on. Because of where it is defined, the connector inherits from and extends on the DbProviderFactory. This extension involves many classes and sub classes which determine how the interaction to mysql is enacted. Because it is open source, the actual code can be downloaded from oracle.

CLR Can't find a type, even though it's in the same assembly

I'm troubleshooting a WCF problem in our application, and turned on WCF tracing with the WCF Service Configuration Editor in VS 2010, which added the following sharedListener to the web.config:
<sharedListeners>
<add initializeData="D:\Logs\CRCCustomerService\Web_tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
Now, when I take steps to reproduce my error, I'm getting an exception thrown from the System.Diagostics library saying that it can't find XmlWriterTraceListener:
Stack Trace:
System.TypeInitializationException: The type initializer for 'System.ServiceModel.DiagnosticUtility' threw an exception. ---> System.Configuration.ConfigurationErrorsException: Couldn't find type for class System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
at System.Diagnostics.TraceUtils.GetRuntimeObject(String className, Type baseType, String initializeData)
at System.Diagnostics.TypedElement.BaseGetRuntimeObject()
at System.Diagnostics.ListenerElement.GetRuntimeObject()
at System.Diagnostics.ListenerElement.GetRuntimeObject()
at System.Diagnostics.ListenerElementsCollection.GetRuntimeObject()
at System.Diagnostics.TraceSource.Initialize()
at System.Diagnostics.TraceSource.get_Listeners()
And it goes on for several more lines, but this establishes the context.
My question is, since, according to ObjectBrowser and Reflector, XmlWriterTraceListener is a member class of the same assembly that System.Diagnostics is, how can it NOT not be able to find it?
And secondly, since every single line in the exception stack comes from system code, how on earth do I begin to debug the root cause here?
Are you using .NET 4.0?
If not, you have to beware the service config utility. It will hard code the version of the listener to 4.0 and you'll need to manually change your web.config

Set connectionstring for Membership Service via code

I have an ASP.NET web project and a membership provider configured via my web.config. Its fully working so no problem there.
We have an older system with a lot of users and I would therefor like to create a class library that can create users in this ASP.NET project but since its a class library it cannot have its own app.config-file.
is it possible to set all this information via code somehow?
<membership defaultProvider="ShidMembershipProvider">
<providers>
<clear/>
<add name="ShidMembershipProvider" type="SundaHus.AspNet.Membership.ShidMembershipProvider" connectionStringName="ShidConnectionString" enablePasswordRetrieval="true" enablePasswordReset="true" requiersQuestionAndAnswer="true" applicationName="ECB3-development" minRequiredPasswordLength="5"/>
</providers>
</membership>
You have a custom membership provider it looks like? This connects to your own custom database? You should be able to just point to that database for your code. Or, if you just inherit the functionality from the base class, you can also try overriding the Initialize method, look for the connection string, and change the value to something else.

Resources