i have a web application with custom AuthHandler that uses MySQL connection for checking permissions and business logic, that is linked to MS SQL database instance entities
so, the problem happens when the MS SQL Context is creating:
System.ArgumentException
Additional information: Keyword not supported.
at MySql.Data.MySqlClient.MySqlConnectionStringBuilder.GetOption(String key)
at MySql.Data.MySqlClient.MySqlConnectionStringBuilder.set_Item(String keyword, Object value)
at System.Data.Common.DbConnectionStringBuilder.set_ConnectionString(String value)
at MySql.Data.MySqlClient.MySqlConnectionStringBuilder..ctor(String connStr)
at MySql.Data.MySqlClient.MySqlConnection.set_ConnectionString(String value)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.<SetConnectionString>b__18(DbConnection t, DbConnectionPropertyInterceptionContext`1 c)
contexts code:
public SqlServerContext()
:base("SQLServer")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.AutoDetectChangesEnabled = true;
}
public MySqlContext()
:base("MySQL")
{
}
connection strings in config:
<add name="SQLServer"
connectionString="Data Source={};Initial Catalog={};Persist Security Info=True;User ID={};Password={};MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
<add name="MySQL" connectionString="Server={};Port=3306;Database=Test;Uid={};Pwd={}" providerName="MySql.Data.MySqlClient" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" />
</providers>
contexts are now injected with Ninject container:
binder.Bind<DbContext>().ToConstructor(i => new SqlServerContext()).Named(GlobalConstants.Context.ContentCodename);
binder.Bind<DbContext>().ToConstructor(i => new MySqlContext()).Named(GlobalConstants.Context.UserCodename);
for the first, i don't understant, why code is trying to build connection strings with MySql instances. so i've decided to create SQL Server context with implicit connection string:
public SqlServerContext()
: base(a())
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.AutoDetectChangesEnabled = true;
}
private static string a()
{
var a = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = new SqlConnectionStringBuilder
{
DataSource = #"{}",
InitialCatalog = "{}",
UserID = "{}",
Password = "{}",
MultipleActiveResultSets = true
}.ConnectionString
}.ConnectionString;
return a;
}
but there are errors something like: provider name keyword is not supported, multiple active results set keyword is not supported - that is characteristically for MySQL behavior. does have anybody solutions for that problem?
MySQL context was marked by attribute:
[DbConfigurationType(typeof (MySqlEFConfiguration))]
that is recommended for MySQL contexts using EF. removing this attribute solving issue
Related
I was seeking on the internet a bit, but couldn't find exactly what I meant...
Could you please elaborate what exactly I'm doing wrong here and how can I actually accomplish what I need? Issue explained in code comment just below multiple strings.
um.FindByName(username) - of course gives me an error "The entity type ApplicationUser is not part of the model for the current context"
public class MyNewAuthenticationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization == null)
{
base.OnAuthorization(actionContext);
}
else
{
string authenticationToken = actionContext.Request.Headers.Authorization.Parameter;
string decodedToken = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationToken));
string[] usernamePasswordArray = decodedToken.Split(':');
string username = usernamePasswordArray[0];
string password = usernamePasswordArray[1];
// Here is the issue. I need to check whether the user is in admin role....
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new WeatherAppDbEntities()));
var user = um.FindByName(username);
var isInRole = um.IsInRole(user.Id, "Admin");
if (// User is admin)
{
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
}
}
UPDATE:
Well it all works fine if i use:
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
in the new authentication attribute that i've created... Not really sure though what's the best practice to use ApplicationDbContext() with Ado.net data model created later
Like Stormcloak mentioned it seems that you have two or more DbContexts and therefore you are using more then one databases or connection strings.When creating Asp.Net MVC projects, tamplate comes with some models and controlers, as well as connection string named "DefaultConnection". Visual studio uses SQL Server Express and with connection string it generates database that will store information about users, so when you create your own database (" WeatherAppDb") you are basically working with two databases.
How to prevent this?
1. When creating MVC project check Web.config file for <connectionStrings> tag, if you find something
like tihs
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MyMVCProject-20180127104017.mdf;Initial Catalog=aspnet-MyMVCProject-20180127104017;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="WeatherAppDbConnectionString" connectionString="Data Source=(LocalDb)\SQLEXPRESS;;Initial Catalog=WeatherAppDb;Integrated Security=True"
providerName="System.Data.SqlClient" />
The easiest way would be to delete "Default Connection" connection string and rename your "Weather App DbConnectionString" to "Default Connection", so you would be left with just this
//renamed from WeatherAppDbConnectionString to Default Connection
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\SQLEXPRESS;;Initial Catalog=WeatherAppDb;Integrated Security=True"
providerName="System.Data.SqlClient" />
2. Once you have done first step, just go to your
WeatherAppDbEntities and as StormCloack stated make sure you have "Default Connection" here
public class WeatherAppDbEntities : IdentityDbContext<ApplicationUser>
{
public WeatherAppDbEntities()
: base("DefaultConnection")
{
}
}
As far as your code, maybe there could be a problem also but not sure, i've modified a little.
WeatherAppDbEntities db = new WeatherAppDbEntities();
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
var user = db.Users.Find(username);
It seems that the ApplicationUser identity isn't part of your current context WeatherAppDbEntities. You should implement it to your context.
public class WeatherAppDbEntities : IdentityDbContext<ApplicationUser>
{
public WeatherAppDbEntities()
: base("DefaultConnection")
{
}
}
A tricky (and frustrating problem) - perhaps you folks may be clever enough to solve it:
Problem
I want to be able to read/write to my database using Entity Frameworks. I have got a simple app rails running on Heroku (straightforward scaffold). I want to connect to this database and manipulate records. The good news is that I can successfully connect to that database using npgsql. The bad news is that I cannot do it with Entity Frameworks. This is the error I’m receiving:
System.Data.Entity.Core.ProviderIncompatibleException: An error
occurred while getting provider information from the database. This
can be caused by Entity Framework using an incorrect connection
string. Check the inner exceptions for details and ensure that the
connection string is correct. --->
System.Data.Entity.Core.ProviderIncompatibleException: The provider
did not return a ProviderManifestToken string. --->
System.IO.FileLoadException: Could not load file or assembly 'Npgsql,
Version=3.1.2.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7' or
one of its dependencies. The located assembly's manifest definition
does not match the assembly reference. (Exception from HRESULT:
0x80131040)
Here is the stack trace:
at Npgsql.NpgsqlServices.GetDbProviderManifestToken(DbConnection connection)
at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
--- End of inner exception stack trace ---
at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
--- End of inner exception stack trace ---
at System.Data.Entity.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection)
at System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.<>c__DisplayClass1.<ResolveManifestToken>b__0(Tuple`3 k)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at System.Data.Entity.Infrastructure.DefaultManifestTokenResolver.ResolveManifestToken(DbConnection connection)
at System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInfo(DbConnection connection, DbProviderManifest& providerManifest)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.Select[TSource,TResult](IQueryable`1 source, Expression`1 selector)
at ge_EntityFrameworkTest.Program.<Test>d__4.MoveNext() in c:\Users\Koshy\Documents\Visual Studio 2013\Projects\Practice\ge-EntityFrameworkTest\ge-EntityFrameworkTest\Program.cs:line 118
Here is my connection string:
NpgsqlConnectionStringBuilder sqlBuilder = new NpgsqlConnectionStringBuilder();
sqlBuilder.Username = user;
sqlBuilder.Password = password;
sqlBuilder.Host = host;
sqlBuilder.Port = Int32.Parse(port);
sqlBuilder.Database = database;
sqlBuilder.Pooling = true;
sqlBuilder.UseSslStream = true;
sqlBuilder.SslMode = Npgsql.SslMode.Require;
sqlBuilder.TrustServerCertificate = true;
Here is my “Hello world” that I am using to connect and read from my database (from the players table). It is successfully printing: “Lionel Messi” on to the console. Great!
#region connectingAndReadingDatabase
using (var conn = new NpgsqlConnection(sqlBuilder.ToString()))
{
conn.Open();
using (var cmd = new NpgsqlCommand())
{
cmd.Connection = conn;
// Retrieve all rows
cmd.CommandText = "SELECT * FROM players";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader.GetString(1));
}
}
}
}
#endregion
The problem is when I try to use Entity Frameworks. It fails massively with a painful error. I am using exactly the same connection string, and cannot for the life of me work out where I’m going wrong. Perhaps you may be able to easily spot the problem?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using Npgsql;
using System.Data.Entity;
using System.Data.Common;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Configuration;
using System.Data.Entity.ModelConfiguration.Conventions;
// Here is the code pertaining to my hello world entity framework example:
[Table("players", Schema = "public")]
public class Player
{
[Key]
[Column("id")]
public int id { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("team")]
public string Team { get; set; }
public Player() { }
}
class NpgsqlConfiguration : System.Data.Entity.DbConfiguration
{
public NpgsqlConfiguration()
{
SetProviderServices ("Npgsql", Npgsql.NpgsqlServices.Instance);
SetProviderFactory ("Npgsql", Npgsql.NpgsqlFactory.Instance);
SetDefaultConnectionFactory (new Npgsql.NpgsqlConnectionFactory ());
}
}
[DbConfigurationType(typeof(NpgsqlConfiguration))]
public class PlayerContext : DbContext
{
public PlayerContext(DbConnection connection): base(connection, true)
{
}
public DbSet<Player> Players { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//modelBuilder.Conventions.Add<CascadeDeleteAttributeConvention>();
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.HasDefaultSchema("public");
base.OnModelCreating(modelBuilder);
}
}
And here is my app.config file
<?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=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v12.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
<provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.data>
<DbProviderFactories>
<add name="Npgsql Data Provider"
invariant="Npgsql"
description="Data Provider for PostgreSQL"
type="Npgsql.NpgsqlFactory, Npgsql" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<add name="PlayerContext" connectionString="Username=hjanadgkizjmgf;Password=password;Host=ec2-54-235-250-156.compute-1.amazonaws.com;Port=5432;Database=deek4ap6cf2a1;Pooling=true;Use SSL Stream=True;SSL Mode=Require;TrustServerCertificate=True;" providerName="Npgsql" />
</connectionStrings>
</configuration>
When I pass in a connection string directly - the same one which worked so well to retrieve records earlier, I get this curious exception:
“Keyword not supported ‘username’” – obviously referring to the
connection string passed in.
using (var db = new PlayerContext(sqlBuilder.ToString()))
{ // etc }
Also curiously, I receive a warning before compiling:
“Warning 1 Found conflicts between different versions of the same
dependent assembly that could not be resolved. These reference
conflicts are listed in the build log when log verbosity is set to
detailed. pg-EF-test2” perhaps it’s something to do with Npgsql?
Any assistance would be much appreciated.
Looks like the "EntityFramework6.Npgsql" nuget package in the current version has incorrectly defined dependencies. It lists "Npgsql (>= 3.1.0)" as a dependency but it actually requires Npgsql in version 3.1.2 or higher.
So the fix is simple - just update the Npgsql package to the latest version. "Update-Package Npgsql" should do the trick.
And as for the context constructor with a string parameter - you got a weird exception because that constructor expects you to pass the name of the connection string from your config file. You should use it like this:
using (var db = new PlayerContext("PlayerContext"))
{ }
I am trying to create a Database with entity framework code-first environment.
The tables in database are identity tables.
The problem is with SQL server's database creation. There is no database created When I ran application.
However, I am able to find physical find here at this location -
C:\Users\user\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS\HWAPI.mdf
So whenever I do add any table or change the structure then all the changes are happening in above location and think that this is not using master database.
There is no database created in my local SQL server.
Have a look at my code -
StartUp.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
config.DependencyResolver = new NinjectResolver(NinjectWebCommon.CreateKernel());
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
app.CreatePerOwinContext(OwinAuthDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
}
}
And there is the context -
public class OwinAuthDbContext : IdentityDbContext<ApplicationUser>, IDisposable
{
public OwinAuthDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
Database.SetInitializer<OwinAuthDbContext>(null);
}
public static OwinAuthDbContext Create()
{
return new OwinAuthDbContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<IdentityUser>().ToTable("AspNetUsers");
modelBuilder.Entity<IdentityRole>().ToTable("AspNetRoles");
modelBuilder.Entity<IdentityUserClaim>().ToTable("AspNetUserClaims");
modelBuilder.Entity<IdentityUserLogin>().ToTable("AspNetUserLogins");
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
web.config
<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=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=HWAPI;Integrated Security=SSPI;Connect Timeout=30;User Instance=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Please assist and let me know if additional info is required.
Your problem is with the connection string.You need to try as shown below.
If you need to use Localhost then :
<connectionStrings>
<add name="DefaultConnection" connectionString="Server=localhost; Database=HWAPI;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
If you need to use LocalDb then :
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\HWAPI.mdf;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
Thanks everybody for putting their inputs.
It turns out that I needed to setup credentials for existing database. After I setup credentials security for database then it worked.
before -
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=HWAPI;Integrated Security=SSPI;Connect Timeout=30;User Instance=True"
providerName="System.Data.SqlClient" />
after -
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=HWAPI;User ID=sa;Password=truw#123" providerName="System.Data.SqlClient"/>
This solved my issue and I was able to connect to database within SQLEXPRESS.
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.
We're using ASP.Net membership providers (the SQL Server provider), and I want to be able to set up an Admin user account as part of our installer. To do this, I need the ASP.Net membership provider configured so that my installer can use it - but I don't want to have to set up a config file for the installer.
So is there a way of configuring an ASP.Net membership through code without writing a custom provider?
Ok, following the solution they conjured up here: http://forums.asp.net/p/997608/2209437.aspx
I created a class which, in the parameterless constructor (which you need) just gets the server and port from the command line arguments. Such that I can go "MembershipInitializer.exe "SomeSqlServer\Instance" 51000.
public class CustomSQLMembershipProvider : SqlMembershipProvider {
private readonly string _server;
private readonly string _port;
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Web.Security.SqlMembershipProvider"/> class.
/// </summary>
public CustomSQLMembershipProvider() {
string[] args = System.Environment.GetCommandLineArgs();
// args[0] is the exe name
_server = args[1];
_port = args[2];
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
// Update the private connection string field in the base class.
string connectionString = string.Format(#"Data Source={0},{1};Initial Catalog=aspnetdb;UID=NICCAMembership;PWD=_Password1;Application Name=NICCA;Connect Timeout=120;", _server, _port);
// Set private property of Membership provider.
FieldInfo connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
}
}
In the app.config of your console app (or windows app)
<configuration>
<connectionStrings>
<clear/>
<add name="MembershipDB"
connectionString="Some Bogus String here that gets overrided in the custom class"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<authentication mode="Forms"/>
<authorization>
<deny users="?"/>
</authorization>
<membership>
<providers>
<remove name="AspNetSqlMembershipProvider"/>
<add name="AspNetSqlMembershipProvider"
connectionStringName="MembershipDB"
applicationName="NICCA"
type="MyInitializeMembershipDB.CustomSQLMembershipProvider, MyInitializeMembershipDB"
requiresUniqueEmail="false"
requiresQuestionAndAnswer="false"/>
</providers>
</membership>
</system.web>
</configuration>
If you are in need of the role provider bit as well, you probably have to override SqlRoleProvider in much the same way.
If you are creating a program to automatically initialize your membership database to a specific state based but the sql server address and port name aren't known until someone enters them into a install wizard, this will do the trick..
Does this help?
Membership.ApplicationName = "yourfbaApplicationame";
MembershipUser user = Membership.CreateUser("admin,"password","emaiol#g.com");
and Make sure that you have the following entries in the config file.
<connectionStrings>
<add connectionString="server=sqd01-1-cll;database=FBA;Integrated Security=SSPI;" name="FBASqlConnString" providerName="System.Data.SqlClient"/>
If you still wanted to use the complete code and dont need to use the config file. Use the below
SqlMembershipProvider ObjSqlMembershipProvider = new SqlMembershipProvider();
SqlRoleProvider ObjSqlRoleProvider = new SqlRoleProvider();
NameValueCollection ObjNameValueCollRole = new NameValueCollection();
NameValueCollection ObjNameValueCollMembership = new NameValueCollection();
MembershipCreateStatus enMembershipCreateStatus;
ObjNameValueCollMembership.Add("connectionStringName", "Connection String Name");
ObjNameValueCollMembership.Add("applicationName", "ApplicatioNAme");
//these items are assumed to be Default and dont care..Should be given a look later stage.
ObjNameValueCollMembership.Add("enablePasswordRetrieval", "false");
ObjNameValueCollMembership.Add("enablePasswordReset", "false");
ObjNameValueCollMembership.Add("requiresQuestionAndAnswer", "false");
ObjNameValueCollMembership.Add("requiresUniqueEmail", "false");
ObjNameValueCollMembership.Add("passwordFormat", "Hashed");
ObjNameValueCollMembership.Add("maxInvalidPasswordAttempts", "5");
ObjNameValueCollMembership.Add("minRequiredPasswordLength", "1");
ObjNameValueCollMembership.Add("minRequiredNonalphanumericCharacters", "0");
ObjNameValueCollMembership.Add("passwordAttemptWindow", "10");
ObjNameValueCollMembership.Add("passwordStrengthRegularExpression", "");
//hard coded the Provider Name,This function just need one that is present. I tried other names and it throws error. I found this using Reflector ..all the rest are take care by the above
//name value pairs
ObjSqlMembershipProvider.Initialize("AspNetSqlMembershipProvider", ObjNameValueCollMembership);MembershipUser user = ObjSqlMembershipProvider.CreateUser("admin,"password","emaiol#g.com");
One this You need to give the connection string in the Config file no other go. If you want that too to be from the code you need to inherit the class