How to edit app.config at runtime for different role and membership providers - app-config

I am working on a vb.net development project in Visual Studio 2015 and need to be able to edit the app.config for the project at run time in order to access role and membership providers for different web sites. I would like to be able to change the ApplicationServices settings in the connectionStrings section and the applicationName settings in the membership and roleManager provider sections. I have edited the initial app.config file in the project's base directory to look like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<clear />
<add name="ApplicationServices" connectionString="Data Source=.\SQLEXPRESS; Integrated Security=True; User Instance=False; Connect Timeout=30; Initial Catalog=MYWEBSITE" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" applicationName="/" passwordFormat="Encrypted" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="true" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="8" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="5" />
</providers>
</membership>
<roleManager enabled="true">
<providers>
<clear />
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
</configuration>
At run time I am attempting to fetch the settings from the projects app.config file shown above using the following code:
Public Shared Function ReadAllConfigSettings(ByRef Configs(,) As String) As Boolean
ReadAllConfigSettings = False
Configs.Initialize()
Dim ConfigCounter As Integer = 0
Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
Try
Dim Settings = config.AppSettings.Settings
If Settings.Count = 0 Then
ReadAllConfigSettings = False
Exit Function
Else
For Each key As String In Settings.AllKeys
ConfigCounter = ConfigCounter + 1
Configs(ConfigCounter, 1) = key
Configs(ConfigCounter, 2) = Settings(key).Value
Next
ReadAllConfigSettings = True
End If
Catch e As ConfigurationErrorsException
ReadAllConfigSettings = False
End Try
End Function
When I run the code above the Settings collection retrieved from the Settings = config.AppSettings.Settings line of code is always empty with null entries and the Settings.Count is 0.
I am stumped as to why this is not getting the setting I have added to the app.config file, and I cannot continue to work on changing them if I can't even figure out how to retrieve them. Can someone point me in the right direction?
Thanks!
David

After re-thinking the process I came up with a solution that appears to be a way to do it without trying to edit the app.config file. Below is the code I scrambled together from fragment I found during my research into the problem:
Public Shared Function UpdateMembership(ConnectionStr As String, AppName As String, UserName As String, OldPassword As String, NewPassword As String, TheQuestion As String, TheAnswer As String, Optional TheError As String = Nothing) As Boolean
UpdateMembership = False
Dim IsMember As Boolean = False
Dim AUser As MembershipUser
Dim ChangePassOK As Boolean = False
Dim ChangeQAOK As Boolean = False
Try
Dim settings As Object = ConfigurationManager.ConnectionStrings("ApplicationServices")
Dim fi As Object = GetType(ConfigurationElement).GetField("_bReadOnly", (BindingFlags.Instance Or BindingFlags.NonPublic))
fi.SetValue(settings, False)
settings.ConnectionString = ConnectionStr
Membership.Providers.Item("AspNetSqlMembershipProvider").ApplicationName = AppName
Roles.Providers.Item("AspNetSqlRoleProvider").ApplicationName = AppName
Roles.Providers.Item("AspNetWindowsTokenRoleProvider").ApplicationName = AppName
IsMember = Membership.ValidateUser(UserName, OldPassword)
If IsMember Then
AUser = Membership.GetUser(UserName, False)
If Not IsNothing(AUser) Then
ChangePassOK = AUser.ChangePassword(OldPassword, NewPassword)
If ChangePassOK Then
ChangeQAOK = AUser.ChangePasswordQuestionAndAnswer(NewPassword, TheQuestion, TheAnswer)
End If
If ChangeQAOK Then
UpdateMembership = True
End If
End If
End If
Catch ex As Exception
If Not IsNothing(TheError) Then
TheError = ex.Message
End If
End Try
End Function
It works fine so it can be used to adjust the security settings for any user specific to each site's config.

Related

How to resolve key/value pair with external .config file

I am specifying <appSettings> in my app.config file, I am adding
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings configSource="ShareAppSettings.debug.config"/>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1"/>
</startup>
</configuration>
ShareAppSettigns.debug.config is my external config file, which I am using on my local machine and I do not want to share it with the rest of my team.
ShareAppSettings.debug.config looks like:
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<add key="clientID" value="11" />
<add key="clientSecret" value="11" />
<add key="tenantID" value="11" />
</appSettings>
Whenever I am trying to debug the main code:
private static List<string> AppCredentials()
{
string clientID = ConfigurationManager.AppSettings["clientID"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
string tenantID = ConfigurationManager.AppSettings["tenantID"];
List<string> appCred = new List<string> { clientID, clientSecret, tenantID };
if (clientID == null)
throw new Exception("ShareAppSettings.Debug.Config file was not provided in this repo.");
return (appCred);
}
For some reason I am not getting values for clientId, slientSecret nor tenantId. This code is a part of grasshopper Add-on for v6 template, and its running on .NET Framework 4.7.1. Whenever I copy the same code into a new C# console of a same framework, the code is built. I would truly appreciate if you could give me suggestions on how to solve this.
What "EnableWindowsFormsHighDpiAutoResizing" means and how can make this work?
Many Thanks
enter image description here
I suggest to use the file attribute (corresponding to the AppSettingsSection.File property) instead of the configSource attribute (corresponding to the SectionInformation.ConfigSource property) in the appSettings section.
configSource doesn't support other keys in the section, while appSettings may contain other keys, needed by the Application and possibly somewhere else (someone else may add/remove them - for testing purposes or any other reason).
The file attribute allows instead the presence of other key in the appSettings section.
Your app.config file can be:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings file="ShareAppSettings.debug.config">
<add key="DpiAwareness" value="PerMonitorV2"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1"/>
</startup>
</configuration>
Now the values are accessible by both opening a named configuration section:
appSettings.Settings[] returns a KeyValueConfigurationElement
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");
var kvpClientID = appSettings.Settings["clientID"];
var kvpClientSecret = appSettings.Settings["clientSecret"];
var kvpCenantID = appSettings.Settings["tenantID"];
string clientID = kvpClientID.Value;
and directly, using ConfigurationManager.AppSettings - a NameValueCollection - which returns the value of the specified key:
string clientID = ConfigurationManager.AppSettings["clientID"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
string tenantID = ConfigurationManager.AppSettings["tenantID"];
As a note, using the file attribute, your ShareAppSettings.debug.config doesn't need (but it's not forbidden) the XML header, it can be just:
<appSettings>
<add key="clientID" value="11" />
<add key="clientSecret" value="11" />
<add key="tenantID" value="11" />
</appSettings>
Secondary note:
you can set the file attribute to point to another file at run-time and refresh the appSettings values to updated the configuration.
Note that, if a file attribute was already set, all values contained in that .config file are not dismissed, but instead moved to the [Application].exe.config file, to become part of the <appSettings> section (thus, they are preserved).
Another reason why using the file attribute may be preferable.
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var appSettings = config.AppSettings;
appSettings.File = "SomeOtherFile.config";
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");

RIA Service Error in a Silverlight Application

In a very simple Silverlight Application I have a DomainService Class which has a single method that returns a list of Letter Objects.
The application works fine when I run it in VisualStudio. However, when I publish it to a folder on my Windows 10 local machine and run it using IIS (version 10.0.166299.5) I get the following error:
The remote server returned an error: NotFound.
at System.ServiceModel.DomainServices.Client.OperationBase.Complete(Exception error) at System.ServiceModel.DomainServices.Client.LoadOperation.Complete(Exception error) at System.ServiceModel.DomainServices.Client.DomainContext.CompleteLoad(IAsyncResult asyncResult) at System.ServiceModel.DomainServices.Client.DomainContext.<>c__DisplayClass1b.b__17(Object )
I supect this is due to something being wrong in missing in my WebConfig file. My WebConfig Currently looks like this:
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.6" />
<httpRuntime targetFramework="4.6" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="DomainServiceModule" preCondition="managedHandler" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</modules>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
The code for my Domain Service Class is like this:
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using SilverData.Web.Models;
namespace SilverData.Web.Services
{
[EnableClientAccess]
public class DrugsRiaService : DomainService
{
public IQueryable<Letter> GetAllLetters()
{
List<Letter> letters = new List<Letter>();
Letter letterA = new Letter { ID = 1, Statement = "Mike" };
Letter LetterB = new Letter { ID = 2, Statement = "Emma" };
Letter LetterC = new Letter { ID = 3, Statement = "Peter" };
letters.Add(letterA);
letters.Add(LetterB);
letters.Add(LetterC);
return letters.AsQueryable();
}
}
}
The error was due to the problem that .svc file wasn't being served.. The problem got solved with the kind help from the Kyle Abraham on Experts Exchange.
https://www.experts-exchange.com/questions/29084691/RIA-Service-Error-in-a-Silverlight-Application.html
The solution was to add the following line to the webserver section of the Webconfig
<handlers>
<add name=".svc" verb="*" path="*.svc" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</handlers>
I'm not sure, its a guess as I have not used RIA for awhile, but I think letters needs to returned as something other than queryable... try ToList() which causes the query to execute, and the payload is complete with the complete enumeration that was retrieved from the database. Remember, this is a remote call from a client, not a local one that can extend the queryable.

XML Connectionstrings

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="Citrus_Welding.My.MySettings.CitWeldConnectionString"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source="C:\Citrus Welding\CitWeld.mdb""
providerName="System.Data.OleDb" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
I am looking at the connection string, I need the Data Source to = a selected file from another page by default... I tried & pagename.openfiledialog.filename & but I keep getting an error. Any ideas?
It appears that you're saying that you want the user to be able to set the Data Source at run time. If so then omit it from the connection string in the config file and set it like this at run time:
Dim builder As New OleDbConnectionStringBuilder(My.Settings.CitWeldConnectionString)
builder.DataSource = newDataSourceValue
Dim connection As New OleDbConnection(builder.ConnectionString)

MVC 4 - after seeding database webpages_Roles is still empty

So I have basic MVC 4 Internet application project with Entity Framework 5.
I have configured WebSecurity that uses my table for users.
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "Id", "Email", autoCreateTables: true);
Then in my migration configuration class I seed DB with new roles and add users to them.
internal sealed class Configuration : DbMigrationsConfiguration<Infrastructure.KlepecV2Db>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(Infrastructure.KlepecV2Db context)
{
if(!Roles.RoleExists("Admin"))
{
Roles.CreateRole("Admin");
}
if (!Roles.RoleExists("Test1"))
{
Roles.CreateRole("Test1");
}
if(Membership.GetUser("user1") != null)
{
if(!Roles.IsUserInRole("user1","Admin"))
{
Roles.AddUserToRole("user1", "Admin");
}
}
if (Membership.GetUser("user2") != null)
{
if (!Roles.IsUserInRole("user2", "Admin"))
{
Roles.AddUserToRole("user2", "Admin");
}
}
}
}
So when I type "update-database" in NuGet console everything gets executed without errors. But if I look into webpages_Roles table its empty. Also webpages_UsersInRoles is empty.
For testing I have removed Role.RoleExists() calls and updating database fails, becouse roles already exists.
What am I missing here? Where are this roles stored?
I came across into an error The Role Manager feature has not been enabled mentioned by #Magnus. Hope this probably related to your roles issue in which the default role provider is unknown.
The error The Role Manager feature has not been enabled happened when I move the WebSecurity.InitializeDatabaseConnection method from MVC project into a class library (data access) for code first migration seed.
The point is App.config need to be configured for Package Manager Update-Database command to be run just like when Web.config exist.
Below is my App.config and Seed. Note that
I add "DefaultConnection" connection string *
Add system.web->roleManager to set the enable="true"
Add runtime->assemblyBinding->qualifyAssembly to give hint to compiler where is WebMatrix.WebData by giving the full assembly name.
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<!--<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Db;Persist Security Info=True;User=user;Password=pass" providerName="System.Data.SqlClient" />-->
</connectionStrings>
<system.web>
<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="WebMatrix.WebData" fullName="WebMatrix.WebData, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>
</configuration>
Seed Method:
protected override void Seed(DatabaseContext context)
{
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "Id", "Email", autoCreateTables: true);
if(!Roles.RoleExists("Admin"))
{
Roles.CreateRole("Admin");
}
if (!Roles.RoleExists("Test1"))
{
Roles.CreateRole("Test1");
}
if(Membership.GetUser("user1") != null)
{
if(!Roles.IsUserInRole("user1","Admin"))
{
Roles.AddUserToRole("user1", "Admin");
}
}
if (Membership.GetUser("user2") != null)
{
if (!Roles.IsUserInRole("user2", "Admin"))
{
Roles.AddUserToRole("user2", "Admin");
}
}
}
Hope this will help anyone with The Role Manager feature has not been enabled issue when using code first migration seed in a class library.
Update
* EF5 will read the connection string in Web.config of Mvc project but not in the App.config of the project with EF Migrations. However the membership and roleManager settings is still required in the EF Migration project.
Wanted to add my $0.02 to the conversation. I have a similar setup to CallMeLaNN, but was still getting the error. My solution was to set my "Data" project to a StartUp project. After that, my app.config file started getting picked up, and I can now seed my users from the Update-Database command.

How do I read a custom section in app.config from codebehind?

I have an app.config file that stores values in a few different sections. I have these snippets:
<configuration>
<configSections>
<sectionGroup name="someDataAccessLayer">
<section name="databaseConnectionStrings" type="sometype" />
</sectionGroup>
</configSections>
<someDataAccessLayer>
<databaseConnectionStrings>
<databaseConnectionString name="someSQL"
value="database=somedatabase;Integrated Security=False;User Id=sa;server=someserver;Password=somepassword/>
</databaseConnectionStrings>
</someDataAccessLayer>
How do I read the connection string in the codebehind? Specifically the value which is
database=somedatabase;Integrated Security=False;User Id=sa;server=someserver;Password=somepassword
Thanks for your help! Please let me know if the question is still unclear.
Your configuration section will be associated with some .NET class to handle it:
<configSections>
<sectionGroup name="someDataAccessLayer">
<section name="databaseConnectionStrings" type="sometype" />
</sectionGroup>
</configSections>
So to read the settings from the <localeSettings> section, you need to use the ConfigurationManager (add a reference to System.Configuration to your project) to get those settings into an instance of that class:
sometype cs = ConfigurationManager.GetSection("someDataAccessLayer/databaseConnectionStrings") as sometype;
Now you have an object of type sometype that contains all the settings in that config section. One of those properties will be a list of database connection strings, which you can now enumerate and find the appropriate one and read it's .Value property.
App.Config Settings:
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="MyApp.LocalConnectionString"
connectionString="Data Source= .\SQLEXPRESS;Initial Catalog=DBName;Integrated Security = true"
providerName="System.Data.SqlClient" />
Access at DataLayer using the ConfigurationManager as:
// add reference
using System.Configuration;
// then access connection string in your class
private static string strConnectionString = ConfigurationManager.ConnectionStrings["MyApp.LocalConnectionString"].ConnectionString;

Resources