Few queries about InitializeSimpleMembership class usage in ASP.Net MVC4 - asp.net-mvc-4

i am new in MVC. so i just create a mvc project with vs2013 with internet template. i found one class called InitializeSimpleMembership. tell me what is the usage of this class.
i put break point on this function OnActionExecuting & SimpleMembershipInitializer and saw this function is getting called when i try to access any protected page or when i am clicking on login or register link. i need some insight about this class InitializeSimpleMembership.
what this line is doing LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); ?
tell me what the below routine is doing
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized.", ex);
}
}
i could understand this line context.Database.Exists() is trying to check a specific db is exist or not. which db it is trying to check exist or not?
what this line is doing WebSecurity.InitializeDatabaseConnection() ?
guide me what i need to do as a result simple membership provider create required table and i could validate user against my database.
tell me what if i need to add more fields then what i need to do.
looking for guidance. thanks

The SimpleMembership provider has been introduced with ASP.NET MVC 4. It extends the core membership and role providers in order to make more flexible the way in which user information are stored in a custom database.
The attribute InitializeSimpleMembershipAttribute takes care of initializing the simple membership provider, defining which context class should be used to work with the database (the UserContext class).
The WebSecurity.InitializeDatabaseConnection initializes the membership system specifying the database through the connection string (“DefaultConnection”), the name of the table in which the user profile data are stored (“UserProfile”) and the name of the field that should be used for the login and so to match the user profile with the membership account.
The method LazyInitializer.EnsureInitialized just ensures that the simple membership is initialized once.
This attribute creates the tables necessary for managing membership in the database specified by the connection string. So it creates the table for the UserProfile model class with the columns “UserId” and “UserName” and uses the “UserId” as a foreign key to relate with the other auto generated tables needed for authentication and authorization.
The AccountController that contains all the basic operations that can be performed on the user profile is decorated with the attribute and in this way every time the user tries to login or register the simple membership is automatically initialized.
http://weblogs.asp.net/jongalloway/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates

Related

Create role using entity framework core migrations

I'm creating my 4th migrations script with EF Core (2.0.0). In there I want to add a few roles to the database.
The problem is, is that I'm not really sure how to do this. Currently I have this:
protected override void Up(MigrationBuilder migrationBuilder)
{
// todo: Pass connection string somehow..?
var opt = new DbContextOptions<ApplicationContext>();
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationContext(opt)));
//if (!roleManager.RoleExists("ROLE NAME"))
//{
// todo: create the role...
//}
}
But creating the RoleManager like that gives me the following error:
There is no argument given that corresponds to the required formal
parameter 'roleValidators' of
'RoleManager.RoleManager(IRoleStore,
IEnumerable>, ILookupNormalizer,
IdentityErrorDescriber, ILogger>)'
I'm not sure how to solve this problem. I couldn't find any info on how to do this properly in .NET Core using migrations.
I'm facing two issues in this code:
I'm trying to create an instance of the DbContext somehow. Shouldn't I be able to get the DbContext from within my migrations code?
Instantiating the RoleManager like this doesn't work and needs to be resolved.
How can I solve these problems?
The Up method is basically an instruction file that tells EF's database migrator how to generate a database upgrade script. The method is executed when the script is generated. Doing any data manipulation there is absolutely out of place. EF core doesn't support seeding yet, so you have to add missing roles when the application starts, for example by something like this.

I cannot figure out how to use the SimpleMembershipProvider.GetUserNameByEmail Method

This is a MVC 4 Internet application. I have set the Role Provider and Role Manager to SimpleRoleProvider and SimpleMembershipProvider in the Web.config file, but I continue to get the "You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class" exception despite initializing WebSecurity.InitializeDatabaseConnection in the Global,asax.cs file. I know this was initialized properly because the Roles property in the Authorize Attribute I have created and assign programmatically work perfect. All I want to do is retrieve a Users UserName and email it to them if they forget and cannot login. Advice appreciated.
[HttpPost]
[CaptchaVerify("Captcha is not valid")]
[AllowAnonymous]
public ActionResult ForgotUserNameOrPassword(UserProfile model, FormCollection collection)
{
if (!ModelState.IsValid)
{
ViewBag.Error = "The Captcha answer is incorrect";
return View();
}
else
{
SimpleMembershipProvider mySMP = new SimpleMembershipProvider();
int outRecs;
dynamic email = new Postal.Email("UserNameEmail");
MembershipUserCollection myUserCol =mySMP.FindUsersByEmail(model.UserEmail, 0, 0, out outRecs);
email.Username = myUserCol;
email.To = model.UserEmail;
email.From = model.UserEmail;
email.Send();
return View("../Account/Login");
}
}
Even if you did call InitializeDatabaseConnection properly it would not work for SimpleMembershipProvider.FindUsersByEmail. Here is a note in the documentation for this method.
If the SimpleMembershipProvider class has been initialized using a call to the WebSecurity.InitializeDatabaseConnection() method, this method is not supported and will throw a NotSupportedException exception. However, if the WebSecurity.InitializeDatabaseConnection() method has not been called, and if you have configured your site to use the standard ASP.NET membership provider, this method is passed through to the standard membership provider. For more information, see the SimpleMembershipProvider class overview.
What you are experiencing does not make any sense given the documentation. Where exactly is the exception being thrown? When you call FindUsersByEmail?
Updated 6/28/13
SimpleMembershipProvider does not implement all of the standard provider methods. If a method is missing you have a couple of options. First you can create your own custom SimpleMembershipProvider that is derived from the original that has the methods you need. Or you can extend the WebSecurity class to include the methods you need. Take a look at the SimpleSecurity open source project which decouples SimpleMembership from the ASP.NET MVC application. This article describes how to extend the WebSecurity class and queries the database directly. You can do something similar and query for a particular user by their email address.
But SimpleMembership does not support storing the users email address out-of-the-box. Take a look at this article on how to customize SimpleMembership to include the email address.
Also keep in mind that the reason that the base membership provider returns multiple users for an email address is that the schema does not restrict a user from opening multiple accounts with the same email address, unless the email address is used as the username.

Using MVC 4 SimpleMembership with an existing database-first EF model

I am trying to use SimpleMembership in my MVC 4 for the first time and I already have an existing database and EF5 model created based on it! I searched a lot but I cant find how I could use it in my case and also to have everything under my own model.
It would be great if somebody can give me an idea how to do this.
Thanks
Purely as a point of reference, it might be a good idea to create a new Internet Application template of an ASP.NET MVC 4 Web Application project (i.e. via File > New Project).
If you look at the AccountController, as #zms6445 says, it is decorated with an InitializeSimpleMembership attribute. You can find the implementation of this attribute in the InitializeSimpleMembershipAttribute.cs file in the Filters folder within the root directory.
In here, this is the missing part of the puzzle - you need to hook up your existing database so that it is used by the SimpleMembershipProvider. This is the code you need:
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
try
{
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("CONNECTION_STRING_NAME", "USER_TABLE", "USER_ID_FIELD", "USER_NAME_FIELD", autoCreateTables: true);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("Something is wrong", ex);
}
}
}
Some things to note:
CONNECTION_STRING_NAME is an entry in your web.config ConnectionStrings - you CANNOT use the model connection string here - the SimpleMembershipProvider does not recognise that format! You need to specify an System.Data.SqlClient connection string, e.g.
<add name="CONNECTION_STRING_NAME" connectionString="data source=SERVER;initial catalog=DATABASE;user id=USER;password=PASSWORD;" providerName="System.Data.SqlClient" />
USER_TABLE is the table in your database to hold extra user information, such as first name, surname etc. This is linked to the autogenerated tables via the USER_ID_FIELD.
USER_ID_FIELD is usually the primary key of your Users table. It must be of type int.
USER_ID_NAME is a unique name for the user, which could be an Email address.
autoCreateTables is set to true to ensure the tables required for the SimpleMembership to work are created if they don't already exist.
Of course, this code only gets fired if you hit a page via the AccountController, since this has been decorated by the attribute. You could put a breakpoint in there and see it in action.
This should get you started - the Internet Application template is a pretty good template to follow if you get stuck.
Hope this helps.
In your web.config in the appSettings tag, add the line
<add key="enableSimpleMembership" value="true"/>
SimpleMembership is built in so from here you simply need to write
[InitializeSimpleMembership]
above your public class AccountController: Controller
When you want to force a user to log in for a certain page you write in the pages controller
[Authorize]
That tables will be automatically generated in your database. If you want to add more fields to these tables you will need to simply google it.
Here's a link for more information http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx

CREATE DATABASE permission denied in database 'master'. MVC EF 4.1 Codefirst getting started

I checked here and the internet with no answer. How do I get this to work ? I am using discountasp.net SQL so is it a setting on thier side to make it work ?
The following blog post explains this well. If you haven't specified a connection string in your web.config than EF CodeFirst will attempt to create a DB on your local instance of SQLExpress. Otherwise you can set the intent by assigning to a named connnection string via the public constructor of your entities context inheriting from the base constructor.
http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx
public class UnicornsContext : DbContext
{
public UnicornsContext()
: base("UnicornsCEDatabase")
{
}
}
Either way you'll need to ensure that your account has appropriate access to the SQL(Express) server to create a new database.
User in connection string used to access database has no create database right, so the exception is thrown. Try changing user or giving him access rights.

Single website multiple connection strings using asp mvc 2 and nhibernate

In my website i use ASP MVC 2 + Fluent NHibernate as orm, StructureMap for IoC container.
There are several databases with identical metadata(and so entities and mappings are the same). On LogOn page user fiils in login, password, rememberme and chooses his server from dropdownlist (in fact he chooses database).
Web.config contains all connstrings and we can assume that they won't be changed in run-time.
I suppose that it is required to have one session factory per database.
Before using multiple databases, i loaded classes to my StructureMap ObjectFactory in Application_Start
ObjectFactory.Initialize(init => init.AddRegistry<ObjectRegistry>());
ObjectFactory.Configure(conf => conf.AddRegistry<NhibernateRegistry>());
NhibernateRegistry class:
public class NhibernateRegistry : Registry
{
public NhibernateRegistry()
{
var sessionFactory = NhibernateConfiguration.Configuration.BuildSessionFactory();
For<Configuration>().Singleton().Use(
NhibernateConfiguration.Configuration);
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(
ctx => ctx.GetInstance<ISessionFactory>().GetCurrentSession());
}
}
In Application_BeginRequest i bind opened nhibernate session to asp session(nhibernate session per request) and in EndRequest i unbind them:
protected void Application_BeginRequest(
object sender, EventArgs e)
{
CurrentSessionContext.Bind(ObjectFactory.GetInstance<ISessionFactory>().OpenSession());
}
Q1: How can i realize what SessionFactory should i use according to authenticated user?
is it something like UserData filled with database name (i use simple FormsAuthentication)
For logging i use log4net, namely AdoNetAppender which contains connectionString(in xml, of course).
Q2: How can i manage multiple connection strings for this database appender, so logs would be written to current database? I have no idea how to do that except changing xml all the time and reseting xml configuration, but its really bad solution.
I suppose that it is required to have one session factory per database.
No; you can do just fine with one session factory for both databases.
You just supply an opened IDbConnection as a param to the OpenSession() method of ISessionFactory.
By doing so, you'll lose the possibility for a second level cache, but that might not be a problem.
If you want the second level cache, you need to implement you're own DriverConnectionProvider and supply it via fluent nh's Provider<TYourDriverConnectionProvider>() method.