Nibble

Contour 3.0 Code First, Member registration, profile, login, change password

The upcoming Contour 3.0 release features a new code first framework that is outlined in this post on umbraco.com

To add some more examples I’ve updated the example with some additional member forms:

Profile form

using System;
using System.Collections.Generic;
using Umbraco.Forms.CodeFirst;
using Umbraco.Forms.Core.Providers.FieldTypes;
using umbraco.cms.businesslogic.member;
 
namespace Contour.CodeFirstExample
{
    [Form("Member/Profile", ShowValidationSummary = true, MessageOnSubmit = "Profile updated!")]
    public class Profile: FormBase
    {
        [Field("Profile", FormFieldsets.Details,
            Mandatory = true,
            DefaultValue = "{member.name}")]
        public string Name { get; set; }
 
        [Field("Profile", FormFieldsets.Details,
            Mandatory = true,
            Regex = @"(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})",
            DefaultValue = "{member.email}")]
        public string Email { get; set; }
 
        [Field("Profile", FormFieldsets.Details,
            Type = typeof(FileUpload),
            DefaultValue = "{member.avatar}")]
        public string Avatar { get; set; }
 
        public override IEnumerable<Exception> Validate()
        {
            var e = new List<Exception>();
 
            var m = Member.GetCurrentMember();
 
            if (m != null)
            {
                if (m.Email != Email)
                {
                    if (Member.GetMemberFromLoginName(Email) != null)
                        e.Add(new Exception("Email already in use"));
                }
            }
 
            return e;
 
        }
 
        public override void Submit()
        {
            var m = Member.GetCurrentMember();
 
            if (m != null)
            {
                m.Email = Email;
                m.LoginName = Email;
                m.Text = Name;
                //asign custom properties
                if (!string.IsNullOrEmpty(Avatar))
                    m.getProperty("avatar").Value = Avatar;
            }
        }
    }
}

 

Change password form

using System;
using System.Collections.Generic;
using Umbraco.Forms.CodeFirst;
using Umbraco.Forms.Core.Providers.FieldTypes;
using umbraco.cms.businesslogic.member;
 
namespace Contour.CodeFirstExample
{
    [Form("Member/Change password", ShowValidationSummary = true, MessageOnSubmit = "Password updated!")]
    public class ChangePassword: FormBase
    {
        [Field("Change password", "",
            Type = typeof(Password),
            Mandatory = true)]
        public string Password { get; set; }
 
        [Field("Change password", "",
            Type = typeof(Password),
            Mandatory = true)]
        public string RepeatPassword { get; set; }
 
        public override IEnumerable<Exception> Validate()
        {
            var e = new List<Exception>();
         
            //makes sure the passwords are identical
            if (Password != RepeatPassword)
                e.Add(new Exception("Passwords must match"));
 
            return e;
        }
 
        public override void Submit()
        {
            var m = Member.GetCurrentMember();
 
            if(m != null)
                m.Password = Password;
        }
    }
}

 

Login form

using System;
using System.Collections.Generic;
using Umbraco.Forms.CodeFirst;
using Umbraco.Forms.Core.Providers.FieldTypes;
using umbraco.cms.businesslogic.member;
 
namespace Contour.CodeFirstExample
{
    [Form("Member/Login", ShowValidationSummary = true, MessageOnSubmit ="You are now logged in")]
    public class Login: FormBase
    {
        [Field("Login", "",
           Mandatory = true,
           Regex = @"(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})")]
        public string Email { get; set; }
 
        [Field("Login", "",
            Type = typeof(Password),
            Mandatory = true)]
        public string Password { get; set; }
 
 
        public override IEnumerable<Exception> Validate()
        {
            var e = new List<Exception>();
 
            if(Member.GetMemberFromLoginName(Email) == null)
                e.Add(new Exception("No member found with that email address"));
            else if (Member.GetMemberFromLoginNameAndPassword(Email, Password) == null)
                e.Add(new Exception("Incorrect password"));
 
            return e;
        }
 
        public override void Submit()
        {
           var m = Member.GetMemberFromLoginNameAndPassword(Email, Password);
           if (m != null)
               Member.AddMemberToCache(m);
        }
    }
}

 

Registration form

using System;
using System.Collections.Generic;
using Umbraco.Forms.CodeFirst;
using umbraco.cms.businesslogic.member;
using umbraco.BusinessLogic;
using Umbraco.Forms.Core.Providers.FieldTypes;
 
namespace Contour.CodeFirstExample
{
    
    public enum FormPages
    {
        Registration
    }
 
    public enum FormFieldsets
    {
        Details
    }
 
    [Form("Member/Registration", ShowValidationSummary = true, MessageOnSubmit="You are now registered!")]
    public class Registration: FormBase
    {
        public const string MemberTypeAlias = "Member";
        public const string MemberGroupName = "Authenticated";
 
        [Field(FormPages.Registration,FormFieldsets.Details,
            Mandatory= true)]
        public string Name { get; set; }
 
        [Field(FormPages.Registration, FormFieldsets.Details,
            Mandatory = true,
            Regex = @"(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})")]
        public string Email { get; set; }
 
        [Field(FormPages.Registration, FormFieldsets.Details, 
            Type = typeof(Password),
            Mandatory = true)]
        public string Password { get; set; }
 
        [Field(FormPages.Registration, FormFieldsets.Details, 
            Type = typeof(Password),
            Mandatory = true)]
        public string RepeatPassword { get; set; }
 
        [Field(FormPages.Registration, FormFieldsets.Details, 
            Type = typeof(FileUpload))]
        public string Avatar { get; set; }
 
        public override IEnumerable<Exception> Validate()
        {
            var e = new List<Exception>();
            //checks if email isn’t in use
            if(Member.GetMemberFromLoginName(Email) != null)
                e.Add(new Exception("Email already in use"));
            //makes sure the passwords are identical
            if (Password != RepeatPassword)
                e.Add(new Exception("Passwords must match"));
 
            return e;
        }
        public override void Submit()
        {
            //get a membertype by its alias
            var mt = MemberType.GetByAlias(MemberTypeAlias); //needs to be an existing membertype
            //get the user(0)
            var user = new User(0);
            //create a new member with Member.MakeNew
            var member = Member.MakeNew(Name, mt, user);
            //assign email, password and loginname
            member.Email = Email;
            member.Password = Password;
            member.LoginName = Email;
            //asign custom properties
            if(!string.IsNullOrEmpty(Avatar))
                member.getProperty("avatar").Value = Avatar;
            //asssign a group, get the group by name, and assign its Id
            var group = MemberGroup.GetByName(MemberGroupName); //needs to be an existing MemberGroup
            member.AddGroup(group.Id);
            //generate the member xml with .XmlGenerate
            member.XmlGenerate(new System.Xml.XmlDocument());
            //add the member to the website cache to log the member in
            Member.AddMemberToCache(member);
            
        }
    }
}

The code assumes there is a membertype called Member with a additional property with the alias avatar and a membergroup called Authenticated

For more member properties the code needs to be updated…

After deploying you should end up with the following forms

image

Full sourcecode is available here

28 Comments so far

  1. Shannon on November 30th, 2012

    With this solution would you not then be storing all you users password in plain text?

  2. Tim Geyssens on November 30th, 2012

    @Shannon nope

  3. martin on December 4th, 2012

    Is it possible to use this pattern with custom fieldtypes like the re-captcha in contour contrib? Or is it limited only to core fieldtypes?

  4. Tim Geyssens on December 6th, 2012

    @martin yup custom fieldtypes is also possible, add reference and then set the type on the field attribute :)

  5. Ash on December 7th, 2012

    Is it possible to enable conditions or the additional settings on the fields?
    If yes how would we do it?

  6. Tim Geyssens on December 21st, 2012
  7. Maxime on February 4th, 2013

    How can we add more fields? I try to apply for iwin and have to copy code

  8. Will on February 4th, 2013

    hey,

    Is it possible to create form steps using the code first approach?

    Thanks, will

  9. Tim Geyssens on April 9th, 2013

    @Will yeah if you have different page names in the field attributes

  10. Pete Duncasnon on April 15th, 2013

    Hey Tim,

    We’ve had a nasty time getting this working on a recent project trying to get login, signup etc working. Feels like we are going against the grain. Where best to send feedback, quirks and issues for this sort of stuff so others don’t get as stuck?

    Cheers

    Pete

  11. Dan on August 2nd, 2013

    I’m using Umbraco 6.0.5 and Contour 3.0.12 and the reg form works fine except no custom properties are being saved. Help!

  12. Gavin on November 8th, 2013

    For the Login the Password and UserName is being stored in clear text in the UFRecordDataString table. Is there anyway to prevent this ?

    I’ve tried the option StoreRecordsLocally=false but that does seem to effect it.

    Thanks,
    Gavin

  13. Dan Evans on January 8th, 2014

    Hi Tim

    These forms are great, however all users login info (passwords in particular) are saved in Contour in plain text. Is there an easy way to stop Contour saving this information as it’s a bit of a security risk.

    Thanks

    Dan

  14. Tim Geyssens on January 8th, 2014

    @Dan, yeah you can specify to not store locally on the form attribute

  15. Jacob Polden on April 24th, 2014

    For some reason only one of my contour forms renders correctly at a time. If I restart the app pool they alternate consistently, even the count of field sets changes in the database. They are two different classes in the same namespace and compiled into one dll. Is that okay or should I be breaking up each form into a separate dll?

  16. Chen on July 21st, 2014

    Hi Tim,

    Does the above code examples work in Umbraco 7? Thank you.

    Chen

  17. Tony Gayter on November 18th, 2014

    When I add the StoreRecordsLocally on the form I get the following error, looks like its not set for a load balanced environment

    Unable to serialize the session state. In ‘StateServer’ and ‘SQLServer’ mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in ‘Custom’ mode.

  18. imgur on January 27th, 2015

    When you make a website, all your web pages are served from the server residing
    somewhere on the internet. Dream - Host is an online hosting company that offers products like domain registration, shared website hosting, Virtual Private Server
    (VPS), and public cloud services. You can be diligent about protecting your website but someone
    else on the same server might not be.

  19. soccer predictions on January 28th, 2015

    Every weekend i used to pay a visit this website,
    for the reason that i wish for enjoyment, for the reason that this this web site conations
    truly good funny material too.

  20. cadouri on February 1st, 2015

    Hi there, constantly i used to check weblog posts here
    in the early hours in the break of day, as i like to
    gain knowledge of more and more.

  21. tiny.cc on February 3rd, 2015

    Cyclonic and bag less vacuum cleaners use almost the same system as the filter bags but uses a
    canister to trap the debris instead of a filter.
    Instead, yoou have too lift it as you maneuver around the area.
    Eureka claim hat the Insta - Rinse Cleaning System lets you to shampoo,
    then rinse, all with thhe push of a button, so you.

  22. Bojan Miletic on February 25th, 2015

    This is a pretty old, but still very useful post. Great work.

    I need to ask if anybody had issue with Validate method? It’s not run at all for me.

    Not even something very simple like this:

    public override IEnumerable Validate()
    {
    var e = new List();
    e.Add(new Exception(”Please provide address”));
    return e;
    }

    The form is submitted anyway. The site has: umbraco v 4.9.1 (Assembly version: 1.0.4869.25729) and Umbraco Contour version 3.0.1.

    Any ideas or I’m missing something here?

  23. site de rencontre marié on March 18th, 2015

    Magnificent items from you, man. I have be mindful your stuff prior to and you are just too magnificent.
    I really like what you have blught here, certainly like what
    you are saying and the way by which you assert it.
    You make it entertaining and you still take care of to stay
    it wise. I can’t wait to learn far more from you. This iis actually
    a wonderful web site.

  24. money today scam on March 25th, 2015

    Wow, fantastic weblog format! How lengthy have you ever been running a
    blog for? you made running a blog look easy. The overall look
    of your web site is fantastic, as well as the content material!

  25. cadouri pentru barbati on March 27th, 2015

    Wow, that’s what I was looking for, what a stuff! existing here at this weblog, thanks admin of
    this web site.

  26. Extreme Antler Supplement on March 28th, 2015

    Remarkable! Its in fact remarkable piece of writing, I have got much
    clear idea about from this piece of writing.

  27. When this occurs, the primary HoH is often not offered the advantages resembling use of the “HoH Room”.

  28. make a claim three on March 30th, 2015

    Most of these entail small damage to the automobiles or related property.
    Once you have provided them with basic information you be
    able to leave the rest to them. Your claim is unique and will have its own factors that will affect your claim and compensation.

Leave a Reply