Home > .NET, MVC 4, Twilio > Seed Users and Roles with MVC 4, SimpleMembershipProvider, SimpleRoleProvider, Entity Framework 5 CodeFirst, and Custom User Properties

Seed Users and Roles with MVC 4, SimpleMembershipProvider, SimpleRoleProvider, Entity Framework 5 CodeFirst, and Custom User Properties

September 25, 2012 Leave a comment Go to comments

I’ve been Googling over the weekend and so far didn’t find any articles out there on how integrate EF5 CodeFirst nicely with SimpleMembership and at the same time, seeding some of your users, roles and associating users to roles while supporting custom fields/properties during registration, hence this blog post.

I think this is a nice to have, especially during PoC development where you could be developing features that depend on authentication and authorization while making schema changes with EF CodeFirst. The last thing you want to do is run update-database for migrations and have to manually re-insert/re-seed all your users, roles and associating the two every time you ran migrations (e.g. update-database -force from the Package Manager Console).

First, create an “Internet Application” ASP.NET MVC4 Project, because this is the only out of the box MVC template that has the new SimpleMembershipProvider wired up out of the box. One of the features I like the most about the SimpleMembershipProvider is it gives you total control of the highly requested “User” table/entity. Meaning you integrate SimpleMembershipProvider with your own user table, as long as it has a UserId and UserName fields in your table.

Obviously there are many more features in SimpleMembership provider, here are some links in this regard:

Explicitly wire up the providers even though this is implied, so that when do run the “update-database” command from the Package Manager Console for migrations we can use the native “Roles” Api.

In the “System.Web” Section add:


    <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
      <providers>
        <clear/>
        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
      </providers>
    </roleManager>
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear/>
        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>

Let’s add a custom field to the User table by adding a Mobile property to the UserProfile entity (MVC4SimpleMembershipCodeFirstSeedingEF5/Models/AccountModel.cs).


    [Table("UserProfile")]
    public class UserProfile
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Mobile { get; set; }
    }

Enable EF5 CodeFirst Migrations

Seed your Roles and any Users you want to provision, also note the WebSecurity.InitializeDatabaseConnection method we are invoking. This method is what tells SimpleMembership which table to use when working with Users and which columns are for the UserId and UserName. I’m also going to demonstrate how you can hydrate additional custom columns such as requiring a User’s mobile number when registering on the site.


#region

using System.Data.Entity.Migrations;
using System.Linq;
using System.Web.Security;
using MVC4SimpleMembershipCodeFirstSeedingEF5.Models;
using WebMatrix.WebData;

#endregion

namespace MVC4SimpleMembershipCodeFirstSeedingEF5.Migrations
{
    internal sealed class Configuration : DbMigrationsConfiguration<UsersContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
        }

        protected override void Seed(UsersContext context)
        {
            WebSecurity.InitializeDatabaseConnection(
                "DefaultConnection",
                "UserProfile",
                "UserId",
                "UserName", autoCreateTables: true);

            if (!Roles.RoleExists("Administrator"))
                Roles.CreateRole("Administrator");

            if (!WebSecurity.UserExists("lelong37"))
                WebSecurity.CreateUserAndAccount(
                    "lelong37",
                    "password",
                    new {Mobile = "+19725000000"});

            if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
                Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
        }
    }
}

Now, run the update-database -verbose command from Package Manager Console, we are using the -verbose switch so that we can get better visibility on what’s getting executed on SQL. Notice the Mobile field is being created.

Let’s go ahead and do a sanity check and make sure all of our Users and Roles were provisioned correctly from the Seed method in our migration configuration, by executing a few queries.


SELECT TOP 1000 [UserId]
      ,[UserName]
      ,[Mobile]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[UserProfile]
  
  SELECT TOP 1000 [RoleId]
      ,[RoleName]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_Roles]
  
  SELECT TOP 1000 [UserId]
      ,[RoleId]
  FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_UsersInRoles]

Results

  • Users were inserted
  • Roles were provisioned
  • The user “LeLong37″ was added and associated to the Administrator role

Finally for a sanity check, let’s go ahead and run the app and sign-in with the provisioned user from our Seed method.

Successfully authenticated with our seeded provisioned user (thought I’d add a blue star badge to the screenshot to add some humor :P )!

One last thing, let’s go ahead and modify our Register view, Register model and AccountController to gather the user’s mobile number during registration.

Register View (Register.cshtml)


@model MVC4SimpleMembershipCodeFirstSeedingEF5.Models.RegisterModel
@{
    ViewBag.Title = "Register";
}

<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>Create a new account.</h2>
</hgroup>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()

    <fieldset>
        <legend>Registration Form</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
            </li>
            <li>
                @Html.LabelFor(m => m.Mobile)
                @Html.TextBoxFor(m => m.Mobile)
            </li>
        </ol>
        <input type="submit" value="Register" />
    </fieldset>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}


Register model (AccountModel.cs)


    public class RegisterModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        [Required]
        [DataType(DataType.PhoneNumber)]
        [Display(Name = "Mobile")]
        public string Mobile { get; set; }
    }


Register Action (AccountController.cs)


        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    WebSecurity.CreateUserAndAccount(
                        model.UserName, 
                        model.Password, 
                        new { Mobile = model.Mobile }, 
                        false);

                    WebSecurity.Login(model.UserName, model.Password);
                    return RedirectToAction("Index", "Home");
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

Finally, let’s register.

Let’s go ahead and run our SQL queries again and make sure the mobile number was actually saved to our UserProfile table during the registration.

Sweet! Registration successful, with mobile number saved to the UserProfile table.

Happy Coding…!

Download Sample Application: http://blog.longle.net/2012/09/26/multi-step-asp-net-mvc-4-registration-with-sms-using-twilio-cloud-communication-and-simplemembershipprovider-for-increased-user-validity/

About these ads
  1. hansoky
    September 27, 2012 at 3:54 pm | #1

    Thanks, very helpful, saved me quite some time.

    Regards, Hans

    • Le
      September 27, 2012 at 4:56 pm | #2

      Hans,

      Thanks for the positive feedback, and I’m glad you found the post helpful.

  2. Peter Wallenius
    September 27, 2012 at 4:31 pm | #3

    Great sample!

    Could you hint how to access the custom user property from code after login?

    • Le
      September 27, 2012 at 4:59 pm | #4

      Peter,

      Thanks! So far the only way I know of at the moment, is to actually access custom user properties using EntityFramework itself.

      • Peter Wallenius
        September 28, 2012 at 2:46 am | #5

        Hi Le,

        I have implemented your sample, and it Works perfektly – thanks for sharing :-)
        Do you know of any way to get the Id of a user from inside MVC4 so that I can use the .Find method of the DBContext or do I have to create a query searching for the UserName…

        /re. Peter

        • Le
          September 28, 2012 at 5:59 pm | #6

          Peter,

          You are on the right track, you will have to query the UserProfile table using EntityFramework (your DBContext) by username.

  3. Aaron
    October 5, 2012 at 2:26 am | #7

    Hi Le,

    I’ve gone through, and created a project based on the membership samples you’ve given here and begun to expand on it to include related tables.. However it seems the WebSecurity.CreateUserAndAccount method chokes when we have a self-defined ‘User’ table with foreign keys.

    I have one-to-one and many-to-many relationships defined, and both cause errors similar to this: System.Data.SqlClient.SqlException (0×80131904): Invalid column name ‘PlayingTeams’.

    PlayingTeams is a virtual ICollection and I’ve set up mapping like this in the OnModelCreating method:

    modelBuilder.Entity()
    .HasMany(t => t.Players)
    .WithMany(p => p.PlayingTeams)
    .Map(mc =>
    {
    mc.ToTable(“TeamPlayers”);
    mc.MapLeftKey(“UserProfileId”);
    mc.MapRightKey(“TeamId”);
    });

    What do you think..? Is there something missing, or are you perhaps aware of a limitation in the design of this?

    Cheers, Aaron

    • Le
      October 10, 2012 at 10:10 pm | #8

      Hi Aron,

      I’m unaware of why this might be happening, currently my User table has foreign keys, however just not with a many-to-many relationship, and instead a one-to-one relationship. However looking at your modelBuilder code, it looks like you can’t insert a Player without inserting the user into a PlayingTeam, the WebSecurity.CreateUserAndAccount will not do this. You can test this theory by temporarily removing the many-to-many.

      • Aaron
        October 16, 2012 at 6:06 am | #9

        Hi Le,

        Sorry for not writing earlier, I just returned from a short and much-needed break :-)

        I will check this out in the evening and see what sticks with some different approaches and write back afterwards.

        Perhaps you’re right about the model builder code and I need to learn a bit more about how this fluent API works.

        Cheers,
        - Aaron

  4. Diin
    October 20, 2012 at 7:07 am | #10

    I just tried the sample of your link and could not download could you please provide the sample code again thanks

  5. darrel
    October 23, 2012 at 6:22 am | #12

    Hi, thanks for the good post. I have made use of this in my work.

    I would like to clarify, if I wanted to use the email field in place of the user name, would I change:

    WebSecurity.InitializeDatabaseFile(“SecurityDemo.sdf”, “Users”, “UserID”, “Username”, true);

    to:

    WebSecurity.InitializeDatabaseFile(“SecurityDemo.sdf”, “Users”, “UserID”, “Email”, true);

    Then, within my MVC 4 app, in the account controller, login action I would place:

    if (ModelState.IsValid && WebSecurity.Login(model.Email, model.Password, persistCookie: model.RememberMe))

    {

    return RedirectToLocal(returnUrl);

    }

    I would continue this, matching up the web security username with the user model email e.g:

    private static string ErrorCodeToString(MembershipCreateStatus createStatus)

    {

    // See go.microsoft.com/fwlink for

    // a full list of status codes.

    switch (createStatus)

    {

    case MembershipCreateStatus.DuplicateUserName:

    return “An account with that email already exists. Please use a different email or contact info@moneydrainplug.com.”;

    .

    .

    .

    Apologies for the long post and all the code, I hope it is still legible.

    Thanks

    • Le
      October 24, 2012 at 10:52 am | #13

      Thanks Darrel for the update!

  6. David
    October 28, 2012 at 10:28 am | #14

    Hi Lee
    Thank you very much for this post
    If I want to add Administrator from View What should I do?

    • Le
      October 28, 2012 at 11:54 am | #15

      Hi David, you will need to create a view that with with a minimum of two text fields e.g. Username and Password. In your controller action or service that your injecting to invoke the WebSecurity.CreatUserAndAccount method.

      
      WebSecurity.CreateUserAndAccount("lelong37@gmail.com", "mypassword");
      
      

      SimpleMembershipProvider does not support the ASP.NET Configuration Site, the out of the box Admin screens that you can use to manage User, Roles, and Permissions with the other providers.

  7. October 30, 2012 at 3:34 pm | #16

    Hi great work really helpful. Would you be so kind to let me know if i would like to input more fields how can i work around the WebSecurity.CreateUserAndAccount(…….) for example I would like to input
    model.UserName,
    model.Password,
    model.FirstName,
    model.LastName );

    Please any suggestion would be helpful and thanks in advance for any help! Regards, Ilia

    • Le
      October 30, 2012 at 3:57 pm | #17

      Hi Ilia,

      You will need to create those fields in your the user table you are using.

      You can get those values in by using a dynamic object/class as the last parameter in the WebSecurity.CreateUserAndAccount method.

      
                  if (!WebSecurity.UserExists("lelong37@gmail.com"))
                      WebSecurity.CreateUserAndAccount(
                          "lelong37@gmail.com", 
                          "password", 
                          new
                              {
                                  FirstName = model.FirstName,
                                  LastName = model.LastName,
                                  Created = DateTime.Now, 
                                  Updated = DateTime.Now
                              });
      
      
  8. October 30, 2012 at 11:08 pm | #18

    Thanks. Your recipe for newing up additional columns in the WebSecurity.CreateUserAndAccount call was EXACTLY what I needed.

    • Le
      October 31, 2012 at 5:05 pm | #19

      Hi Craig, thanks for the positive feedback and for stopping by..! :)

  9. iliali16
    October 31, 2012 at 5:03 pm | #20

    Thank you Le I managed doing it as you say also adding
    WebSecurity.CreateUserAndAccount(
    model.UserName,
    model.Password,
    new {FirstName = model.FirstName,
    LastName = model.LastName,
    City = model.City,
    ZIP = model.ZIP,
    Street = model.Street,
    StreetNumber = model.StreetNumber,
    Country = model.Country}, false
    );
    and it works perfectly. Now I need to work on the admin being able to edit these parameters. Thanks for the reply.

    • Le
      October 31, 2012 at 5:06 pm | #21

      itiali, thanks for the positive feedback and stopping by, good luck on the Admin…!

  10. iliali16
    November 1, 2012 at 4:07 pm | #22

    Hi Le will you be able to help me a bit and advice me on the best way I should allow the user to vie his details and edit them later if he requires. Also give him the chance to unsubscribe. Thank you very much in advance!

  11. Rob
    November 5, 2012 at 8:24 pm | #23

    Great article. thanks. I’m using Nhibernate, but this has been very informative to get me going.

    • Le
      November 6, 2012 at 11:06 am | #24

      Rob, thanks for the positive feedback and stopping by! :)

  12. November 15, 2012 at 2:01 am | #25

    Hi Le, thanks for this. This is very useful.

    I have a question: is the InitializeSimpleMembership attribute in the AccountController class still needed or can it be deleted? Thanks

    • Le
      November 15, 2012 at 5:00 pm | #26

      Hi Jeremiah,

      You can delete it, as long as you are calling WebSecurity.CreateUserAndAccount method from you Seed method in your /MIgrations/Configuration.cs class as illustrated in this blog post.

  13. November 15, 2012 at 8:30 am | #27

    I’m trying this but when I try to update-database -verbose, return and error “Ya hay un objeto con el nombre ‘UserProfile’ en la base de datos.”

  14. November 15, 2012 at 8:35 am | #28

    Sorry the error in english is “There is already an object named ‘UserProfile’ in the database.”

    • Le
      November 15, 2012 at 5:01 pm | #29

      Hi txumari,

      You will can pass in false for the last parameter if your table already exists.

      
      WebSecurity.InitializeDatabaseConnection("MyDataContext", "User", "Id", "Username", false);
      
      
  15. Tariq
    November 15, 2012 at 5:35 pm | #30

    This post was a ‘SUPERGLUE’ for my work.
    Saved me many days of frustration.
    Thank you very very very much.
    May God Bless You.

    • Le
      November 15, 2012 at 5:46 pm | #31

      Hi Tarig, glad this helped and thanks for stopping by. :)

  16. November 16, 2012 at 5:27 pm | #32

    When i try to run i get the following error am i missing anything?
    You must call the “WebSecurity.InitializeDatabaseConnection” method before you call any other method of the “WebSecurity” class. This call should be placed in an _AppStart.cshtml file in the root of your site.

    I followed your steps

    • November 16, 2012 at 5:27 pm | #33

      Here is the actual error

      Running Seed method.
      System.InvalidOperationException: You must call the “WebSecurity.InitializeDatabaseConnection” method before you call any other method of the “WebSecurity” class. This call should be placed in an _AppStart.cshtml file in the root of your site.
      at WebMatrix.WebData.SimpleRoleProvider.get_PreviousProvider()
      at WebMatrix.WebData.SimpleRoleProvider.RoleExists(String roleName)
      at System.Web.Security.Roles.RoleExists(String roleName)
      at StreamingAdmin.Migrations.Configuration.Seed(StreamingDBContext context) in C:\Satish\StreamingAdmin\StreamingAdmin\Migrations\Configuration.cs:line 35
      at System.Data.Entity.Migrations.DbMigrationsConfiguration`1.OnSeed(DbContext context)
      at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
      at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
      at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
      at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
      at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
      at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
      at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
      at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
      You must call the “WebSecurity.InitializeDatabaseConnection” method before you call any other method of the “WebSecurity” class. This call should be placed in an _AppStart.cshtml file in the root of your site.

      • paablo
        November 28, 2012 at 1:51 am | #34

        Satish – did you every find a solution? I am having the same issue.

        • Faisal
          December 19, 2012 at 8:40 pm | #35

          satish, paablo: I had the same issue but sorted by adding the following line of code (same as in Configuration.cs) in Application_Start() method in my Global.asax.cs WebSecurity.InitializeDatabaseConnection(“DefaultConnection”, “Users”, “Id”, “UserName”, false);

  17. November 19, 2012 at 4:04 am | #36

    I try to pass the las paremeter false, but I get the same error. Furthermore if my database exists without the new field “email” and I put a “false” how can I update my database?

    • Le
      November 26, 2012 at 10:57 am | #37

      Hi txumari,

      For a sanity check could you please download and run the sample application just to validate that it works first?

  18. paablo
    November 25, 2012 at 3:41 am | #38

    I get the same “You must call the “WebSecurity.InitializeDatabaseConnection” method before you call any other method of the “WebSecurity” class. This call should be placed in an _AppStart.cshtml file in the root of your site.” if I try and seed users/roles inside my initiation method via Update-Database. This error does not appear if I remove the seeding code, and I already call the WebSecurity.InitializeDatabaseConnection method in my Global.asax.cs.

  19. grim
    November 25, 2012 at 10:40 am | #39

    Many thanks for this tutorial! It was very useful for me :)

    • Le
      November 26, 2012 at 10:58 am | #40

      Hi grim,

      I’m glad this was helpful, thanks for stopping by :)

  20. Jit
    November 26, 2012 at 5:03 am | #41

    The explanation refers to changing the ‘User’ table yet the code still refers to the ‘Userprofile’ table !!. So yes this will all work except when it comes to retrieveing the value of the additional profile fields. as this still points at the ‘Userprofile’ table which hasn’t been extended or populated !!.

    Example Code of Retrieving Profile Fied Values::

    if (oSettings.Alert_Required_Locations_Changes)
    {
    using (var context = new UsersContext())
    {
    var profile = context.UserProfiles.SingleOrDefault(x => x.UserName == User.Identity.Name);
    if (profile.Email.IsNotNullOrEmpty())
    {

    EMail.sendEmail(CONFIRM_LOCATION_REQUIRED, CONFIRM_CREATE_TO_BE_VALIDATED, profile.Email);
    }
    }
    }

    • Le
      November 26, 2012 at 11:00 am | #42

      Jit,

      Thanks you for sharing this.

  21. paablo
    November 28, 2012 at 1:36 am | #43

    Any Idea why I cannot apply this code example (that I can confirm works) to my own project? This is starting to drive me insane. Something so simple should not be this complicated. I can place the InitializeDatabaseConnection code more than once and it won’t throw the “InitializeDatabaseConnection has already been called” error. Really need help with this one.

    • Le
      November 28, 2012 at 1:51 am | #44

      Hi paablo,

      Could you first confirm that the sample application works before implementing this into your solution? After doing so let me know and I try to guide you to integrating it into your project.

  22. paablo
    November 28, 2012 at 1:53 am | #45

    Your sample app works fine. I am currently running it on the side of my project trying to work out the differences with no luck.

    • paablo
      November 28, 2012 at 1:58 am | #46

      I think my problem is that the “WebSecurity.InitializeDatabaseConnection” is simply not running. I can place 2 of them in my Seed method and still get the same error – where as two from the OOTB sample project give the “The “WebSecurity.InitializeDatabaseConnection” method can be called only once.”

  23. November 30, 2012 at 8:35 am | #48

    Hello!
    In the Configuration.cs the Role(f.e Role.RoleExists) does not exist in this context.
    Any ideas?

  24. onbermejo
    November 30, 2012 at 8:51 am | #49

    My answer to my question: using System.Web.Security in the Configuration.cs.

    Answer to the WebSecurity.InitializeDatabaseConnection error:
    Create _AppStart.cshtml file in the root and put only this code:ç

    @using WebMatrix.WebData;
    @{
    WebSecurity.InitializeDatabaseConnection(
    “Your_database”,
    “Your_table”,
    “UserId”,
    “UserName”, autoCreateTables: true);
    }

    Hope this helps

    • paablo
      November 30, 2012 at 9:21 am | #50

      Thanks for taking the time to help us out onbermejo.
      I hope your advice helped Oscar.
      Unfortunately adding the reference to _AppStart.html did not make a difference. WebSecurity.InitializeDatabaseConnection just does not seem to run at all. I can put it in twice and not get a “you can only call once” error. Anyone who solves this will be my hero!

      • onbermejo
        November 30, 2012 at 9:26 am | #51

        I don’t know, it’s working for me…
        I have followed the guide with the last update of the visual.

        Have you changed the webconfig?


        Have you done all the commands from Package Manager Console?

        • onbermejo
          November 30, 2012 at 9:27 am | #52

          AutomaticMigrationsEnabled = true;

          in the Configuration.cs?

          • paablo
            November 30, 2012 at 9:30 am | #53

            Yeah I have done all that stuff. There is more information on my stack overflow questions.
            Basically, if I hit debug, WebSecurity.InitializeDatabaseConnection is called as expected. If I run “Update-Database” it doesn’t seem to get called anywhere, hence the error.
            The only difference with my project really is that my project is split into a Domain and a WebUI project for the separate layers.

            • Oracularman
              December 1, 2012 at 11:51 am | #54

              After creating a new C# MVC4 application in VS 2012, for migrations and simplemembership, do the following

              1. Check the Connection String in the web.config. If using Machine\SQLExpress

              2. In Web.Config

              3. After PM> enable-migrations, in Configuration.cs

              #region

              using System;
              using System.Data.Entity;
              using System.Data.Entity.Migrations;
              using System.Linq;
              using System.Web.Security;
              using TSBVISTP.Models;
              using WebMatrix.WebData;
              using System.Collections.Generic;

              #endregion

              namespace TSBVISTP.Migrations
              {
              internal sealed class Configuration : DbMigrationsConfiguration
              {
              public Configuration()
              {
              AutomaticMigrationsEnabled = true;
              }

              protected override void Seed(STPDBContext context)
              {
              // This method will be called after migrating to the latest version.

              // You can use the DbSet.AddOrUpdate() helper extension method
              // to avoid creating duplicate seed data. E.g.
              //
              // context.People.AddOrUpdate(
              // p => p.FullName,
              // new Person { FullName = “Andrew Peters” },
              // new Person { FullName = “Brice Lambson” },
              // new Person { FullName = “Rowan Miller” }
              // );
              //
              WebSecurity.InitializeDatabaseConnection(“DefaultConnection”, “UserProfile”, “UserId”, “UserName”,
              autoCreateTables: true);
              if (!Roles.RoleExists(“Administrator”))
              Roles.CreateRole(“Administrator”);
              if (!WebSecurity.UserExists(“UserGA”))
              WebSecurity.CreateUserAndAccount(“UserGA”, “password”,
              new
              {
              FirstName = “User”,
              LastName = “GA”,
              userAddress = “123 something dr”,
              userCity = “Austin”,
              userZip = “78750″,
              WorkPhone = “512-555-5555″,
              AlternatePhone = “512-668-7898″,
              FaxNumber = “512-232-1212″,
              EmailAddress = “Simitt@gmail.com”
              }, false);
              if (!Roles.GetRolesForUser(“UserGA”).Contains(“Administrator”))
              Roles.AddUsersToRoles(new[] {“UserGA”}, new[] {“Administrator”});

              //var students = new List
              //{
              // new Student { FirstMidName = “Carson”, LastName = “Alexander”, EnrollmentDate = DateTime.Parse(“2005-09-01″) },
              // new Student { FirstMidName = “Meredith”, LastName = “Alonso”, EnrollmentDate = DateTime.Parse(“2002-09-01″) },
              // new Student { FirstMidName = “Arturo”, LastName = “Anand”, EnrollmentDate = DateTime.Parse(“2003-09-01″) },
              // new Student { FirstMidName = “Gytis”, LastName = “Barzdukas”, EnrollmentDate = DateTime.Parse(“2002-09-01″) },
              // new Student { FirstMidName = “Yan”, LastName = “Li”, EnrollmentDate = DateTime.Parse(“2002-09-01″) },
              // new Student { FirstMidName = “Peggy”, LastName = “Justice”, EnrollmentDate = DateTime.Parse(“2001-09-01″) },
              // new Student { FirstMidName = “Laura”, LastName = “Norman”, EnrollmentDate = DateTime.Parse(“2003-09-01″) },
              // new Student { FirstMidName = “Nino”, LastName = “Olivetto”, EnrollmentDate = DateTime.Parse(“2005-09-01″) }
              //};
              //students.ForEach(s => context.Students.Add(s));
              //context.SaveChanges();

              //var Staffs = new List
              //{
              // new Staff { FirstMidName = “Kim”, LastName = “Abercrombie”, HireDate = DateTime.Parse(“1995-03-11″) },
              // new Staff { FirstMidName = “Fadi”, LastName = “Fakhouri”, HireDate = DateTime.Parse(“2002-07-06″) },
              // new Staff { FirstMidName = “Roger”, LastName = “Harui”, HireDate = DateTime.Parse(“1998-07-01″) },
              // new Staff { FirstMidName = “Candace”, LastName = “Kapoor”, HireDate = DateTime.Parse(“2001-01-15″) },
              // new Staff { FirstMidName = “Roger”, LastName = “Zheng”, HireDate = DateTime.Parse(“2004-02-12″) }
              //};
              //Staffs.ForEach(s => context.Staffs.Add(s));
              //context.SaveChanges();

              //var departments = new List
              //{
              // new Department { Name = “English”, Budget = 350000, StartDate = DateTime.Parse(“2007-09-01″), PersonId = 9 },
              // new Department { Name = “Mathematics”, Budget = 100000, StartDate = DateTime.Parse(“2007-09-01″), PersonId = 10 },
              // new Department { Name = “Engineering”, Budget = 350000, StartDate = DateTime.Parse(“2007-09-01″), PersonId = 11 },
              // new Department { Name = “Economics”, Budget = 100000, StartDate = DateTime.Parse(“2007-09-01″), PersonId = 12 }
              //};
              //departments.ForEach(s => context.Departments.Add(s));
              //context.SaveChanges();

              //var programs = new List
              //{
              // new Program { ProgramId = 1050, Title = “ASE”, Credits = 3, DepartmentId = 3, Staffs = new List() },
              // new Program { ProgramId = 4022, Title = “ESC2″, Credits = 3, DepartmentId = 4, Staffs = new List() },
              // new Program { ProgramId = 4041, Title = “SWEAT”, Credits = 3, DepartmentId = 4, Staffs = new List() },
              // new Program { ProgramId = 1045, Title = “ESE”, Credits = 4, DepartmentId = 2, Staffs = new List() },
              // new Program { ProgramId = 3141, Title = “ASE2″, Credits = 4, DepartmentId = 2, Staffs = new List() },
              // new Program { ProgramId = 2021, Title = “SWT”, Credits = 3, DepartmentId = 1, Staffs = new List() },
              // new Program { ProgramId = 2042, Title = “ABC”, Credits = 4, DepartmentId = 1, Staffs = new List() }
              //};
              //programs.ForEach(s => context.Programs.Add(s));
              //context.SaveChanges();

              //programs[0].Staffs.Add(Staffs[0]);
              //programs[1].Staffs.Add(Staffs[1]);
              //programs[2].Staffs.Add(Staffs[2]);
              //programs[3].Staffs.Add(Staffs[2]);
              //programs[4].Staffs.Add(Staffs[3]);
              //programs[5].Staffs.Add(Staffs[3]);
              //programs[6].Staffs.Add(Staffs[3]);
              //programs[7].Staffs.Add(Staffs[3]);
              //context.SaveChanges();

              //var enrollments = new List
              //{
              // new Enrollment { PersonId = 1, ProgramId = 1050, Grade = 1 },
              // new Enrollment { PersonId = 1, ProgramId = 4022, Grade = 3 },
              // new Enrollment { PersonId = 1, ProgramId = 4041, Grade = 1 },
              // new Enrollment { PersonId = 2, ProgramId = 1045, Grade = 2 },
              // new Enrollment { PersonId = 2, ProgramId = 3141, Grade = 4 },
              // new Enrollment { PersonId = 2, ProgramId = 2021, Grade = 4 },
              // new Enrollment { PersonId = 3, ProgramId = 1050 },
              // new Enrollment { PersonId = 4, ProgramId = 1050, },
              // new Enrollment { PersonId = 4, ProgramId = 4022, Grade = 4 },
              // new Enrollment { PersonId = 5, ProgramId = 4041, Grade = 3 },
              // new Enrollment { PersonId = 6, ProgramId = 1045 },
              // new Enrollment { PersonId = 7, ProgramId = 3141, Grade = 2 },
              //};
              //enrollments.ForEach(s => context.Enrollments.Add(s));
              //context.SaveChanges();

              //var officeAssignments = new List
              //{
              // new ClassAssignment { PersonID = 9, Location = “Class 1″ },
              // new ClassAssignment { PersonID = 10, Location = “Class 27″ },
              // new ClassAssignment { PersonID = 11, Location = “Class 304″ },
              //};
              //officeAssignments.ForEach(s => context.OfficeAssignments.Add(s));
              //context.SaveChanges();

              var menus = new List
              {
              new Menu {Id = 1, Name = “Main”, MenuItems = new List()},

              };
              menus.ForEach(s => context.Menus.Add(s));
              context.SaveChanges();

              var menuitems = new List
              {
              new MenuItem
              {
              Id = 1,
              Name = “Home”,
              ActionName = “Index”,
              ControllerName = “Home”,
              Url = “”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 2,
              Name = “Student”,
              ActionName = “Index”,
              ControllerName = “Student”,
              Url = “”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 3,
              Name = “Staff”,
              ActionName = “Index”,
              ControllerName = “Staff”,
              Url = “”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 4,
              Name = “Programs”,
              ActionName = “Index”,
              ControllerName = “Program”,
              Url = “”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 5,
              Name = “Residential”,
              ActionName = “Index”,
              ControllerName = “Department”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 6,
              Name = “About”,
              ActionName = “About”,
              ControllerName = “Home”,
              Url = “”,
              ParentMenu = menus[0]
              },
              new MenuItem
              {
              Id = 7,
              Name = “Contact”,
              ActionName = “Contact”,
              ControllerName = “Home”,
              Url = “”,
              ParentMenu = menus[0]
              },
              };
              menuitems.ForEach(s => context.MenuItems.Add(s));
              context.SaveChanges();

              }
              }
              }

              4. update-database -verbose

              5. In SQL run update query to add columns

              GO
              ALTER TABLE [dbo].[UserProfile]
              ADD [FirstName] VARCHAR (50) NULL,
              [LastName] NVARCHAR (50) NULL,
              [userAddress] NVARCHAR (50) NULL,
              [userCity] NVARCHAR (50) NULL,
              [userZip] NVARCHAR (50) NULL,
              [WorkPhone] NVARCHAR (50) NULL,
              [AlternatePhone] NVARCHAR (50) NULL,
              [FaxNumber] NVARCHAR (50) NULL,
              [EmailAddress] NVARCHAR (50) NULL;

              6. PM> update-database -verbose

              you must see migrations working.now.

              • Oracularman
                December 1, 2012 at 11:54 am | #55

                Some content got eaten up above.

                2. In Web.Config

                and

  25. Oracularman
    December 1, 2012 at 11:56 am | #56

    The code works great. All I have to do is alter the userprofile table to add the additional columns and then re-run PM>update-database -verbose and the seed data gets in.

  26. paablo
    December 1, 2012 at 11:13 pm | #57

    I managed to fix the problem I was having. My project was referencing the wrong version of WebMatrix.WebData

    • Le
      December 2, 2012 at 1:05 am | #58

      paablo, yey….! I was worried there wasn’t a solution for your issue :)

    • onbermejo
      December 2, 2012 at 4:45 am | #59

      Congrats!

  27. December 2, 2012 at 2:12 am | #60

    Hi Le! Excellent Work! can I ask, what if I need another role, and the administrator can change its (the new record one) role?

    • Le
      December 2, 2012 at 3:30 am | #61

      Thanks twisttwist, are you asking how you can change a user’s role?

  28. K. Gutzeit
    December 8, 2012 at 5:01 am | #62

    Excelent Tutorial!!

    Best regards from Germany
    Kai G.

    • Le
      December 12, 2012 at 12:03 pm | #63

      Vielen Dank für Ihren Besuch! :)

  29. December 12, 2012 at 5:35 am | #64

    how to do this with custom membership
    i.e

    –>

    where CustomMembership.Providers.Custom2 is

    public class Custom2 : WebMatrix.WebData.ExtendedMembershipProvider
    {
    // implemenet here
    }

    I tried but getting error

  30. Faisal
    December 19, 2012 at 8:45 pm | #65

    Great work Le
    Many Thanks

    • Le
      December 19, 2012 at 8:50 pm | #66

      Sure thing, thanks for stopping by :)

  31. December 21, 2012 at 11:08 am | #67

    Great article but I also run into a problem where the Package Manager Console tells me that “To call this method, the “Membership.Provider” property must be an instance of “ExtendedMembershipProvider”.”

    Which is strange to me because I believe this happens when you call a method that you’re not supposed to from SimpleMembership. This happens when I do the update-database. I have nothing special in the Configuration file, just checking if some Role and User exist, and if not create them. Any idea?

  32. aro
    January 2, 2013 at 11:51 pm | #68

    the download is gone!

  33. January 3, 2013 at 5:31 am | #70

    Hello Le, Great Tutorial,

    I have a problem though. In your code example, you don’t declare your SimpleRoleProvider anywhere for the Seed method?

    So for me, the object Roles doesnt exist? what am i doing wrong?

    • dyk3r5
      January 3, 2013 at 10:40 am | #71

      I’ve solved that issue, but I get the same fault as paablo, even after referencing the version 2.0 of the WebMatrix.WebData.dll????

      • January 4, 2013 at 5:20 am | #72

        I’ve since figured this, Ive had to reference :-

        using System;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
        using WebMatrix.WebData;
        using WebMatrix.Data;
        using System.Web;

        • Le
          January 8, 2013 at 1:26 pm | #73

          Thanks for sharing this!

  34. Tim
    January 3, 2013 at 3:25 pm | #74

    Anyone know where you configure the simplemembership (for password format etc?) is it to be done in web.config like before?

  35. lalberto
    January 6, 2013 at 11:06 am | #75

    Hi this post has been really helpful, but i have a problem, I need to set up the membership and roles using a ModelFirst DB on another project on my solution and my Context is there so im not able to use migrations and when i try to initialize the web security it thows InvalidOperationException teling me that it can only be called once and if I delete de DB to crate it later it works but then the Role manager doesn’t work. I did every thing like you said but no results what do you think it might be

    • Le
      January 8, 2013 at 1:27 pm | #76

      You may want to take a look at Filters/InitializeSimpleMembershipAttribute.cs, it’s being called there as well if this is an MVC 4 project.

  36. Leo
    January 19, 2013 at 9:52 am | #77

    Hi Le,

    I’ve read your article and it helped me a lot to get started with SimpleMembership. I’ve managed to implement SimpleMembership from scratch into a ASP.NET MVC 4 Basic Application, but I have a little issue yet.

    The problem is that to implement SimpleMembership I needed to use the InitializeSimpleMembershipAttribute that comes with the ASP.NET MVC 4 Internet Application and I’m not finding a cool way to use this with the Repository Pattern because it directly references one specific Context and specific name of table for users.

    Then at first I have two options: the first option is that on every single project I copy the Filter and change the configuration, directly referencing the context (which is not good, since I want to use repository pattern and interact with the context through the repository).

    The second option, I’ve tryed to generalize the filter to any context, passing it to the filter as a Type object, but it again directly references the context.

    Is there any better way to work with SimpleMembership and Repository Pattern in such a way that we get a good generalization, at the point that we can even move the filter to a separate assembly and reference it in any project ?

    Sorry if my question is silly, but I’m beginner with ASP.NET MVC and SimpleMembership and I’m still struggling with such issues.

    Thanks again for the article, your help and attention.

  37. January 20, 2013 at 11:47 pm | #78

    Hi Le,

    Sorry if this is to basic but I’m new at this. On the first part of your tutorial ->
    “In the “System.Web” Section add:”

    How do you add code to the System. Web.

    Thanks,

    Mark

    • January 21, 2013 at 12:07 pm | #79

      Hi Le,
      I was looking at the sample and I see that you added the coded in the Web.config file. I got it.

      Thanks,

      Mark

      • Le
        January 22, 2013 at 3:58 pm | #80

        Awesome, glad you found it!

  38. January 22, 2013 at 6:13 pm | #81

    Hi le,
    Great tutorial, I got it running fast. I was wondering what do I need to do if I wanted to create a second role such as clients? Would it be with a dupplicate of the code in the web system.web

    and another basic question :) remember I’m new at this.

    You would use [Authorize] to allow regular users to that part of the code. How would you use the Administrator. would it be [Administrator]?

  39. January 22, 2013 at 6:24 pm | #82

    Hi Le,

    Sorry but I can keep answering my questions. The duplicate on the code worked. Should have tried before.

    The only thing pending is the [Administrator] not sure how to approach this.

    Thanks,

    Mark

  40. January 22, 2013 at 8:04 pm | #83

    Got it [Authorize( Roles="Administrator" ) ]

    Great tutorial.

    • Le
      January 23, 2013 at 4:08 am | #84

      Awesome!

      • January 25, 2013 at 11:15 pm | #85

        Hi Lee,
        I’m know is not part of this tutorial but i was wondering if you can point me in the right direction. I would like to show only part of the menu if the person does not have the right roles. Sorry if this post does not belong here.

        Thank you

        • January 26, 2013 at 12:22 am | #86

          Seems like all I have to do is ask and then It comes to me.. Sorry about that.

          • Le
            January 28, 2013 at 8:38 pm | #87

            Glad you found your solution!

  41. yust
    February 3, 2013 at 5:35 am | #88

    download link is dead. anyone still got the project?

    • February 3, 2013 at 11:24 am | #89

      Look at comment #69 it has the link, I just got it from there a few day ago.

  42. Taz
    February 6, 2013 at 7:14 am | #90

    Hi,

    In you example, how you added the new field for Mobile data, how can you add this into the Manage action so the user can update that details freely?

  43. February 19, 2013 at 10:50 pm | #91

    Long Le …
    u r awessome

    • Le
      February 20, 2013 at 12:43 pm | #92

      bilalfazlani, thanks for the positive feedback. :)

  44. Ólafur
    February 28, 2013 at 2:56 pm | #93

    Good post!

    • Le
      February 28, 2013 at 11:55 pm | #94

      thanks Olafur for the positive feedback!

  45. User123
    March 7, 2013 at 9:30 am | #95

    Hello!
    Thank you for this post – it was really helpful to me. Saved me a lot of time and nerve. :)
    Thank you!

    But, if we wanna add more “atributes” in dB, for example: BirthDate, LastName, FirstName ,… How to do that?
    I did try like adding the same way u add in your example PhoneNumber:

    AccountModel.cs
    …..
    [Table("UserProfile")]
    public class UserProfile
    {
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UserEmail { get; set; }
    ……..

    Configuration.cs

    if (!WebSecurity.UserExists(“user123″))
    WebSecurity.CreateUserAndAccount(
    “user123″,
    “123456″,
    new { FirstName = “John” },
    new { LastName = “Kent” },
    new { UserEmail = “example@example.com” });
    …….
    But iv got error:
    “No overload for method ‘CreateUserAndAccount’ takes 5 arguments” – what I have to do that this code work?

  46. March 12, 2013 at 8:48 am | #96

    Hi Le
    thanks a million for your post, it was so helpfull. However i would like to ask you, if there is a way instead of adding fields to the Userprofile table to save information in fields in another table (for example a custom table or the webpages_membership table).

    I added 2 new fields (first name and last name) in the webpages_Membership table, sumbittted them with migrations, but saving them is not possible since they cannot be saved directly with the model.firstname since they are not in the UserProfile table.

    Any ideas?

    Again thanks for the awsome post!

    Tolis

  47. March 17, 2013 at 11:59 pm | #97

    Hi Long,

    Very nice article.
    Your SKYDRIVE download is no longer available though.
    Might I have a copy ?

    Best, LA Guy

    • Le
      March 20, 2013 at 10:56 pm | #98

      there is a link to it in the one of the comments! :)

  48. yust
    March 31, 2013 at 5:32 pm | #99

    Hi,

    Great tut!

    Suppose i want to add a table, How would i do that? I already tried to set up a table like the user profile, and did the update-database command. But at no avail…

  49. taanak
    April 3, 2013 at 3:21 pm | #100

    Hi. Thank you very much! I’ve spent 3 days on this task until I found your article. I had the same problem as txumari, but I think the reason was due to using default database before manipulations with it. There are no errors in a new created project !!!

  50. T
    April 10, 2013 at 12:28 am | #101

    Le, many thanks – you have provided the most concise example of how to set up forms based security that I have found, saving a great deal of time.

    For those that have had issues such as Satish and Txumari – I experienced both of your problems. The root problem seems to be setting up the visual studio 2010 Server Explorer to look at the database.

    Following Le’s outline with out running Server explorer all works. However, depending on when you set up the Server Explorer I hit either Satish or Txumair’s issues. Simply put: Do not use Server Explorer with SQL Express in this example.

    One other small point, I did have to use SQL 2008 express configuration manager to enable a user of the form hostname\username. That is your laptop network name and your sign on name. This eliminated the error that demanded the database be initialized prior to use.

    Once again, many thanks
    T

    • Le
      April 20, 2013 at 7:27 pm | #102

      Thanks T for the tip! Had similar issues using SQL Express.

  51. April 30, 2013 at 5:01 pm | #103

    Reblogged this on Anthony Trimble.

  52. yust
    May 5, 2013 at 10:46 am | #105

    hi,

    How do you move all database operations to a class library project? I’ve come far, but the webpages_roles etc are not created in the database.

    • Le
      May 6, 2013 at 10:14 am | #106

      Not sure I understand what you mean by move all database operations to a class library? Also please download the sample solution and make sure it runs correctly, webpages_roles should be created. You may want to start with a fresh new empty database first and run the project.

      • yust
        May 9, 2013 at 2:55 am | #107

        What i meant was, that i enabled migrations in a class library project. i’m trying to seperate database access and the web site. so i moved websecurity etc too. i also created a datacontext class. the problem i’m facing right now, is that ‘Roles’ doesn’t excist in the current context. Even though i added System.Web.Security. which is the namespace of it. Anything else i might be missing?

        • yust
          May 9, 2013 at 11:24 am | #108

          never mind, i didn’t referenced system.web in the project. somehow i thought i did.

  53. May 6, 2013 at 12:23 am | #109

    Great Article Le.

  54. Sam
    May 6, 2013 at 2:40 am | #111

    Oops. I wanted to add …. I’ve tried your solution out and it works. I thought I would try adding some additional model classes and context class. I found that EF Add-Migration doesn’t see the new model classes and pops up with the changes being empty. Is there something with multiple DBcontexts that I am implementing incorrectly?

    Cheers.

    • Le
      May 6, 2013 at 10:11 am | #112

      Sam,

      You need to make sure you have all your Entity Framework mapping classes implemented and these mapping classes need to be registered and added in the YourDbContext.OnModelCreating(DbModelBuilder builder) event.

      Example:

      
              protected override void OnModelCreating(DbModelBuilder builder)
              {
                  builder.Conventions.Remove<PluralizingTableNameConvention>();
                  builder.Configurations.Add(new DataAuditMap());
                  builder.Configurations.Add(new LogMap());
                  builder.Configurations.Add(new LogLevelMap());
      
                  base.OnModelCreating(builder);
              }
      
      
      
  55. Sam
    May 6, 2013 at 3:42 am | #113

    I refactored the UsersContext to hold any additional application entities and that works. I just learned migrations can be on for only one context in a project. Unless you have any insight. Thanks again.

    • Le
      May 6, 2013 at 10:09 am | #114

      Sam, you need to run migrations while explicitly specifying which context you are running it for, you can actually do migrations for more than one context.

      example: (from the package manager console):

      update-database -ConfigurationTypeName “”

  56. Sam
    May 6, 2013 at 2:46 pm | #115

    Thanks Le! I had come across that before in another MVC project with multiple contexts and required only one context to be part of migrations. The console is really good about the error message about multiple contexts also.

    I was trying to migrate two contexts in the same project and the console states migrations can be on for only one context in a project.

    This whole experiment was to work out the kinks integrating simpleMemberhship and some usefull application data as well.

    Again, great article which provides another vector to possible solutions :-)

  57. May 12, 2013 at 5:19 pm | #116

    thanks for this – skydrive link is now dead?!

  58. May 12, 2013 at 5:48 pm | #124

    Is it the file starting ‘building a composite mvc3….’?

    That doesn’t seem right as I know SimpleMembership changed a lot between MVC3 & 4 no?

  59. Reiterer
    May 17, 2013 at 10:24 am | #125

    Thank you, that was very helpful :)

  1. September 26, 2012 at 1:50 am | #1
  2. October 10, 2012 at 6:35 am | #2
  3. November 4, 2012 at 1:19 am | #3
  4. December 19, 2012 at 7:24 pm | #4
  5. January 6, 2013 at 5:42 pm | #5
  6. April 1, 2013 at 1:01 pm | #6
  7. April 6, 2013 at 4:41 am | #7

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 124 other followers

%d bloggers like this: