Let us say i am creating an app called ConsoleApp2.
Because of some third party libraries i am using, my default app.config file is generating code like
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
That is because my solution references different versions of one library, so it needs to tell everyone: "Hey, if you look for any oldVersion of this library, just use newVersion". And that is all right.
The problem is that i want to define a separate config file "test.exe.config" where i have some settings and get rid of the automatically generated one.
In order to tell my App about the new config file i am using code like
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");
And that works (almost) perfectly. And i wrote there "almost" since although the <appSettings> section is being read correctly, the <runtime> section is not being looked at in my custom config file, but the App looks for it in the default config file instead, which is a problem since i want to be able to delete that one later.
So, how can i tell my Application to read also the <runtime> information from my custom config file?
How to reproduce the issue
A simple sample to reproduce my issue is as follows:
Create a library called ClassLibrary2 (.Net Framework v4.6) with a single class as follows
using Newtonsoft.Json.Linq;
using System;
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
var json = new JObject();
json.Add("Succeed?", true);
Reash = json.ToString();
}
public String Reash { get; set; }
}
}
Note the reference to Newtonsoft package. The one installed in the library is v10.0.2.
Now create a Console Application called ConsoleApp2 (.Net Framework v4.6) with a class called Program which content is simply as follows:
using System;
using System.Configuration;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "test.exe.config");
var AppSettings = ConfigurationManager.AppSettings;
Console.WriteLine($"{AppSettings.Count} settings found");
Console.WriteLine($"Calling ClassLibrary2: {Environment.NewLine}{new ClassLibrary2.Class1().Reash}");
Console.ReadLine();
}
}
}
This Application should have installed also Newtonsoft, but in a different version v12.0.3.
Build the Application in Debug mode. Then, in the folder ConsoleApp2/ConsoleApp2/bin/Debug create a file called test.exe.config with following content
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<appSettings>
<add key="A" value="1"/>
<add key="B" value="1"/>
<add key="C" value="1"/>
</appSettings>
</configuration>
and note that in that same Debug folder there is also the default config file ConsoleApp2.exe.config with a content like
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
If a this point you run the application it will compile with no problems and you should see a Console like
Note that the (3) settings were read from my custom config file correctly. So far so good...
Now rename the default config file to something like _ConsoleApp2.exe.config and run again the application. You should now get a FileLoadException.
So again, how can i tell my Application to read the <runtime> information from my custom config file?
Rationale
The reason i am looking an answer to this question is as follows:
When we release our application, we put all the .exe and .dll files in one folder and our custom config file (with settings, etc) in another, where our clients have similar files.
In the folder with the .exe and .dll files we try to keep as little as possible so i was asked to find a way to get rid of that ConsoleApp2.exe.config if possible. Now, since the aforementioned bindings were written in that config file, i just tried moving that information to our custom config file... but so far i have failed to achieve: the binding redirects are always tried to be read from that ConsoleApp2.exe.config, so as soon as i remove it i get exceptions...
You're probably looking for config transforms:
The idea behind is that you create multiple configurations in Visual Studio like Debug, Release, Production, Test ... in the configuration manager and a default configuration file plus so-called transforms.
Note that you can create as many configuation as you like in the configuration manager. To add new ones, click on Solution Configurations (the dropdown showing "Debug" or "Release"), and select "Configuration Manager...". Open it, and you see a list of all currently existing configurations. Drop down the combobox "Active Solution configuration" and select "<New...>" to add more.
Those transforms specify what makes the specific configuration different from the default one - so you don't need to repeat what you have already specified in the default configuration, instead you just mention the differences, for example:
<configuration>
<appSettings>
<add key="ClientSessionTimeout" value="100"
xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
which finds the relevant setting by its key ClientSessionTimeoutand sets its value to 100 by replacing the original value in the config file (this is what the additional transform attributes xdt:Transform="SetAttributes" xdt:Locator="Match(key)" mean). You can also specify to remove existing settings (by specifying xdt:Transform="Remove" instead), e.g.
<add key="UserIdForDebugging" xdt:Transform="Remove" xdt:Locator="Match(key)"/>
would remove a user Id that should be there only for debugging, not for the release (To find out more about available options, please look here - described for Web.config, but also applicable for App.config).
In addition to the App.Config file you have one file per configuration, i.e. App.Debug.Config for Debug, App.Release.Config for Release etc. Visual Studio helps you creating them.
I have already created answers in StackOverflow here and there, which describes it in detail, please have a look.
If you're having issues displaying them in Visual Studio, take a look here.
Regarding your Rationale:
Transforms are creating a full configuration file by applying the transform file onto the default configuration file. The resulting file is compiled and put into the "bin" folder - together with the other compiled files. So, if you have a configuration "Release" selected, then all the files including the transformed config file are compiled into "bin\Release".
And the configuration file is named just as the exe file plus ".config" appended at the end (in other words, there is no ".Release.config" in the binary folder, but a "MySuperCoolApp.exe.config" created - for the application "MySuperCoolApp.exe").
Likewise, the same is true for the other configuration - each configuration creates a subfolder inside of "bin" - if you're using scripts, that subfolder can be referenced as $(TargetDir) in a post-build event.
Config transformation
Given the issue occur when you try to use another (non-native) config file you are trying to find a solution to 'properly' substitute it. In my answer I want to step back a little and focus on the reason why do you want to substitute it. Based on what you described in the question, you have it to define custom application settings. If I understood correctly, you plan to link it to the target project, set 'Copy to output' property to 'Always' and you'll get it near the application.
Instead of copying the new config file, there is a way to transform existing (native) one, in your case - ConsoleApp2.exe.config using Xdt transformations. To achieve that, you create transformation file and declare there only the sections which you want to transform, for example:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings xdt:Transform="Replace">
<add key="A" value="1"/>
<add key="B" value="1"/>
<add key="C" value="1"/>
</appSettings>
</configuration>
Benefits of such approach are:
flexibility: transforms are very
flexible, you may replace sections, merge them, set/remove attributes, etc. You may have environment specific (DEV/UAT/PROD) or build specific(Debug/Release) transforms.
reusability: define transform once and reuse it in all projects you need.
granularity: you declare only what you need, no need to copy-paste whole config.
safety: you let nuget and msbuild manage 'native' config file (add binding redirects, etc)
The only disadvantage of this approach is learning curve: you need to learn syntax and know how to glue transforms to your configs in MSBuild.
.NET Core has support of transform, here is an example how to create transforms for web.config, but you can apply transforms to any configs.
If you develop .NET applications (not .NET Core) then I'd recommend to look at Slowcheetah.
There are a lot of resources and useful blogbosts about transformation, it is rather widely used. Please contact me if you'll have difficulties.
From my point of view config transforms is a right solution to achieve your goal so I'd strongly recommend to consider it instead of tweaking runtime.
Externalize config sections
If you still want to keep appSettings in common location, then you can externalize config sections with ConfigSource attribute. Check this and this thread for details:
// ConsoleApp2.exe.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings configSource="../commonConfig/connections.config"/>
</configuration>
// connections.config:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
<add name="MovieDBContext"
connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\Movies.mdf"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
AppSettings section contains File attribute that allows you to merge parameters from another file.
This option allows you to replace certain sections of the configuration, but not whole content itself. So if you need only appSettings, it is totally applicable - you just put config file with appSettings to common location shared with user and patch config file (add file or configSource attribute) to source this section from that location. If you need more sections, you'll need to extract them as separate files.
To work properly with different .config file, you may keep the default one to manage biding redirects and an other one for your application parameters. To do so Change default app.config at runtime looks great.
You also can shut down the automatic binding redirect generation and use only a hand crafted app.config file. There is an example here : Need a way to reference 2 different versions of the same 3rd party DLL
Edit
Taking account of the rationale:
If I understand it, you don't want the app.exe.config file at all.
You already manage to put and read custom contant somewhere else.
Only remains the binding redirect.
You can get rid of it by managing the binding redirect at runtime like it's done here: https://stackoverflow.com/a/32698357/361177
You may also recreate a configurable binding resolver by made your code look at the config file.
My two cents here: it's feasible but I don't think it worth it.
Edit 2
This solution looks promising https://stackoverflow.com/a/28500477/361177
I am new in c# programming. Recently i developed a desktop app and create exe file for this. But it is not run in another pc. Here my app.config file-
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="newConnectionString"
connectionString="Data Source=.\SqlExpress;AttachDbFilename=|DataDirectory|Asset_Management_System.mdf; Integrated Security=True;User Instance =True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
Please help me.
Build the project in a release state (Build>Configuration Manager> Active Solution configuration). It is going to create a Release Folder inside the "BIN" folder, which would contain all the files need to execute the program. If you make reference to others files, they should be contained there too, so put them on that folder. This folder can be carried to others PC running windows with ".NET Framework" installed and the application should run fine. Also, you can create an installer by deployment technologies like Click Once, that would do stuff like Install all the dependencies automatically (.Net Framework, visual C++ etc.) and special configuration or settings.
OVERVIEW
Using Fitnesse with EF6, can't get Effort to start up.
I've tried every trick in all the posts I can find.
All the posts say to either call 'RegisterProvider', or add a config section. Neither is working.
So far:
I have "Effort.Provider" in the DbProviderFactories section in machine.config.
I have Effort.Provider showing up when I look at DbProviderFactories.GetFactoryClasses();
ProcMon shows that it is looking for and finding Effort.dll.
Result:
Any of
DbConnectionFactory.CreateTransient();
Effort.EntityConnectionFactory.CreateTransient(connectionString);
DbProviderFactory dataFactory = DbProviderFactories.GetFactory(dt.Rows[5]);
throw
Effort.Exceptions.EffortException: The Effort library failed to register
Also tried:
"Effort.Provider" in the entityFramework section of Runner.exe.config but couldn't get that to work. Just crashed the app.
Uninstalling EF and Effort.EF6 and re-installing. No visible effect.
Calling Effort.Provider.EffortProviderConfiguration.RegisterProvider(); from a class constructor and various startup locations. Effort.Provider never showed up in DbProviderFactories.GetFactoryClasses();
With "Effort.Provider" in the DbProviderFactories section in app.config, it shows up in GetFactoryClasses just as well as machine.config.
Using:
Windows 10
.Net 4.6
VS 2016
EF 6.1.2 (although it says 6.1.3 is installed, not sure what that means)
Do I need to register a DLL or something? Nothing in the instructions about that.
More Details:
App.config
<configuration>
<runtime>
<loadFromRemoteSources enabled="true"/>
</runtime>
<system.data>
<DbProviderFactories>
<add name="Effort.Provider" invariant="Effort.Provider" description="Effort.Provider" type="Effort.Provider.EffortProviderFactory, Effort" />
</DbProviderFactories>
</system.data>
</configuration>
It looks like you need to register the "entityFramework" config section in the app.config file.
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<entityFramework>
<providers>
<provider invariantName="Effort.Provider" type="Effort.Provider.EffortProviderServices,Effort" />
</providers>
</entityFramework>
Then in your code create the Effort connection and pass it to your DbContext. If you don't already have a constructor that takes an object of type System.Data.Common.DbConnection, create one.
System.Data.Common.DbConnection connection = DbConnectionFactory.CreateTransient();
var context = new MyContext(connection);
I would also recommend setting a connectionString in your app.config. I believe the call to CreateTransient creates a connection for you, but if your code under test has code that creates another dbContext somewhere, Effort will look to the app.config to get that information. Below is an example that will create a transient database so that all operations completed in one test do not affect another test.
<add name="DefaultConnection" connectionString="Data Source=in-process;IsTransient=true" providerName="Effort.Provider" />
this is my app.config file. I am using vs 2012 with c#.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="Small_Business_Management.Properties.Settings.businessdataConnectionString1"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\businessdata.mdf;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
now i included the database file businessdat.mdf in the solution.Now when i publish the application it is not working in other computers.It works fine in mine. In other computers it asks me to install sql server.How can i publish with a local database so that it works without installing sql server in other computers
If you want to use the LocalDB functionality of SQL Server 2012 you need to install the LocalDB functionality on each device you deploy to. You can find the installer here.
It is possible to do a silent install, so you can include it in your application installer if you have one:
msiexec /i SqlLocalDB2012.msi /qn IACCEPTSQLLOCALDBLICENSETERMS=YES
more information here and here
If you really do not want to (or can not) install anything on the devices you deploy to, you can always check out sqlite
You basically have two choices:
Install LocalDB on the other computers - you may be able to integrate this into your installation/deployment process for the app.
Use an embedded database
To expand the above a bit, to avoid an installation you'll have to use an embedded database so that the necessary libraries are deployed with your application. In context the obvious choice would be SQL Server Compact which should work with the code and SQL you already have i.e. there's a reasonable chance you'll only need to add the files/references and change the connection string.
My Program uses EF to access data from a SQL CE database. When debug the application using debug setup it works fine but if I use release setup I get a MetadataException when the program tries to access the database through EF.
What I've checked so far:
Debug and release configuration is identical (same target platform)
The app.config is copied to the same directory as the executable (\Release)
The sdf database file is copied to \Release\
Metadata Artifact Processing is set to Embed in Output Assembly
Connection string name is identical in app.config and EF model
My app.config:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="GeoDataEntities" connectionString="metadata=res://*/Model.EF.Model.csdl|res://*/Model.EF.Model.ssdl|res://*/Model.EF.Model.msl;provider=System.Data.SqlServerCe.3.5;provider connection string="Data Source=|DataDirectory|\GeoData.sdf"" providerName="System.Data.EntityClient" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>
The assembly Model.EF is the namespace and Model the name of the edmx, I think that should be right.
I know that there a lot of posts and blogs about MetadataException and I've tried to solve this but nothing have worked so far.
Best regards
Jay
I really don't know what I've done but it's working since I've checked in and checked out from TFS.