ASP.NET MVC Example

Apr 8, 2011 at 11:37 PM

This is a great library! Thank you for your effort!  Will you create a simple MVC sample that uses this library? Also it will be good to have a simple example of how to upgrage the current MVC app that uses the old ASP.NET membership provider?  Thanks.

Coordinator
Apr 9, 2011 at 11:41 AM

Hi @JayKnowsit. Thanks for the kind comments. As requested, I have just created a sample MVC app that utilises the old membership provider (AspNetSqlMembershipProvider) that comes with Visual Studio and then replaced it with MRPLibrary. The sample can be found in the Downloads page. The main changes are in the web.config as shown below:

    <!--<membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
             enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
             maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
             applicationName="/" />
      </providers>
    </membership>

    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </profile>

    <roleManager enabled="false">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>-->


    <membership defaultProvider="mainMembershipProvider">
      <providers>
        <clear/>
        <add  name="mainMembershipProvider"
    type="AspAuthentication.Providers.PortalMembershipProvider"
    connectionStringName="ApplicationServices"
    enablePasswordRetrieval="false"
    enablePasswordReset="true"
    requiresQuestionAndAnswer="false"
    requiresUniqueEmail="false"
    maxInvalidPasswordAttempts="5"
    minRequiredPasswordLength="6"
    minRequiredNonalphanumericCharacters="0"
    passwordAttemptWindow="10"
    applicationName="/"
    passwordFormat="Hashed"
    createDatabaseObjects="true"
  />
      </providers>
    </membership>
    <profile enabled="true" defaultProvider="mainProfileProvider">
      <providers>
        <clear/>
        <add  name="mainProfileProvider"
    type="AspAuthentication.Providers.PortalRoleProvider, AspAuthentication" connectionStringName="ApplicationServices"
    applicationName="/"
    createDatabaseObjects="true"
  />
      </providers>
    </profile>
    <roleManager enabled="true" defaultProvider="mainRoleProvider">
      <providers>
        <clear/>
        <add  name="mainRoleProvider"
    type="AspAuthentication.Providers.PortalRoleProvider, AspAuthentication"
    connectionStringName="ApplicationServices"
    applicationName="/"
    createDatabaseObjects="true"
  />
      </providers>
    </roleManager>

Apr 9, 2011 at 4:27 PM

Thanks for your response. I changed the connection string as follows:

<

add name="ApplicationServices "connectionString="data source=.;Integrated Security=SSPI;Initial Catalog=aspnetef;MultipleActiveResultSets=true; Persist Security Info=true" providerName="System.Data.SqlClient" />

I changed the database name from aspnetdb to aspnetef.  I am getting a MembershipCreateStatus.ProviderError. The database is not created.  Do you know what is thproblem?

Coordinator
Apr 9, 2011 at 5:40 PM

hi @JayKnowsit,

First of all does that database exist? I intentionally designed the library not to create the database just the necessary objects i.e tables.

Apr 9, 2011 at 10:08 PM

Sorry, I  am used to the code first.  Since this library uses the codefirst, I assumed that it would create the database, if not exist.

How can I enable the auto-creation of the database?

Apr 9, 2011 at 10:39 PM

It works great when I use the exising aspnetdb database.  In a new development senario, it would be nice if we can create the database with initial seeds.

Coordinator
Apr 9, 2011 at 11:27 PM
Edited Apr 9, 2011 at 11:28 PM

There is no way to auto create the database with the library. I envisaged that the library will be utilised within a solution that already defines a the database. If you really need the library to support creating a database when it none exist, I can compile a special version for you. In one of the projects i am currently working on, I am actually using the library as it it to seed the database on application start. Code sample below. Persistence.DomainContext is a class that inherits DbContext in EntityFramework. You can actually just replace it with DbContext.

       protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            SetupDefaultUsers();
        }

       private static void SetupDefaultUsers()
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<Persistence.DomainContext>());
            using (var context = new Persistence.DomainContext("ApplicationServices"))
            {
                context.SaveChanges();
            }

            var securityCop = new SecurityCop
            {
                FormsGateKeeper = new UserFormsAuthentication()
            };

            CreateRole(securityCop, "User");

            const string user = "someuser";
            CreateUser(securityCop, user);
            AddUserToRole(securityCop, user, "User");
        }

        private static void AddUserToRole(ISecurityCop securityCop, string username, string rolename)
        {
            if (!securityCop.PortalRoleProvider.IsUserInRole(username, rolename))
            {
                securityCop.PortalRoleProvider.AddUsersToRoles(new[] { username },
                                                           new[] { rolename });
            }
        }

        private static void CreateRole(ISecurityCop securityCop, string roleName)
        {
            if (!securityCop.PortalRoleProvider.RoleExists(roleName))
            {
                securityCop.PortalRoleProvider.CreateRole(roleName);
            }
        }

        private static void CreateUser(ISecurityCop securityCop, string username)
        {
            int totalRecords;
            securityCop.PortalMembershipProvider.FindUsersByName(username, 0, 1, out totalRecords);
            if (totalRecords == 0)
            {
                MembershipCreateStatus status;
                securityCop.PortalMembershipProvider.CreateUser(username,
                    "somevalue",
                    string.Format("{0}@somevalue.com", username),
                    out status);
            }
        }
    

 Hope this is helpful.

Apr 10, 2011 at 12:29 AM

If the solution is already deployed and working fine, I might want to keep it as is.  Howver, if I am starting the new app, I will definitely start with this library.  In that case, a data initializer with some seeds would be very useful.   I was thinking about an initialzer class that inherit DropDatabaseIfModelChanges<ASPNEDDBContext> and overiding Seed method.  Typical sample data may include administrator, contributor, moderator, verifiedmember, member, and guest,  Verified members usually have profile data.  Does this libary use a table-based profile instead of a property-based profile?  Thanks.

Coordinator
Apr 10, 2011 at 1:29 PM
Edited Apr 10, 2011 at 1:30 PM

After thinking about your suggestions, I am convinced that they are valid and I will be including them in the next release: the ability to create the database if it does not exist and seed data (especially roles in the solution). I will start work on this this week. The library does support user  profile creation. I assume by property-based profile you mean a variable (almost like a name - value pair) list of data associated to a user as opposed to a fixed data structure. if this is correct then yes the library uses a property-base profile. Each profile can have as many or little data as required by the solution.

Apr 10, 2011 at 3:29 PM

This is great.  By property based profile provider, I meant the old implementation of profile provider as a blob storage provider. Storing the profile data in a column as a blob limits our ability to make richer queries on the back-end for your personalization data. Rather than restating the issue, here is some links that explains and resolve the issue.  Thanks.
1. http://www.eggheadcafe.com/articles/20060731.asp
2. http://www.asp.net/downloads/sandbox/table-profile-provider-samples

Coordinator
Apr 12, 2011 at 11:29 AM

MRPLibrary does not use the blob approach. The way i implemented it is kind of similar to the first link you provided. However, rather than restrict you to a fixed sets of columns, I designed it that each user will have a profile and the profile can have zero to many profileItems. ProfileItems (Id- used by the library, Name, Values, ProfileUsername- foreignKey to the username). The important properties are the Name and Value. So a use can have as many of these as required. You really don't need to worry about this structure as the library then exposes this to you via the ProfileProvider pattern. However, based on this implementation, you can have the rich queries you talked about earlier. In addition, if you decide to actually get the library's internal object structure i.e Profile and ProfileItem objects, you can do build some intersting stuff. The Profile provider model hides most of these but if for example you got the profile provider from ASP and then cast it to the library's IPortalProfileProvider then you can execute the following statement to retrieve the profile for a user:

            //_provider is the profile provider retrieved from ASP Profile Manager
            var profileManager = (IPortalProfileProvider)_provider;
            Profile userProfile = profileManager.UnitOfWork.Search<Profile>(p => p.Username == "someusername").FirstOrDefault();
            if (userProfile != null)
            {
                //now lets loop through all the profile items for the user
                foreach (ProfileItem profileItem in userProfile.ProfileData)
                {
                    string name = profileItem.Name;
                    string value = profileItem.Value;
                }
            }

Hope that was useful

Apr 12, 2011 at 5:31 PM
Edited Apr 13, 2011 at 7:04 AM

Excellent.  I feel like a kid in a candy store.  This also gives an opportunity to integrate it with a custom Windows Identity Foundation(WIF) Security Token Service.  You have been a great help.  Thanks.

 

Sep 10, 2011 at 6:21 AM

I wanted to try the MVC sample this week.  However, I could not open it in the visual stio becuase the web project does not use IISExpress but IIS.

Can you post the MVC sample with IISExpress or Development web server?  I am trying to add some admin pages that allow CRUD operation on memberhip, roles, and profile.

Thanks in advance. 

PS) I heard that Microsoft released a universal asp.net provider. (Scott Hanselman had a blog post.  Did you have a change to reviewit?

Coordinator
Sep 10, 2011 at 8:56 AM

Hi @JayKnowsit sorry to hear you had an issue opening the sample. However, I did check the sample and it actually uses IISExpress.

Nevertheless, I went ahead this morning and added a second sample that does not use IISExpress (change set : fa957e086d5c).

Although you can download the sample from the source code tab of this page, I have just zipped the entire solution (Solution with Samples) and added it to the download section. To open the solution, I think you will need a non-express

version of Visual Studio. But you should be open idividual projects with express anyhow. Let me know if it is still a problem opening the solution.

It should be very easy to add the CRUD operations you talked about and remember you can actually add roles right from the config like you requested the last time.

I think the universal provider is interesting. I was actually planning to support SQL Compact. The SQL Azure part is really good.

hope this is helpful.