I have a web deployment project that does a web.config section replacement using an external file. (this is to change the connection strings section).
The web.config section replacement works fine when built manually, but when built as part of a TFS build the section is not replaced. I cannot find any errors or warnings in the build log.
What are the likely causes, or how can I 'debug' this?
Have you considered using Web.Config's ability to pull a section from a separate file? You refer to the external file like so (this is my code for loading a file that has my connection strings section):
<connectionStrings configSource="WebCS.config"/>
Then the connection string can be deployed as a separate file:
<connectionStrings>
<add name="ConnString" connectionString="Data Source=<server>;Initial Catalog=<DB>;User ID=<ID>;Password=<pwd>" providerName="System.Data.SqlClient"/>
</connectionStrings>
That way, you don't have to worry about changing the web.config file at all.
I am not sure this will help at all....but this is a way to add/update a connection string without having to replace the whole config section.
public static void SaveConfigVal(string connectionString, string connName)
{
System.Configuration.ExeConfigurationFileMap fileMap = new System.Configuration.ExeConfigurationFileMap();
fileMap.ExeConfigFilename = GetConfigFileName();
//System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
// Retrieve the section group
ConnectionStringSettings keyValue = config.ConnectionStrings.ConnectionStrings[connName];
// If the key already exists, just replace
if (keyValue != null)
{
keyValue.ConnectionString = connectionString;
}
else
{
// Add a new key if the setting doesn't exist
config.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(connName, connectionString));
}
config.Save(ConfigurationSaveMode.Modified);// (ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("ConnectionStrings");
}
private static string GetConfigFileName()
{
//return config file name....
}
If you're using or can upgrade to Visual Studio 2010, you can utilize the new web.config transformations to alter the web.config based on selected configuration.
http://msdn.microsoft.com/en-us/library/dd465318.aspx
Related
I am creating Asp.net core application and trying to connect to the database. I am getting an error at the following line of code in ConfigureServices method in the startup.cs file. The error that I am getting is the value cannot be null. It seems like it cant find the CustomerOrderEntities key in the web.config file. Not sure what the problem is
services.AddDbContext<CustomerOrderEntities>(options =>
options.UseSqlServer(Configuration.GetConnectionString("CustomerOrderEntities")));
Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CustomerOrderEntities>(options =>
options.UseSqlServer(Configuration.GetConnectionString("CustomerOrderEntities")));
AutoMapperConfiguration.Configure();
// Create the container builder.
var builder = new ContainerBuilder();
// Register dependencies, populate the services from
// the collection, and build the container. If you want
// to dispose of the container at the end of the app,
// be sure to keep a reference to it as a property or field.
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>();
builder.RegisterType<DbFactory>().As<IDbFactory>();
builder.RegisterType<CustomerRepository>().As<ICustomerRepository>();
builder.RegisterType<ProductRepository>().As<IProductRepository>();
builder.RegisterType<OrderRepository>().As<IOrderRepository>();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
// Create the IServiceProvider based on the container.
return new AutofacServiceProvider(this.ApplicationContainer);
}
Web.Config
<connectionStrings>
<add name="CustomerOrderEntities" connectionString="metadata=res://*/EF.CustomerOrderContext.csdl|res://*/EF.CustomerOrderContext.ssdl|res://*/EF.CustomerOrderContext.msl;provider=System.Data.SqlClient;provider connection string="data source=test-PC\MSSQLSERVER2014;initial catalog=CodeFirstTest;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
Connection string in ASP.NET Core is defined in appsettings.json, for example:
"ConnectionStrings": {
"CustomerOrderEntities": "Server=(localdb)\\mssqllocaldb;Database=aspnet-a3e892a5-6a9c-4090-bc79-fe8c79e1eb26;Trusted_Connection=True;MultipleActiveResultSets=true"
},
In your case name of connecting string is CustomerOrderEntities, you get null, probably it's not there, check you appsettings.json.
Your connectionstring in Appsettings.json is definitely missing. You cannot set connection string in web.config in Asp.net core whether you are targeting full .net framework or .net core. Alternative you type the connection string value in services.AddDbContext(options =>
options.UseSqlServer("Your Connectionstring"));
for more information check here;
https://learn.microsoft.com/en-us/ef/core/
I'm using kpm pack to generate my deployment, which I deploy to Azure via ftp. I need to be able to serve static json files, so I need to add the following to my web.config:
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="text/html" />
</staticContent>
</system.webServer>
The problem is that kpm pack generates the web.config, so the only way to accomplish this is to add the config section to the web.config after it's been generated. Since I'm doing automated deployments via ci, this would require a bit of effort. Is there a better way to accomplish this?
You should add your configurations to the source of web.config, instead of the target.
If you don't have a web.config in root of the project being packed, please create one. Then add your static content configurations to [project_root]/web.config.
"kpm pack" will preserve all configurations in [project_root]/web.config, add some information needed by IIS, and then write it to wwwroot/web.config.
Important Update:
A change was introduced in "kpm pack": https://github.com/aspnet/KRuntime/pull/972
Please move your web.config from project root to the source of wwwroot.
The source of wwwroot folder can be specified with 'webroot' in project.json (https://github.com/aspnet/Home/wiki/Project.json-file#webroot).
You can also specify it with '--wwwroot' option of "kpm pack".
In ASP.NET Core you may be able to avoid web.config altogether by configuring the static file middleware options (StaticFileOptions) in code, providing a custom FileExtensionContentTypeProvider as its ContentTypeProvider:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddInstance<IContentTypeProvider>(
new FileExtensionConentTypeProvider(
new Dictionary<string, string>(
// Start with the base mappings
new FileExtensionContentTypeProvider().Mappings,
// Extend the base dictionary with your custom mappings
StringComparer.OrdinalIgnoreCase) {
{ ".json", "text/html" }
}
)
);
...
}
public void Configure(
IApplicationBuilder app,
IContentTypeProvider contentTypeProvider)
{
...
app.UseStaticFiles(new StaticFileOptions() {
ContentTypeProvider = contentTypeProvider
...
});
...
}
I have a .NET Web solution with an Azure Cloud Service project and a single webrole. I deploy it to the East coast West coast data/compute centers for failover purposes and have been asked to automate the deployment using Powershell MSBuild and Jenkins.
The problem is i need to change the Sql Azure database connectionString in the Web.config prior to packaging and publishing to each deployment. Seems simple enough.
I understand that the webrole properties Settings tab allows you to add custom configuration properties to each deployment with a type of either "string" or "Connection String" but it looks like the "Connection String" option applies to only Blob, Table or Queue storage. If I use the "String" and give it an Sql Azure connection string type it writes it out as an key/value pair and Entity Framework and the Membership Provider do not find it.
Is there a way to add a per-deployment connection string setting that points to Sql Azure?
Thanks,
David
Erick's solution is completely valid and I found an additional way to solve the problem so I thought I'd come back and put it up here since I had such trouble finding an answer.
The trick is getting the Entity Framework and any providers like asp.net Membership/profile/session etc... to read the connection string directly from the Azure service configuration rather than the sites web.config file.
For the providers I was able to create classes that inherit the System.Web.Providers.DefaultMembershipProvider class and override the Initialize() method where I then used a helper class I wrote to retrieve the connection string using the RoleEnvironment.GetConfigurationSettingValue(settingName); call, which reads from the Azure service config.
I then tell the Membership provider to use my class rather than the DefaultMembershipProvider. Here is the code:
Web.config:
<membership defaultProvider="AzureMembershipProvider">
<providers>
<add name="AzureMembershipProvider" type="clientspace.ServiceConfig.AzureMembershipProvider" connectionStringName="ClientspaceDbContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
Note the custom provider "AzuremembershipProvider"
AzuremembershipProvider class:
public class AzureMembershipProvider : System.Web.Providers.DefaultMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
string connectionStringName = config["connectionStringName"];
AzureProvidersHelper.UpdateConnectionString(connectionStringName, AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName),
AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName + "ProviderName"));
base.Initialize(name, config);
}
}
And here's the helper class AzureProvidersHelper.cs:
public static class AzureProvidersHelper
{
internal static string GetRoleEnvironmentSetting(string settingName)
{
try
{
return RoleEnvironment.GetConfigurationSettingValue(settingName);
}
catch
{
throw new ConfigurationErrorsException(String.Format("Unable to find setting in ServiceConfiguration.cscfg: {0}", settingName));
}
}
private static void SetConnectionStringsReadOnly(bool isReadOnly)
{
var fieldInfo = typeof (ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
if (
fieldInfo != null)
fieldInfo.SetValue(ConfigurationManager.ConnectionStrings, isReadOnly);
}
private static readonly object ConnectionStringLock = new object();
internal static void UpdateConnectionString(string name, string connectionString, string providerName)
{
SetConnectionStringsReadOnly(false);
lock (ConnectionStringLock)
{
ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["name"];
if (connectionStringSettings != null)
{
connectionStringSettings.ConnectionString = connectionString;
connectionStringSettings.ProviderName = providerName;
}
else
{
ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, connectionString, providerName));
}
}
SetConnectionStringsReadOnly(true);
}
}
The key here is that the RoleEnvironment.GetConfigurationSettingValue reads from the Azure service configuration and not the web.config.
For the Entity Framework that does not specify a provider I had to add this call to the Global.asax once again using the GetRoleEnvironmentSetting() method from the helper class:
var connString = AzureProvidersHelper.GetRoleEnvironmentSetting("ClientspaceDbContext");
Database.DefaultConnectionFactory = new SqlConnectionFactory(connString);
The nice thing about this solution is that you do not end up having to deal with the Azure role onstart event.
Enjoy
dnash
David,
A good option is to use the Azure configurations. If you right click on the Azure project, you can add an additional configuration. Put your connection string(s) in the correct configuration (e.g., ServiceConfiguration.WestCoast.cscfg, ServiceConfiguration.EastCoast.cscfg, etc).
In your build script, pass the TargetProfile property to MSBuild with the name of the configuration, and those settings will be built into the final cscfg.
Let me know if you run into any problems. I did the approach, and it took a few tries to get it working right. Some details that might help.
Erick
We are receiving this error when calling a WCF .net 4.0 service using entity framework.
The 'DbProviderFactories' section can only appear once per config file
It is the first app on the server using EF and other .net 4.0 WCF services are not receiving this error.
Is there any way to correct this error with out editing the machine config file on the server?
The installation for IBM DB2 .NET provider, causes an empty DbProviderFactories, see below. Just delete the second empty entry DbProviderFactories
<system.data>
<DbProviderFactories>
<add name="IBM DB2 for i .NET Provider" invariant="IBM.Data.DB2.iSeries" description=".NET Framework Data Provider for IBM i" type="IBM.Data.DB2.iSeries.iDB2Factory, IBM.Data.DB2.iSeries, Version=12.0.0.0, Culture=neutral, PublicKeyToken=9cdb2ebfb1f93a26" />
</DbProviderFactories>
<DbProviderFactories />
</system.data>
Maybe you could create web.config entries which override any machine-wide settings you want changed.
Described here:
Override machine.config by web.config
Putting the <clear /> instruction inside of the DbProviderFactories tags in the web config to clear out and then override the duplicate entries made in the machine config. Thus doing a hack-work around of the error in the machine.config.
You have to update Machine.config file located in the below paths.
C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\Machine.Config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Machine.Config
For 64-bit machines, Machine.config will be located in ...\Framework64\...
The block to pay attention to is this:
<system.data>
<DbProviderFactories>
<add name="IBM DB2 for i5/OS .NET Provider" invariant="IBM.Data.DB2.iSeries" description=".NET Framework Data Provider for i5/OS" type="IBM.Data.DB2.iSeries.iDB2Factory, IBM.Data.DB2.iSeries, Version=12.0.0.0, Culture=neutral, PublicKeyToken=9cdb2ebfb1f93a26"/>
<add name="Microsoft SQL Server Compact Data Provider" invariant="System.Data.SqlServerCe.3.5" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=3.5.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"/>
</DbProviderFactories>
<!-- This is the line to remove - empty element --><DbProviderFactories/>
</system.data>
As #yonsk already mentioned why this problem occurs (duplicate entry of ), you can create a console application which can fix the machine.config file and then, invoke that console application from your Application's Installer or from your Application whenever you get the Exception. The following code can be used for the console application that will fix the machine.config file.
class Program
{
static void Main()
{
string machineConfigFilePath = RuntimeEnvironment.SystemConfigurationFile;
XDocument xdoc = XDocument.Load(machineConfigFilePath);
XElement[] elements = xdoc.XPathSelectElements("//configuration/system.data/DbProviderFactories").ToArray();
if (elements.Any())
{
foreach (XElement anElement in elements)
{
if (!anElement.HasElements)
anElement.Remove();
}
}
xdoc.Save(machineConfigFilePath);
}
}
If you want to call the console application, from your Application, you would need to invoke that as Administrator. So, the following snippet may help to invoke that console application as Administrator (The user will be prompted with a dialog to accept..)
try
{
Process process = Process.Start(new ProcessStartInfo
{
Verb = "runas",
FileName = "/Path/to/the/console/application",
UseShellExecute = true,
CreateNoWindow = true,
});
process.WaitForExit();
int exitCode = process.ExitCode;
}
catch (Exception ex)
{
}
While calling webservice during uninstallation of windows application I am getting error as
Could not find endpoint element that references contract
ServiceReference2.IService1' in the ServiceModel client configuration
section. This might be because no configuration file was found for
your application, or because no endpoint element matching this name
could be found in the client element.
I am using Installer class in which I am calling webservice client. Following is code of installer.cs
Source code :
namespace webMiner
{
[RunInstaller(true)]
public partial class demoInstaller : Installer
{
SqlConnection conn = new SqlConnection("Data Source=servername;Initial Catalog=comp;User Id=abc;Password=******;");
public demoInstaller():base()
{
InitializeComponent();
AfterUninstall += new InstallEventHandler(AfterUninstallEventHandler);
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
Int32 flag = -1;
string keyName = "";
RegistryKey regeditkey = Registry.CurrentUser.OpenSubKey("sevenuser", RegistryKeyPermissionCheck.ReadWriteSubTree);
keyName = regeditkey.GetValue("currentuser").ToString();
webMiner.ServiceReference2.Service1Client sc = new webMiner.ServiceReference2.Service1Client();
flag = sc.unInstallOperation(keyName);
}
}
}
Where unInstallOperation() will call webservice operation which contains updation of account.
How to solve this issue?
Really feedup with this issue
I have no problem when i call serviceclient from another page or from another class file it give me problem when I am calling during uninstallation of application i.e in Installer class. This is app.config client configuration code that i have used
source code:
<client>
<endpoint address="http://companyfind.info/RegWcfService/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
contract="IService1" name="BasicHttpBinding_IService1" />
</client>
Is there any need to add this in web.config file of web service??
You probably need to use the name of your endpoint when you are instatiating Service1Client
var sc = new webMiner.ServiceReference2.Service1Client("BasicHttpBinding_IService1");
Or, as it was in my case, you have your another class in another project in solution and two app.config classes. So, you need to copy/paste the desription af enpoints and bindings in main app.config.
Try to update the service reference, and check if client configuration is in the startup project config file.