Members via a SurfaceController - using custom properties
HI,
Using Umbraco 7.1.4 I've created myself a SurfaceController to test out the creation of new members and logging in. I've struggling a bit with picking through the various bits of documentation. It's hard to know what is obsolete as I've tried using what I think was the latest approach using the MemberShip Helper stuff and it didn't seem to work.
I've found using Members, I can create members and set a custom property "validateguid" I've added to the "Member" member type using:
regModel.Name = model.Username;
regModel.Password = model.Password;
regModel.Email = model.Email;
// Can set via index (messy)
// myModel.MemberProperties[0].Value = "Set from code";
// System.Diagnostics.Debug.WriteLine( myModel.MemberProperties[0].Value);
// Better - via alias with a lambda?
regModel.MemberProperties.Find(x => x.Alias == "validateguid").Value = newUserGuid;
// Register (create) the member
var member = Members.RegisterMember(regModel, out status, true);
// set them to NOT be approved so we can implement a validate GUID email thang.
member.IsApproved = false;
I want the member NOT to be approved automatically as I'm going to implement an email check (hence the GUID).
This all works but I can't help but feeling like I've hacked a few bits together. My question is wether my approach is correct?
In my next bit of code I try to validate the user's email - so I need to look up their email address and the validate GUID. I actually tried to do this via Members.GetbyUsername initially and that failed - perhaps because of the new email as username?
The problem here is that I can't set the IsApproved attribute now - the Member seems to be read only. Am I missing something?
// weird - Members.GetbyUsername(username) didn't work?!
var member = Members.GetByEmail(email);
string testGUID = "";
testGUID = member.GetPropertyValue("validateguid").ToString().ToLower();
if (testGUID == GUID)
{
// This doesn't work!
// member.IsApproved = true;
Ouch, looks like you're struggling, we should update documentation huh..!
Try and play with this:
using System.Web.Mvc;
using Umbraco.Course.Models;
using Umbraco.Web.Mvc;
namespace Umbraco.Course.Controllers
{
public class RegisterController : SurfaceController
{
public ActionResult Register(RegisterModel model)
{
if (!ModelState.IsValid)
return CurrentUmbracoPage();
var memberService = Services.MemberService;
if (memberService.GetByEmail(model.Email) != null)
{
ModelState.AddModelError("", "Member already exists. Aborting!");
return CurrentUmbracoPage();
}
// IntranetUser is the member type
var member = memberService.CreateMember(model.Email, model.Email, model.Name, "IntranetUser");
// Custom properties can easily be set, use this for your validation guid
member.SetValue("biography", model.Biography);
member.SetValue("avatar", model.Avatar);
// Not yet allowed to log in!
member.IsApproved = false;
// Don't forget to save all these things
memberService.Save(member);
// save their password
memberService.SavePassword(member, model.Password);
// "regular" is the member group
memberService.AssignRole(member.Id, "regular");
// Redirect somewhere
return Redirect("/");
}
}
}
The model looks like this:
using System.ComponentModel.DataAnnotations;
using System.Web;
namespace Umbraco.Course.Models
{
public class RegisterModel
{
[Required]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
public string Password { get; set; }
public string Biography { get; set; }
public HttpPostedFileBase Avatar { get; set; }
}
}
I can't say I've tried to set Approved to false but that should be possible somehow!
Yup - that cleared the fog - I think I got in a bit of mess there!
I'll post my full code when I've got it working for anyone trying to do similar - I spotted a couple of Our Umbraco forum posts without a full solution so I don't think I was alone here!
For checking the user's password on login do I really need to do this or is there a method I've missed?
// Do I really need to hash the password myself - surely there is a helper method to validate user?
HMACSHA1 hash = new HMACSHA1();
hash.Key = Encoding.Unicode.GetBytes(model.Password);
string hashedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(model.Password)));
if (member.RawPasswordValue == hashedPassword)
{
FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
return RedirectToCurrentUmbracoPage();
}
else
{
TempData["Status"] = "Invalid username or password";
return RedirectToCurrentUmbracoPage();
}
Hi Charles - I did initially start mixing the bits of the core .NET code and it started becoming a mess!
Sebastiaan's approach worked perfectly (using members) - if you're interested download the code from Git Hub - I hope it's all done in the Umbraco way.
Great work! Does your solution work directly with the built-in Umbraco members section or do I need to add them to a separate table in the database? I'm new to MVC just wondering if your (github) MvcMemberViewModel will interact directly with the built-in RegisterModel, ProfileModel, etc.
It works directly (if I'm understanding what you're asking!) with the members section. There are no custom tables but (as noted at the start of section 2.1 in my blog post ) you need to create some "generic properties" to match the pieces of information we create in addition to the standard ones. In Umbraco you can add properties easily in Members > Member Types > [your type] > Generic Properties tab.
I've followed your github code example and created the viewmodel,controller, and corresponding views. However, when I tried to submit the register form, I get a null reference.
not sure I'm doing wrong there, will you be able to help please? Thank you in advance!
Sorry didn't provide any details earlier. It's the same code from Steve's github repo, I've not modified it yet. Figured out what it is though, just as you suggested one of the property was empty. I added the following code and the problem went away.
if (!this.ModelState.IsValid)
{
returnthis.CurrentUmbracoPage();
}
I've been basing an Umbraco 7.2 membership system on this, great work Steve btw....got me out of trouble :-)
One thing to note though; on your walkthrough site here it says you need to "Validate page with @Html.Action("MvcMemberValidateRenderForm", "MvcMemberSurface")". I don't know if this was your original code and it changed or it was a typo in your write-up, but there is no ActionResult called MvcMemberValidateRenderForm in your MvcMemberSurfaceController.cs on GitHub.
For the benefit of others (mainly MVC newbs) using your build, you need to call the Action like this; @Html.Action("MvcMemberValidate", "MvcMemberSurface") . No need to create a custom MvcMemberValidateRenderForm ActionResult! (Like I did haha).
Remember to not go into the Dynamic trap!
Always use Umbraco.Typed*
I used Umbraco.Media to get an url for an image while using SetValue on a IMember.
It all compiled nicely, but failed when running since the SetValue method wasn't found due to the entire thing had been turned into dynamic crap.
From the slack channel:
sniffdk:
[2:46 PM] I think its simply that when you retrieve a media item as a
dynamic', everything turns dynamic
[2:47 PM] and the RuntimeBinder tries to find a suitable method with a
suitable amount of parameters
[2:47 PM] and it fails
Members via a SurfaceController - using custom properties
HI,
Using Umbraco 7.1.4 I've created myself a SurfaceController to test out the creation of new members and logging in. I've struggling a bit with picking through the various bits of documentation. It's hard to know what is obsolete as I've tried using what I think was the latest approach using the MemberShip Helper stuff and it didn't seem to work.
I've found using Members, I can create members and set a custom property "validateguid" I've added to the "Member" member type using:
I want the member NOT to be approved automatically as I'm going to implement an email check (hence the GUID).
I also add them to a group using:
This all works but I can't help but feeling like I've hacked a few bits together. My question is wether my approach is correct?
In my next bit of code I try to validate the user's email - so I need to look up their email address and the validate GUID. I actually tried to do this via Members.GetbyUsername initially and that failed - perhaps because of the new email as username?
The problem here is that I can't set the IsApproved attribute now - the Member seems to be read only. Am I missing something?
Ouch, looks like you're struggling, we should update documentation huh..!
Try and play with this:
The model looks like this:
I can't say I've tried to set Approved to false but that should be possible somehow!
Hi Sebastiaan,
I've used similar code on Umbraco 7.7.7 net framework 4.5. It was working.
Now i need to adapt the same member registration surface controller to another site (Umbraco 7.15.6 net framework 4.7.2). Everything's working except
It fails to check if there's a member registered with the email address.
Do you have any idea?
Oh and in your validation of the GUID, it doesn't work because you likely forgot to Save the member:
Yup - that cleared the fog - I think I got in a bit of mess there!
I'll post my full code when I've got it working for anyone trying to do similar - I spotted a couple of Our Umbraco forum posts without a full solution so I don't think I was alone here!
Thanks Sebastian!
For checking the user's password on login do I really need to do this or is there a method I've missed?
I was looking for something like Membership.ValidateUser(m.Email, model.Password)
Much easier :-)
Just log them in, the Login method returns a boolean:
Doh! Not sure how I missed that.
I've blogged my approach - and put my code on github. Would be interested to hear how other people get on with this.
http://siempresolutions.co.uk/blog/Umbraco_Members_Protected_Area_of_Website_Part_2_Using_MVCMembers_Controller
Hi I have been using the .net membership provider rather than Umbraco inbuilt methods.
Steve re:For checking the user's password on login do I really need to do this or is there a method I've missed?
You can use the inbuilt .net methods. The method you need is VallidateUser()
what is the alias of the property you are trying to set on your member. If it is lowercase change it to upper case and give that a try?
I might be missing the orginal problem.
Charlie :)
Hi Charles - I did initially start mixing the bits of the core .NET code and it started becoming a mess!
Sebastiaan's approach worked perfectly (using members) - if you're interested download the code from Git Hub - I hope it's all done in the Umbraco way.
Cheers
Steve
Glad you got it working :)
Hi Steve,
Just wanted to thank you for posting your code on GitHub. Really helped me get my login/registrations pages up and running.
Regards
Ver
You're very welcome!
Cheers
Steve
Hi Steve,
Great work! Does your solution work directly with the built-in Umbraco members section or do I need to add them to a separate table in the database? I'm new to MVC just wondering if your (github) MvcMemberViewModel will interact directly with the built-in RegisterModel, ProfileModel, etc.
Cheers!
Chen
It works directly (if I'm understanding what you're asking!) with the members section. There are no custom tables but (as noted at the start of section 2.1 in my blog post ) you need to create some "generic properties" to match the pieces of information we create in addition to the standard ones. In Umbraco you can add properties easily in Members > Member Types > [your type] > Generic Properties tab.
HTH.
Hi Steve,
I've followed your github code example and created the viewmodel,controller, and corresponding views. However, when I tried to submit the register form, I get a null reference.
not sure I'm doing wrong there, will you be able to help please? Thank you in advance!
Chen
Hi Chen,
I can see what the problem is can you post what you code you have for CreateMember?
Charlie
Hi Chen your error is this line:
var member = memberService.CreateMember(model.Email, model.Email, model.FirstName + " " + model.LastName, "Member");
The 4th parameter "Member" is the UserType i believe and because that is not in your user types you are getting a null exception.
To solve this:
Go to the Users tab in umbraco
Right click on UserTypes
Click create
Enter Member
And your could should work.
Charlie :)
Hi Charlie,
Thank you for the quick reply. Actually I do have "Member" defined as a MemberType (see attachment). Not sure what else is wrong tho :(
Thanks,
Chen
You need to figure out which property is null and why. Also, in order to not keep us guessing at what your problem could be, post some code.
Hi Sebatiaan/Charlie,
Sorry didn't provide any details earlier. It's the same code from Steve's github repo, I've not modified it yet. Figured out what it is though, just as you suggested one of the property was empty. I added the following code and the problem went away.
Thank you both!
Chen
No worries, must of been something you were passing in as null. Glad you fixed it. Could you maked it as complete please :)
I just made use of this and your blog post to get my membership system into gear! Thanks so much. #HFYR
You're very welcome - thanks to those that helped especially Sebastiaan Janssen!
Hi all,
I've been basing an Umbraco 7.2 membership system on this, great work Steve btw....got me out of trouble :-)
One thing to note though; on your walkthrough site here it says you need to "Validate page with @Html.Action("MvcMemberValidateRenderForm", "MvcMemberSurface")". I don't know if this was your original code and it changed or it was a typo in your write-up, but there is no ActionResult called MvcMemberValidateRenderForm in your MvcMemberSurfaceController.cs on GitHub.
For the benefit of others (mainly MVC newbs) using your build, you need to call the Action like this; @Html.Action("MvcMemberValidate", "MvcMemberSurface") . No need to create a custom MvcMemberValidateRenderForm ActionResult! (Like I did haha).
Cheers for all your work on this Steve!
-Sam
Sam quite possibly a last minute rename ... I'll have a look at it and correct it when I get a chance. Thanks for the spot!
Fantastic! Just what I was looking for. Has anyone done anything similar with user profile page?
Just a little heads up from me:
Remember to not go into the Dynamic trap! Always use Umbraco.Typed*
I used Umbraco.Media to get an url for an image while using SetValue on a IMember. It all compiled nicely, but failed when running since the SetValue method wasn't found due to the entire thing had been turned into dynamic crap.
From the slack channel:
is working on a reply...