I want to change a value is my app.config dynamically from my project.
This is my app.config:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.web>
<membership defaultProvider="SqlProvider">
<providers>
<clear />
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MySqlConnection"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false"
applicationName="app1" requiresUniqueEmail="false"
passwordFormat="Hashed" maxInvalidPasswordAttempts="6545"
minRequiredPasswordLength="4" minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>
</providers>
</membership>
</system.web>
</configuration>
I want to change the value of 'applicationName' key inside the 'sqlProvider'.
All i could find on the net is people using:
ConfigurationManager.AppSettings["key"]
But this doesnt work for me.
ConfigurationManager.AppSettings["key"] usually works with the setting defined under "AppSettings" section. you may try out the following code-
public class MembershipSetting
{
/// <summary>
/// Gets or sets the name of the setting.
/// </summary>
public string SettingName { get; set; }
/// <summary>
/// Gets or sets the setting value.
/// </summary>
public string SettingValue { get; set; }
}
private List<MembershipSetting> GetMembershipSetting()
{
List<MembershipSetting> settings = new List<MembershipSetting>
{
new MembershipSetting {SettingName = "Dafult Membership Provider", SettingValue = Membership.Provider.ToString() },
new MembershipSetting {SettingName = "Minimum Required Password Length", SettingValue = Membership.MinRequiredPasswordLength.ToString(CultureInfo.InvariantCulture) },
new MembershipSetting {SettingName = "Minimum Required Non Alphanumeric Characters",SettingValue = Membership.MinRequiredNonAlphanumericCharacters.ToString(CultureInfo.InvariantCulture)},
new MembershipSetting {SettingName = "Password reset enabled", SettingValue = Membership.EnablePasswordReset.ToString()},
new MembershipSetting {SettingName = "Maximum Invalid Password Attempts",SettingValue = Membership.MaxInvalidPasswordAttempts.ToString(CultureInfo.InvariantCulture) },
new MembershipSetting {SettingName = "Attempt windows",SettingValue = Membership.PasswordAttemptWindow.ToString(CultureInfo.InvariantCulture)},
new MembershipSetting {SettingName = "applicationName",SettingValue = Membership.ApplicationName.ToString(CultureInfo.InvariantCulture)}
};
return settings;
}
This article is originally posted here.
Related
Hi i'll try to do the TournamentTracker and it works fine until when im stocked with the mailing lesson.
Got problems in app.config when i add the lines: <system.net> and <mailsettings>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="filePath" value="C:\Users\gertl\Source\Repos\TournamentTracker\TextData"/>
<add key="greaterWins" value="1"/>
<add key="senderEmail" value="me#outlook.com "/>
<add key="senderDisplayName" value="TournamentTracker "/>
</appSettings>
<connectionStrings>
<add name="Tournaments" connectionString="Server=xxx;Database=Tournaments;Trusted_Connection=True;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network host="127.0.0.1" userName="Tim" password="testing" port="25" enableSsl="false"/>
</smtp>
</mailSettings>
</system.net>
<!--<startup>
<supportedRuntime version="v4.0" sku=".NETFrameWork,Version=v4.5.2"/>
</startup>-->
</configuration>
When i comment away the system.net section the connectionString works again.
See if the following helps.
Reads email settings
Reads connection string
Reads one AppSetting value
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="mailSettings">
<section name="smtp_1" type="System.Net.Configuration.SmtpSection"/>
<section name="smtp_2" type="System.Net.Configuration.SmtpSection"/>
</sectionGroup>
</configSections>
<appSettings>
<add key="filePath" value="C:\Users\gertl\Source\Repos\TournamentTracker\TextData"/>
<add key="greaterWins" value="1"/>
<add key="senderEmail" value="me#outlook.com "/>
<add key="senderDisplayName" value="TournamentTracker "/>
</appSettings>
<connectionStrings>
<add name="Tournaments" connectionString="Server=xxx;Database=Tournaments;Trusted_Connection=True;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<mailSettings>
<smtp_1 from="someone#gmail.com">
<network
host="smtp.gmail.com"
port="587"
enableSsl="true"
userName="MssGMail"
password="!#45cow"
defaultCredentials="false" />
<specifiedPickupDirectory pickupDirectoryLocation="MailDrop"/>
</smtp_1>
<smtp_2 from="karenpayneoregon#gmail.com">
<network
host="smtp.gmail.com"
port="587"
enableSsl="true"
userName="oregon#gmail.com"
password="password"
defaultCredentials="false" />
<specifiedPickupDirectory pickupDirectoryLocation="MailDrop"/>
</smtp_2>
</mailSettings>
<system.net>
<mailSettings>
<smtp from="Someone#comcast.net">
<network
host="smtp.comcast.net"
port="587"
enableSsl="true"
userName="MissComcast"
password="d#45cat"
defaultCredentials="true" />
<specifiedPickupDirectory pickupDirectoryLocation="MailDrop"/>
</smtp>
</mailSettings>
</system.net>
</configuration>
Class for getting email settings
using System;
using System.Configuration;
using System.IO;
using System.Net.Configuration;
namespace SmtpConfigurationExample.Classes
{
public class MailConfiguration
{
private readonly SmtpSection _smtpSection;
public MailConfiguration(string section = "system.net/mailSettings/smtp")
{
_smtpSection = (ConfigurationManager.GetSection(section) as SmtpSection);
}
public string FromAddress => _smtpSection.From;
public string UserName => _smtpSection.Network.UserName;
public string Password => _smtpSection.Network.Password;
public bool DefaultCredentials => _smtpSection.Network.DefaultCredentials;
public bool EnableSsl => _smtpSection.Network.EnableSsl;
public string PickupFolder
{
get
{
var mailDrop = _smtpSection.SpecifiedPickupDirectory.PickupDirectoryLocation;
if (mailDrop != null)
{
mailDrop = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
_smtpSection.SpecifiedPickupDirectory.PickupDirectoryLocation);
}
return mailDrop;
}
}
/// <summary>
/// Determine if pickup folder exists
/// </summary>
/// <returns></returns>
public bool PickupFolderExists() => Directory.Exists(PickupFolder);
/// <summary>
/// Gets the name or IP address of the host used for SMTP transactions.
/// </summary>
public string Host => _smtpSection.Network.Host;
/// <summary>
/// Gets the port used for SMTP transactions
/// </summary>
public int Port => _smtpSection.Network.Port;
/// <summary>
/// Gets a value that specifies the amount of time after
/// which a synchronous Send call times out.
/// </summary>
public int TimeOut => 2000;
public override string ToString() => $"From: [ {FromAddress} ]" +
$"Host: [{Host}] Port: [{Port}] " +
$"Pickup: {Directory.Exists(PickupFolder)}";
}
}
Form code
using System;
using System.Text;
using System.Windows.Forms;
using SmtpConfigurationExample.Classes;
using static System.Configuration.ConfigurationManager;
namespace SmtpConfigurationExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void GetEmailSettingsButton_Click(object sender, EventArgs e)
{
var mc = new MailConfiguration();
var builder = new StringBuilder();
builder.AppendLine($"User name: {mc.UserName}");
builder.AppendLine($"From: {mc.FromAddress}");
builder.AppendLine($"Host: {mc.Host}");
builder.AppendLine($"Port: {mc.Port}");
ResultsTextBox.Text = builder.ToString();
}
private void GetConnectionButton_Click(object sender, EventArgs e)
{
ResultsTextBox.Text = ConnectionStrings["Tournaments"].ConnectionString;
}
private void FilePathButton_Click(object sender, EventArgs e)
{
ResultsTextBox.Text = AppSettings["filePath"];
}
}
}
This is what I did to resolve the exact same issue when building the Tournament Tracker.
I commented out or removed the <system.net>, from the
appconfig file: [app.config file][1] [1]:
https://i.stack.imgur.com/8pMoW.png
I installed Fluentemail SMTP NuGet Package: [Fluentemail SMTP
NuGet][2] [2]: https://i.stack.imgur.com/nsttr.png
Email Logic.cs
namespace TrackerLibrary {
public class EmailLogic
{
public static void SendEmail(string sender, string recpient, string to, string subject, string body)
{
var client = new SmtpSender(() => new SmtpClient(host: "localhost")
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25
});
Email.DefaultSender = client;
var mail = Email
.From(emailAddress: sender)
.To(emailAddress: to, name: recpient)
.Subject(subject)
.Body(body)
.Send();
}
}
TournamentLogic.cs
public static void AlertPlayerToNewRound(PlayersModel p, string teamName, MatchupEntryModel competitor)
{
if (p.EmailAddress.Length == 0)
{
return;
}
string sender = "";
string to = "";
string recpient = "";
string subject = "";
StringBuilder body = new StringBuilder();
if (competitor != null)
{
subject = $"You have a new matchup with { competitor.TeamCompeting.TeamName } !";
body.Append("Hello ");
body.Append(p.FirstName);
body.AppendLine(", ");
body.AppendLine();
body.AppendLine("You have a new matchup !");
body.Append("Competitor: ");
body.Append(competitor.TeamCompeting.TeamName);
body.AppendLine();
body.AppendLine();
body.AppendLine("Have a great tournament !");
body.AppendLine("~Tournament Tracker");
}
else
{
subject = "You have a bye this round !";
body.Append("Hello ");
body.Append(p.FirstName);
body.AppendLine(", ");
body.AppendLine();
body.AppendLine("Enjoy your bye round. ");
body.AppendLine("~Tournament Tracker");
}
sender = GlobalConfig.AppKeyLookup("senderEmail");
recpient = p.FullName;
to = p.EmailAddress;
EmailLogic.SendEmail(sender, recpient, to, subject, body.ToString());
After these changes, I was able to successfully send email and receive in Papercut SMTP. I hope this helps.
How would I delete / clear / wipe / overwrite a log file being written through EL6 logging. I am using a logwriter instance to write to a log file that needs to be overwritten every cycle as my program runs in a continuous loop. I will be writing values then overwriting as new values come through.
There may be other/better ways to attack this, but I was able to clear the log file by temporarily repointing the static LogWriter to a temp file, clearing the log with simple File I/O, and then reconnecting the original LogWriter.
I wrote up a simple C# Console App to demonstrate. There are some hard-coded references to the log file configuration in App.config that could probably be cleaned up by using the ConfigurationSourceBuilder, but hopefully this can get you started.
Programs.cs:
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System;
using System.Diagnostics;
using System.IO;
namespace LogFileClearance
{
public static class Marker
{
public static LogWriter customLogWriter { get; set; }
}
class Program
{
private static object _syncEventId = new object();
private static object locker = new object();
private static int _eventId = 0;
private const string INFO_CATEGORY = "All Events";
static void Main( string [] args )
{
InitializeLogger();
Console.WriteLine( "Enter some input, <Enter> or q to quit, c to clear the log file" );
string input = Console.ReadLine().ToUpper();
while ( ! string.IsNullOrEmpty(input) && input != "Q" )
{
Console.WriteLine( "You entered {0}", input );
if ( input == "C" )
{
ClearLog();
}
else
{
WriteLog( input );
}
Console.WriteLine( "Enter some input, <Enter> or q to quit, c to clear the log file" );
input = Console.ReadLine().ToUpper();
}
}
private static int GetNextEventId()
{
lock ( _syncEventId )
{
return _eventId++;
}
}
public static void InitializeLogger()
{
try
{
lock ( locker )
{
if ( Marker.customLogWriter == null )
{
var writer = new LogWriterFactory().Create();
Logger.SetLogWriter( writer, false );
}
else
{
Logger.SetLogWriter( Marker.customLogWriter, false );
}
}
}
catch ( Exception ex )
{
Debug.WriteLine( "An error occurred in InitializeLogger: " + ex.Message );
}
}
static internal void WriteLog( string message )
{
LogEntry logEntry = new LogEntry();
logEntry.EventId = GetNextEventId();
logEntry.Severity = TraceEventType.Information;
logEntry.Priority = 2;
logEntry.Message = message;
logEntry.Categories.Add( INFO_CATEGORY );
// Always attach the version and username to the log message.
// The writeLog stored procedure will parse these fields.
Logger.Write( logEntry );
}
static internal void ClearLog()
{
string originalFileName = string.Format(#"C:\Logs\LogFileClearance.log");
string tempFileName = originalFileName.Replace( ".log", "(TEMP).log" );
var textFormatter = new FormatterBuilder()
.TextFormatterNamed( "Custom Timestamped Text Formatter" )
.UsingTemplate("{timestamp(local:MM/dd/yy hh:mm:ss.fff tt)} tid={win32ThreadId}: {message}");
#region Set the Logging LogWriter to use the temp file
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.LogToCategoryNamed( INFO_CATEGORY ).WithOptions.SetAsDefaultCategory()
.SendTo.FlatFile( "Flat File Trace Listener" )
.ToFile(tempFileName);
using ( DictionaryConfigurationSource configSource = new DictionaryConfigurationSource() )
{
builder.UpdateConfigurationWithReplace(configSource);
Marker.customLogWriter = new LogWriterFactory(configSource).Create();
}
InitializeLogger();
#endregion
#region Clear the original log file
if ( File.Exists(originalFileName) )
{
File.WriteAllText(originalFileName, string.Empty);
}
#endregion
#region Re-connect the original file to the log writer
builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions.DoNotRevertImpersonation()
.LogToCategoryNamed( INFO_CATEGORY ).WithOptions.SetAsDefaultCategory()
.SendTo.RollingFile("Rolling Flat File Trace Listener")
.RollAfterSize(1000)
.FormatWith(textFormatter).WithHeader("").WithFooter("")
.ToFile(originalFileName);
using ( DictionaryConfigurationSource configSource = new DictionaryConfigurationSource() )
{
builder.UpdateConfigurationWithReplace( configSource );
Marker.customLogWriter = new LogWriterFactory( configSource ).Create();
}
InitializeLogger();
#endregion
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<loggingConfiguration name="Logging Application Block" tracingEnabled="true" defaultCategory="" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add fileName="C:\Logs\LogFileClearance.log" footer="" formatter="Timestamped Text Formatter"
header="" rollFileExistsBehavior="Increment"
rollInterval="None" rollSizeKB="1000" timeStampPattern="yyyy-MM-dd"
listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Log File Listener" />
</listeners>
<formatters>
<add template="{timestamp(local:MM/dd/yy hh:mm:ss tt)} tid={win32ThreadId}: {message}" type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" name="Timestamped Text Formatter" />
</formatters>
<categorySources>
<add switchValue="Information" name="All Events">
<listeners>
<add name="Log File Listener" />
</listeners>
</add>
<add switchValue="Error" name="Logging Errors & Warnings">
<listeners>
<add name="Log File Listener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="Information" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings" />
</specialSources>
</loggingConfiguration>
</configuration>
I am trying to Initialize SQL Membership Provider by code and everything is working fine in the first request only!. When the code below executes again (after refreshing the page for example) I get the following error:
The attribute 'connectionStringName' is missing or empty.
Page Load Code:
MembershipSection membershipSection = (MembershipSection)ConfigurationManager.GetSection("system.web/membership");
string sqlProviderName = "AspNetSqlMembershipProvider";
NameValueCollection providerConfig;
providerConfig = membershipSection.Providers[sqlProviderName].Parameters; // returning empty list in the second request
var _SqlProvider = new SqlMembershipProvider();
_SqlProvider.Initialize(sqlProviderName, providerConfig);
Web.config:
<membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ConnectionString" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Encrypted" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" applicationName="/" />
</providers>
</membership>
Any Advice?
how about just keep your data/connectionstring/obj at static level (as like singleton)?
it's not like connectionstring is going to be change throughout the web instance, does it?
static string/dataType _DataToBeRead1timeOnly = null;
static string/dataType DataToBeRead1timeOnly
{
get {
if (_DataToBeRead1timeOnly == null) { _DataToBeRead1timeOnly = .... }
return _DataToBeRead1timeOnly;
}
}
I'm trying to use the MySQLRoleProvider(MySql.Web, Version=6.2.2.0) with Visual Web Developer 2008.
When trying to add a role I get an exception "Table 'test.my_aspnet_applications' doesn't exist"
if (!Roles.RoleExists("TestRole"))
{
Roles.CreateRole("TestRole");
}
Can someone tell me where I went wrong. Or tell me how to generate / find the correct database script to create the role, membership, profile ... MySql tables.
<membership defaultProvider="MySQLMembershipProvider">
<providers>
<remove name="MySQLMembershipProvider"/>
<add autogenerateschema="true" connectionStringName="LocalMySqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Clear" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" passwordAttemptWindow="10" passwordStrengthRegularExpression="" name="MySQLMembershipProvider" type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.2.2.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/>
</providers>
</membership>
<profile enabled="true" defaultProvider="MySQLProfileProvider">
<providers>
<remove name="MySQLProfileProvider"/>
<add name="MySQLProfileProvider" autogenerateschema="true" type="MySql.Web.Profile.MySQLProfileProvider, MySql.Web, Version=6.2.2.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" connectionStringName="LocalMySqlServer" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="true" defaultProvider="MySQLRoleProvider">
<providers>
<remove name="MySQLRoleProvider"/>
<add autogenerateschema="true" connectionStringName="LocalMySqlServer" applicationName="/" name="MySQLRoleProvider" type="MySql.Web.Security.MySQLRoleProvider, MySql.Web, Version=6.2.2.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d"/>
</providers>
</roleManager>
Have you used the ASP.Net configuration tool to switch your application's provider to the MySQL provider? I believe this is what triggers the MySQL provider to automatically generate the schema.
Follow this codeproject howto and you'll be fine.
If your database won't generate try this:
Create a custom ContextInitializer and add this to the Global.asax:
Database.SetInitializer(new CreateMySqlDatabaseIfNotExists<MyContext>());
internal class CreateMySqlDatabaseIfNotExists<TContext>: IDatabaseInitializer<TContext> where TContext : MyContext
{
public void InitializeDatabase(TContext context)
{
if (context.Database.Exists())
{
if (!context.Database.CompatibleWithModel(false))
throw new InvalidOperationException("The model has changed!");
}
else
{
CreateMySqlDatabase(context);
Seed(context);
}
}
private void CreateMySqlDatabase(TContext context)
{
try
{
context.Database.Create();
return;
}
catch (MySqlException ex)
{
// Ignore the parse exception
if (ex.Number != 1064)
{
throw;
}
}
// Manually create the metadata table
using (var connection = ((MySqlConnection) context
.Database.Connection).Clone())
using (var command = connection.CreateCommand())
{
command.CommandText =
#"
CREATE TABLE __MigrationHistory (
MigrationId mediumtext NOT NULL,
CreatedOn datetime NOT NULL,
Model mediumblob NOT NULL,
ProductVersion mediumtext NOT NULL);
ALTER TABLE __MigrationHistory
ADD PRIMARY KEY (MigrationId(255));
INSERT INTO __MigrationHistory (
MigrationId,
CreatedOn,
Model,
ProductVersion)
VALUES (
'InitialCreate',
#CreatedOn,
#Model,
#ProductVersion);
";
command.Parameters.AddWithValue(
"#Model",
GetModel(context));
command.Parameters.AddWithValue(
"#ProductVersion",
GetProductVersion());
command.Parameters.AddWithValue(
"#CreatedOn",
DateTime.Now);
connection.Open();
command.ExecuteNonQuery();
}
}
private byte[] GetModel(TContext context)
{
using (var memoryStream = new MemoryStream())
{
using (var gzipStream = new GZipStream(
memoryStream,
CompressionMode.Compress))
using (var xmlWriter = XmlWriter.Create(
gzipStream,
new XmlWriterSettings {Indent = true}))
{
EdmxWriter.WriteEdmx(context, xmlWriter);
}
return memoryStream.ToArray();
}
}
private string GetProductVersion()
{
return typeof (DbContext).Assembly
.GetCustomAttributes(false)
.OfType<AssemblyInformationalVersionAttribute>()
.Single()
.InformationalVersion;
}
protected void Seed(TContext context)
{ // ...
context.SaveChanges();
}
}
I have an asp.net web app that uses forms-based authentication, a SqlMembershipProvider (using an encrypted password format), and a SqlRoleProvider. I need to know if it's possible to administer the users (create new users, assign them to roles, etc.) from a windows application - the powers that be don't want any administrative functionality in the web app itself.
Here is the membership provider definition from web.config:
<membership defaultProvider="MyProvider">
<providers>
<add name="MyProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="MyConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/MyWebApp"
requiresUniqueEmail="true"
passwordFormat="Encrypted"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/>
</providers>
</membership>
And the role manager definition:
<roleManager enabled="true" defaultProvider="MyRoleManager">
<providers>
<add name="MyRoleManager"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="MyConnectionString"
applicationName="/MyWebApp" />
</providers>
</roleManager>
And here is the machineKey definition (necessary to be able to use encrypted passwords):
<machineKey
validationKey="BC50A82A6AF6A015C34C7946D29B817C00F04D2AB10BC2128D1E2433D0E365E426E57337CECAE9A0681A2C736B9779B42F75D60F09F142C60E9E0E8F9840DB46"
decryptionKey="122035576C5476DCD8F3611954C837CDA5FE33BCDBBF23F7"
validation="SHA1"
decryption="AES"/>
So, obviously, I have a Sql Server database that contains the users and roles for the web app. I'd like to create a separate windows app that references the web app assembly, and use the configured MembershipProvider, RoleProvider, and machineKey to create users, assign users to roles, etc. If that's not possible, I can duplicate the configuration settings from web.config within the windows app. But I don't know how to do this either.
Am I way out of line thinking that this is possible? I've tried googling for a solution, but the signal-to-noise ratio is really bad.
Some options:
You could use the Web Site
Administration Tool, which isn't
Windows-Forms-based, but isn't part
of your Web app, either. It comes
with Visual Studio and can be
accessed by clicking the ASP.NET
Configuration icon in the Solution
Explorer.
It's possible to directly manipulate
the provider database used by a
SqlMembershipProvider from a Windows
Forms app, but you might have to be
careful not to break things.
If you were to create a custom
membership provider, you'd be in
control of how membership and role
data is persisted. If you did that
you could create a reusable library
that could be used in the Web app and
a Windows Forms app, too.
I don't think trying to use a SqlMembershipProvider from a Windows Forms app is a practical approach.
I've come up with a solution, based on the other answers (who both got +1), and some other sites out there.
First, I created Application Config file (app.config). It mirrors exactly what is found in web.config from the web app, with the exception of how the connection string was handled:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="connectionStrings" type="System.Configuration.ConnectionStringsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="MyConnectionString"
connectionString ="SERVER=abc;UID=def;PWD=hij;Initial Catalog=klm;MultipleActiveResultsets=True"/>
</connectionStrings>
<system.web>
<membership defaultProvider="MySqlMembershipProvider">
<providers>
<add name="MySqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="MyConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/MyWebApp"
requiresUniqueEmail="true"
passwordFormat="Encrypted"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/>
</providers>
</membership>
<roleManager enabled="true" defaultProvider="MySqlRoleManager">
<providers>
<add name="MySqlRoleManager"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="MyConnectionString"
applicationName="/MyWebApp" />
</providers>
</roleManager>
<machineKey
validationKey="BC50A82A6AF6A015C34C7946D29B817C00F04D2AB10BC2128D1E2433D0E365E426E57337CECAE9A0681A2C736B9779B42F75D60F09F142C60E9E0E8F9840DB46"
decryptionKey="122035576C5476DCD8F3611954C837CDA5FE33BCDBBF23F7"
validation="SHA1"
decryption="AES"/>
</system.web>
</configuration>
Then I created a helper class that provides access to two singletons: a MembershipProvider and a RoleProvider. This turned out to be easier than I thought, once I knew how to do it:
using System.Configuration;
using System.Reflection;
using System.Web.Security;
namespace WebAdminViaWindows
{
internal static class Provider
{
private static readonly string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
static Provider()
{
Membership = CreateMembershipProvider();
Role = CreateRoleProvider();
}
public static MembershipProvider Membership { get; private set; }
public static RoleProvider Role { get; private set; }
private static MembershipProvider CreateMembershipProvider()
{
var config = ConfigurationManager.OpenExeConfiguration(assemblyFilePath);
var systemWebGroup = config.SectionGroups["system.web"];
if (systemWebGroup == null)
{
throw new ConfigurationErrorsException("system.web group not found in configuration");
}
var membershipSection = systemWebGroup.Sections["membership"];
if (membershipSection == null)
{
throw new ConfigurationErrorsException("membership section not found in system.web group");
}
var defaultProviderProperty = membershipSection.ElementInformation.Properties["defaultProvider"];
if (defaultProviderProperty == null)
{
throw new ConfigurationErrorsException("defaultProvider property not found in membership section");
}
var defaultProviderName = defaultProviderProperty.Value as string;
if (defaultProviderName == null)
{
throw new ConfigurationErrorsException("defaultProvider property is not a string value");
}
var providersProperty = membershipSection.ElementInformation.Properties["providers"];
if (providersProperty == null)
{
throw new ConfigurationErrorsException("providers property not found in membership section");
}
var providerCollection = providersProperty.Value as ProviderSettingsCollection;
if (providerCollection == null)
{
throw new ConfigurationErrorsException("providers property is not an instance of ProviderSettingsCollection");
}
ProviderSettings membershipProviderSettings = null;
foreach (ProviderSettings providerSetting in providerCollection)
{
if (providerSetting.Name == defaultProviderName)
{
membershipProviderSettings = providerSetting;
}
}
if (membershipProviderSettings == null)
{
if (providerCollection.Count > 0)
{
membershipProviderSettings = providerCollection[0];
}
else
{
throw new ConfigurationErrorsException("No providers found in configuration");
}
}
var provider = new SqlMembershipProvider();
provider.Initialize("MySqlMembershipProvider", membershipProviderSettings.Parameters);
return provider;
}
private static RoleProvider CreateRoleProvider()
{
var config = ConfigurationManager.OpenExeConfiguration(assemblyFilePath);
var systemWebGroup = config.SectionGroups["system.web"];
if (systemWebGroup == null)
{
throw new ConfigurationErrorsException("system.web group not found in configuration");
}
var roleManagerSection = systemWebGroup.Sections["roleManager"];
if (roleManagerSection == null)
{
throw new ConfigurationErrorsException("roleManager section not found in system.web group");
}
var defaultProviderProperty = roleManagerSection.ElementInformation.Properties["defaultProvider"];
if (defaultProviderProperty == null)
{
throw new ConfigurationErrorsException("defaultProvider property not found in roleManager section");
}
var defaultProviderName = defaultProviderProperty.Value as string;
if (defaultProviderName == null)
{
throw new ConfigurationErrorsException("defaultProvider property is not a string value");
}
var providersProperty = roleManagerSection.ElementInformation.Properties["providers"];
if (providersProperty == null)
{
throw new ConfigurationErrorsException("providers property not found in roleManagerSection section");
}
var providerCollection = providersProperty.Value as ProviderSettingsCollection;
if (providerCollection == null)
{
throw new ConfigurationErrorsException("providers property is not an instance of ProviderSettingsCollection");
}
ProviderSettings roleProviderSettings = null;
foreach (ProviderSettings providerSetting in providerCollection)
{
if (providerSetting.Name == defaultProviderName)
{
roleProviderSettings = providerSetting;
}
}
if (roleProviderSettings == null)
{
if (providerCollection.Count > 0)
{
roleProviderSettings = providerCollection[0];
}
else
{
throw new ConfigurationErrorsException("No providers found in configuration");
}
}
var provider = new SqlRoleProvider();
provider.Initialize("MySqlRoleManager", roleProviderSettings.Parameters);
return provider;
}
}
}
At this point all that's needed is to access the Membership and Role properties of the Provider class. As an example, the following prints out the first 10 users and their roles:
int total;
foreach (MembershipUser user in Provider.Membership.GetAllUsers(0, 10, out total))
{
var sb = new StringBuilder();
sb.AppendLine(user.UserName);
foreach (var role in Provider.Role.GetRolesForUser(user.UserName))
{
sb.AppendLine("\t" + role);
}
Console.WriteLine(sb.ToString());
}
I'm not sure what "best-practice" would be here, but a simple way that should work is this.
Make a new windows app
Add an Application Config file
(app.config)
Copy the appropriate settings into
the app.config (settings from above
^)
Add a reference to System.Web
And copy the code from your web app
that uses the above settings to
connect to the database
That should do what you want.