Magelia WebStore

  • Summary

How to use the Membership and Profile Provider

Download the code sample of this tutorial:
How To Use The Membership And Profile Provider samples - ZIP - 20.6 mo

Overview: Concept of CustomerSet

Magelia WebStore has its own user base; all available methods for user management can be found at the Customer Service level. Although it is possible to manage the entirety of one's users through these services, in an ASP.net web context it is recommended to use the MembershipProvider and the ProfileProvider that are available at the client level of Magelia WebStore.

Warning! In an ASP.NET web context, it is recommended to use the MembershipProvider and ProfileProvider.

The Magelia WebStore application allows for several vendors and several stores; however, users are not assigned to a store or a vendor, but rather to a CustomerSet. The CustomerSet is relative to the vendor and associated with one or several stores.

When the same CustomerSet is used for two different stores, the users will be shared: a user having an account for store1 will be able to use this same account for store2.

The Magelia WebStore application allows for several vendors and several stores; however

FYI: The configuration of a CustomerSet is performed at the administration console level, under the Sellers - Store tab, then Customer sets.

The configuration of a CustomerSet is performed at the administration console level

A CustomerSet groups customers together. A default customer set is created during setup. Unless you have specific needs (e.g. Orchard integration), we suggest using the default CustomerSet.

Properties of a Customer Set:

You may easily define the parameters of a CustomerSet, via different properties, which are the following:

img

Here is an example of configuration for the Customer Set:

A CustomerSet groups customers together. A default customer set is created during setup. Unless you have specific needs (e.g. Orchard integration)

How to Configure Membership and Profile Provider Information

Magelia WebStore is based on the ASP.NET Membership and Profile provider. The mechanisms for use and implementation are therefore identical to those that you are familiar with in a classic ASP.NET website.

During installation of the NuGet package (see the section How to use Magelia WebStore in a Visual Studio project), the sections Membership and Profile provider have been added to your configuration file:

<membership defaultProvider="WebStoreMembership">
  <providers>
    <add name="WebStoreMembership" type="Magelia.WebStore.Client.Web.Security.WebStoreMembershipProvider, Magelia.WebStore.Client" />
  </providers>
</membership>
<profile defaultProvider="WebStoreProfile">
  <providers>
    <add name="WebStoreProfile" type="Magelia.WebStore.Client.Web.Profile.WebStoreProfileProvider, Magelia.WebStore.Client" />
  </providers>
</profile>

How to configure Membership provider

In order to use the concept of Membership, it is necessary to specify the appropriate configuration via the Membership section.

<configuration>
    <system.web>
      <membership defaultProvider="WebStoreMembership">
        <providers>
          <add name="WebStoreMembership" type="Magelia.WebStore.Client.Web.Security.WebStoreMembershipProvider, Magelia.WebStore.Client" />
        </providers>
      </membership>
    </system.web>
</configuration>

In the above example we use the provider supplied by the Magelia client: WebStoreMembershipProvider.

FYI: For more information on the implementation of a Membership Provider, visit the MSDN Documentation: Managing Users by Using Membership

How to configure the Profile provider

Just as we did for Membership, you must add the Profile section to your configuration:

<configuration>
    <system.web>
        <profile defaultProvider="WebStoreProfile">
            <providers>
            <add name="WebStoreProfile" type="Magelia.WebStore.Client.Web.Profile.WebStoreProfileProvider, Magelia.WebStore.Client" />
            </providers>
        </profile>
    </system.web>
</configuration>

In the above example we use the provider supplied by the Magelia client WebStoreProfileProvider. This profile provider supplies the base properties of any profile in Magelia WebStore, which are the following:

img

You can define additional properties that you wish to manager for your users, such as the format of emails, the title (Mr., Mrs., or Ms.), by defining your own provider. To do so, you will need to create a new class that inherits WebStoreProfile, like in the following example:

using Magelia.WebStore.Client.Web.Profile;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System.ComponentModel;
using System.Web.Profile;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile
{
    public enum Title
    {
        Miss = 0,
        Mrs = 1,
        M = 2
    }
 
    public class WebStoreSampleProfile : WebStoreProfile
    {
        [DefaultValue(MailFormat.Html)]
        [SettingsAllowAnonymous(false)]
        public MailFormat MailFormat
        {
            get
            {
                if (this.GetPropertyValue("MailFormat") != null)
                {
                    return (MailFormat)this.GetPropertyValue("MailFormat");
                }
                else
                {
                    return MailFormat.Html;
                }
            }
            set
            {
                this.SetPropertyValue("MailFormat", value);
            }
        }
 
        [DefaultValue(Title.Miss)]
        [SettingsAllowAnonymous(false)]
        public Title Title
        {
            get
            {
                if (this.GetPropertyValue("Title") != null)
                {
                    return (Title)this.GetPropertyValue("Title");
                }
                else
                {
                    return Title.Miss;
                }
            }
            set
            {
                this.SetPropertyValue("Title", value);
            }
        }
    }
}

You will next need to specify, via your configuration file, that this new class corresponds to your profile provider:

<configuration>
    <system.web>
      <profile enabled="true" defaultProvider="ServicesProfileProvider" automaticSaveEnabled="true"
       inherits="Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile.WebStoreSampleProfile, Magelia.WebStore.Client.Web.UI.Sample">
        <providers>
          <clear />
          <add name="ServicesProfileProvider" type="Magelia.WebStore.Client.Web.Profile.WebStoreProfileProvider, Magelia.WebStore.Client" />
        </providers>
      </profile>
    </system.web>
</configuration>

FYI: For more information on the implementation of a Profile Provider, refer to the MSDN documentation: Implementing a Profile Provider

How to Create a Login Page

In the previous sections we configured our site to be able to manage users via the ASP.NET Membership and Profile provider mechanisms, on our Magelia WebStore shop.

FYI: the examples and extracts of code, used in the different sections, are implemented in a web context within an ASP.NET MVC4 application and using the Razor rendering engine for viewing. You can grab the entire source of the example at the end of the section.

For more information, on ASP .NET MVC and Razor, please refer to the site ASP.NET MVC

In order to create our login page, the first element to define is the controller that will serve to collect information that will be entered by the user, as well as to define our validators and the rendering of the view. Next we will define the controller that will manage assigned Post and Get actions. And finally, we define the view that will be loaded and displayed.

In order to create our login page

How to create a new user

Before users can be authenticated, they must have a registered account. This is why it is necessary to put in place a registration form:

Before users can be authenticated


We use here the classic methods supplied by ASP .NET Membership. For the creation of a user we use therefore the CreateUser method.

using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using CompareAttribute = System.ComponentModel.DataAnnotations.CompareAttribute;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class NewViewModel : IValidatableObject
    {
        private IEnumerable<SelectListItem> _availableTitles;
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "TitleIdLabel")]
        public Int32 TitleId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "FirstNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "FirstNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "FirstNameLengthErrorMessage")]
        public String FirstName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "MiddleNameLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "MiddleNameLengthErrorMessage")]
        public String MiddleName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "LastNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "LastNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "LastNameLengthErrorMessage")]
        public String LastName { get; set; }
 
        [DataType(DataType.EmailAddress)]
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "EmailLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "EmailRequiredErrorMessage")]
        [UniqueEmail(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "UniqueEmailErrorMessage")]
        [Email(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "InvalidEmailErrorMessage")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "EmailLengthErrorMessage")]
        public String Email { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "UserNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "UsernameRequiredErrorMessage")]
        [UniqueUsername(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "UniqueUsernameErrorMessage")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "UsernameLengthErrorMessage")]
        public String Username { get; set; }
 
        [DataType(DataType.Password)]
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "PasswordLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "PasswordRequiredErrorMessage")]
        [PasswordLength(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "PasswordLengthErrorMessage")]
        [PasswordStrength(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "PasswordStrengthErrorMessage")]
        public String Password { get; set; }
 
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "ConfirmPasswordRequiredErrorMessage")]
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "PasswordNotMatchErrorMessage")]
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "PasswordConfirmationLabel")]
        public String ConfirmPassword { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "QuestionLabel")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.NewViewModel), ErrorMessageResourceName = "QuestionLengthErrorMessage")]
        public String Question { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.NewViewModel), Name = "AnswerLabel")]
        public String Answer { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
 
        public IEnumerable<SelectListItem> AvailableTitles
        {
            get
            {
                if (this._availableTitles == default(IEnumerable<SelectListItem>))
                {
                    this._availableTitles = Enumerable.Empty<SelectListItem>();
                }
                return this._availableTitles;
            }
            set
            {
                this._availableTitles = value;
            }
        }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (!Membership.RequiresQuestionAndAnswer)
            {
                yield return ValidationResult.Success;
            }
            else
            {
                if (String.IsNullOrEmpty(Question))
                {
                    yield return new ValidationResult(Resources.Models.Account.NewViewModel.QuestionRequiredErrorMessage, new String[] { "Question" });
                }
                if (String.IsNullOrEmpty(Answer))
                {
                    yield return new ValidationResult(Resources.Models.Account.NewViewModel.AnswerRequiredErrorMessage, new String[] { "Answer" });
                }
            }
        }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.NewViewModel
@{
    ViewBag.Title = Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.New.PageTitle;
}
 
<article id="new">
<div class="content">
        <h2>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.New.NewAccountTitleText</h2>
        @using (Html.BeginForm("New", "Account", new RouteValueDictionary { { "returnUrl", this.Model.ReturnUrl } }))
            {   
                @Html.ValidationSummary(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.New.InvalidFormErrorMessage)
                <div class="editor-label">
                    @Html.LabelFor(m => m.TitleId)
                </div>
                <div class="editor-field">
                    @Html.DropDownListFor(m => m.TitleId, Model.AvailableTitles)
                    @Html.ValidationMessageFor(m => m.TitleId)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.FirstName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.FirstName)
                    @Html.ValidationMessageFor(m => m.FirstName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MiddleName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MiddleName)
                    @Html.ValidationMessageFor(m => m.MiddleName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.LastName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.LastName)
                    @Html.ValidationMessageFor(m => m.LastName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Email)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Email)
                    @Html.ValidationMessageFor(m => m.Email)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Username)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Username)
                    @Html.ValidationMessageFor(m => m.Username)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Password)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.Password)
                    @Html.ValidationMessageFor(m => m.Password)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.ConfirmPassword)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.ConfirmPassword)
                    @Html.ValidationMessageFor(m => m.ConfirmPassword)
                </div>
                if (Membership.RequiresQuestionAndAnswer)
                {
                <div class="editor-label">
                    @Html.LabelFor(m => m.Question)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Question)
                    @Html.ValidationMessageFor(m => m.Question)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Answer)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Answer)
                    @Html.ValidationMessageFor(m => m.Answer)
                </div>
                }
                <div class="buttons">
                    <ul>
                        <li>
                            <button class="highlight" type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.New.NewAccountButtonText</button>
                        </li>
                    </ul>
                </div>
            }
    </div>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
//...
         /// <summary>
        /// Get New action
        /// </summary>
        /// <param name="returnUrl">Retrun Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        public ActionResult New(String returnUrl)
        {
            return this.View(new NewViewModel { ReturnUrl = returnUrl, AvailableTitles = SampleSiteContext.Titles });
        }
 
        /// <summary>
        /// Post New action 
        /// </summary>
        /// <param name="viewModel"></param>
        /// <param name="returnUrl">Return url</param>
        /// <returns>Action result</returns>
        [HttpPost]
        public ActionResult New(NewViewModel viewModel, String returnUrl)
        {
            if (this.ModelState.IsValid)
            {
                MembershipCreateStatus createStatus;
                WebStoreSampleMembershipUser user = Membership.CreateUser(viewModel.Username, viewModel.Password, viewModel.Email, viewModel.Question, viewModel.Answer, true, out createStatus).AsSampleSiteUser();
                if (createStatus == MembershipCreateStatus.Success)
                {
                    user.Profile.FirstName = viewModel.FirstName;
                    user.Profile.MiddleName = viewModel.MiddleName;
                    user.Profile.LastName = viewModel.LastName;
                    user.Profile.Title = (Title)viewModel.TitleId;
                    user.Profile.Save();
                    FormsAuthentication.SetAuthCookie(viewModel.Username, false);
                    if (String.IsNullOrWhiteSpace(returnUrl))
                    {
                        IndexViewModel editViewModel = this.GetIndexViewModel(user);
                        editViewModel.AccountCreated = true;
                        return this.View("Index", editViewModel);
                    }
                    return this.Redirect(returnUrl);
                }
                else
                {
                    this.ModelState.AddModelError("User", this.GetMembershipCreateErrorMessage(createStatus));
                }
            }
            viewModel.AvailableTitles = SampleSiteContext.Titles;
            return this.View(viewModel);
        }
        // ...
    }
}

How to authenticate a user

When a user exists in the registered user database, it is then possible to authenticate the user using a login form on our site. For this we are going to use the ValidateUser method provided by the ASP .NET Membership.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class LogonViewModel
    {
        [Display(ResourceType = typeof(Resources.Models.Account.LogonViewModel), Name = "UserNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.LogonViewModel), ErrorMessageResourceName = "UserNameRequiredErrorMessage")]
        public String UserName { get; set; }
 
        [DataType(DataType.Password)]
        [Display(ResourceType = typeof(Resources.Models.Account.LogonViewModel), Name = "PasswordLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.LogonViewModel), ErrorMessageResourceName = "PasswordRequiredErrorMessage")]
        public String Password { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.LogonViewModel), Name = "RememberMeLabel")]
        public Boolean RememberMe { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public Boolean HasBeenAuthenticated { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.LogonViewModel
@{
    ViewBag.Title = @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.PageTitle;
}
 
<article id="login">
    <div class="content">
        <h1>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.ExistingTitleText</h1>
        @using (Html.BeginForm("Logon", "Account"))
        {
            @Html.ValidationSummary(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.InvalidFormErrorMessage)
            @Html.EditorForModel();
            <p><button type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.SigninButtonText</button></p>
        }
    </div>
    <section>
        <h2>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.NewTitleText</h2>
        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.ContinueButtonText, "New", new { returnUrl = this.Model.ReturnUrl }, new { @class = "big highlight" })
    </section>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        /// <summary>
        /// Get Logon action
        /// </summary>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        public ActionResult Logon(String returnUrl)
        {
            return this.View(new LogonViewModel { ReturnUrl = returnUrl });
        }
 
        /// <summary>
        /// Post Logon action
        /// </summary>
        /// <param name="viewModel">Modèle associé à l'action</param>
        /// <returns>Action result</returns>
        [HttpPost]
        public ActionResult Logon(LogonViewModel viewModel)
        {
            if (Membership.ValidateUser(viewModel.UserName, viewModel.Password))
            {
                FormsAuthentication.SetAuthCookie(viewModel.UserName, viewModel.RememberMe);
                viewModel.HasBeenAuthenticated = true;
                if (String.IsNullOrEmpty(viewModel.ReturnUrl))
                {
                    return this.RedirectToAction("Index");
                }
                else
                {
                    return this.Redirect(viewModel.ReturnUrl);
                }
            }
            else
            {
                this.ModelState.AddModelError(String.Empty, Resources.Controllers.AccountController.InvalidCredentialsErrorMessage);
                return this.View(viewModel);
            }
        }
 
        // ...
    }
}

Warning! In the above example, we use forms authentification. In order for this to work properly, it is necessary to add the following code to your configuration file:

<authentication mode="Forms">
    <forms loginUrl="~/Account/Logon" timeout="2880" />
</authentication>
<anonymousIdentification enabled="true" />

How to Manage User Profiles

In the following code example, we are going to see how to offer basic account management functionalities, notably: update user’s personal information, log-out, modify user’s password, etc.

In the following code example

Update user information

using Magelia.WebStore.Client.Web.Security;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using CompareAttribute = System.ComponentModel.DataAnnotations.CompareAttribute;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class IndexViewModel : IValidatableObject
    {
        private IEnumerable<SelectListItem> _availableTitles;
 
        [DataType(DataType.EmailAddress)]
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "EmailLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "EmailRequiredErrorMessage")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "EmailLengthErrorMessage")]
        [Email(ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "InvalidEmailErrorMessage")]
        public String Email { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "QuestionLabel")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "QuestionLengthErrorMessage")]
        public String Question { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "AnswerLabel")]
        public String Answer { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "TitleIdLabel")]
        public Int32 TitleId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "FirstNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "FirstNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "FirstNameLengthErrorMessage")]
        public String FirstName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "MiddleNameLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "MiddleNameLengthErrorMessage")]
        public String MiddleName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "LastNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "LastNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.IndexViewModel), ErrorMessageResourceName = "LastNameLengthErrorMessage")]
        public String LastName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.IndexViewModel), Name = "RawEmailLabel")]
        public Boolean RawEmail { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public Boolean AccountModified { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public Boolean AccountCreated { get; set; }
 
        public IEnumerable<SelectListItem> AvailableTitles
        {
            get
            {
                if (this._availableTitles == default(IEnumerable<SelectListItem>))
                {
                    this._availableTitles = Enumerable.Empty<SelectListItem>();
                }
                return this._availableTitles;
            }
            set
            {
                this._availableTitles = value;
            }
        }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
 
            if (Membership.Provider is WebStoreMembershipProvider)
            {
                WebStoreMembershipProvider serviceMembershipProvider = Membership.Provider as WebStoreMembershipProvider;
                if (!serviceMembershipProvider.RequiresUniqueEmail)
                {
                    yield return ValidationResult.Success;
                }
                MembershipUser currentUser = Membership.GetUser();
                foreach (MembershipUser user in Membership.FindUsersByEmail(Email))
                {
                    if (!user.ProviderUserKey.Equals(currentUser.ProviderUserKey))
                    {
                        yield return new ValidationResult(Resources.Models.Account.IndexViewModel.EmailAleardyUsedErrorMessage, new String[] { Email });
                        break;
                    }
                }
            }
        }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.IndexViewModel
@{
    ViewBag.Title = Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.PageTitle;
}
 
<article id="account">
    <div class="content">
        <h1>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.AccountTitle</h1>
        @if (this.Model.AccountModified)
            {
                <div class="confirmation">
                    <p>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.UpdateConfirmationText</p>
                </div>
            }
            @if (this.Model.AccountCreated)
            {
                <div class="confirmation">
                    <p>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.CreationConfirmationText</p>
                </div>
            }
            @using (Html.BeginForm("Index", "Account"))
            {   
                @Html.ValidationSummary()
                <div class="editor-label">
                    @Html.LabelFor(m => m.TitleId)
                </div>
                <div class="editor-field">
                    @Html.DropDownListFor(m => m.TitleId, this.Model.AvailableTitles)
                    @Html.ValidationMessageFor(m => m.TitleId)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.FirstName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.FirstName)
                    @Html.ValidationMessageFor(m => m.FirstName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.MiddleName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.MiddleName)
                    @Html.ValidationMessageFor(m => m.MiddleName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.LastName)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.LastName)
                    @Html.ValidationMessageFor(m => m.LastName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Email)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Email)
                    @Html.ValidationMessageFor(m => m.Email)
                </div>
                if (Membership.RequiresQuestionAndAnswer)
                {
                <div class="editor-label">
                    @Html.LabelFor(m => m.Question)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Question)
                    @Html.ValidationMessageFor(m => m.Question)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Answer)
                </div>
                <div class="editor-field">
                    @Html.EditorFor(m => m.Answer)
                    @Html.ValidationMessageFor(m => m.Answer)
                </div>
                }
                <div class="editor-label">
                    @Html.LabelFor(m => m.RawEmail)
                </div>
                <div class="editor-field">
                    <ul>
                        <li>
                            <input id="rbtnHTML" type="radio" name="RawEmail"
                                value="@Boolean.FalseString" @if (!this.Model.RawEmail)
                                    {<text>checked="checked"</text>}/><label for="rbtnHTML">
                                        @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.HTMLLabel</label>
                        </li>
                        <li>
                            <input id="rbtnRaw" type="radio" name="RawEmail"
                                value="@Boolean.TrueString" @if (this.Model.RawEmail)
                                    {<text>checked="checked"</text>} /><label for="rbtnRaw">
                                        @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.RawLabel</label>
                        </li>
                    </ul>
                </div>
                <div class="buttons">
                    <ul>
                        <li>
                            @if (!String.IsNullOrEmpty(this.Model.ReturnUrl))
                            {
                                <a href="@Model.ReturnUrl">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.BackButtonText</a>
                            }
                        </li>
                        <li>
                            <button class="highlight" type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.UpdateButtonText</button>
                        </li>
                    </ul>
                </div>
            }
    </div>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        /// <summary>
        /// Get Index action
        /// </summary>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        [Authorize]
        public ActionResult Index(String returnUrl)
        {
            return this.View(this.GetIndexViewModel(Membership.GetUser().AsSampleSiteUser(), returnUrl));
        }
 
        /// <summary>
        /// Post Index action
        /// </summary>
        /// <param name="viewModel">IndexViewModel information</param>
        /// <returns>Action result</returns>
        [HttpPost]
        [Authorize]
        public ActionResult Index(IndexViewModel viewModel)
        {
            viewModel.AccountModified = false;
            viewModel.AvailableTitles = WebStoreContext.Titles;
            if (this.ModelState.IsValid)
            {
                WebStoreSampleMembershipUser customer = Membership.GetUser().AsSampleSiteUser();
 
                customer.Email = viewModel.Email;
 
                customer.Profile.FirstName = viewModel.FirstName;
                customer.Profile.MiddleName = viewModel.MiddleName;
                customer.Profile.LastName = viewModel.LastName;
                customer.Profile.Title = (Title)viewModel.TitleId;
                customer.Profile.MailFormat = viewModel.RawEmail ? MailFormat.Raw : MailFormat.Html;
 
                Membership.UpdateUser(customer);
                customer.Profile.Save();
 
                viewModel = this.GetIndexViewModel(customer, viewModel.ReturnUrl);
                viewModel.AccountModified = true;
            }
            return this.View(viewModel);
        }
 
        //...
    }
}

User log-out:

Once the user is logged-in, it is possible to know his log-in/log-out status via the property IsAuthenticated of the Request object. It is thus easy to create a link in order to offer the user the option to log-out.

<div id="action-bar">
    @if (this.Request.IsAuthenticated)
    {
        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Shared._Layout.MyAccountLinkText, "Index", "Account")
                     
        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Shared._Layout.LogOffLinkText, "LogOff", "Account")
    }
    else{
        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Shared._Layout.LoginLinkText, "Logon", "Account") 
    }
    | <a href="#">Your bag (0) &nbsp; &euro;0</a>
</div>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        //...
 
        /// <summary>
        /// Get LogOff action
        /// </summary>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        [Authorize]
        public ActionResult LogOff(String returnUrl)
        {
            FormsAuthentication.SignOut();
            if (String.IsNullOrEmpty(returnUrl))
            {
                return this.RedirectToAction("Index", "Home");
            }
            else
            {
                return this.Redirect(returnUrl);
            }
        }
 
        //...
    }
}

Reset user password:

The user must at any time be able to make a request to reset their password, in the event that the user has simply forgotten their log-in password. In our example, the user is going to have to specify their email address in order to receive a new password:

The user must at any time be able to make a request to reset their password

Here again we use the classic methods provided by ASP .NET Membership. Here we use the method GetUserNameByEmail in order to retrieve the user in the database of saved users, then the method ResetPassword to reset their password:

using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class ResetPasswordViewModel
    {
        [Display(ResourceType = typeof(Resources.Models.Account.ResetPasswordViewModel), Name = "EmailLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.ResetPasswordViewModel), ErrorMessageResourceName = "EmailRequiredErrorMessage")]
        [Email(ErrorMessageResourceType = typeof(Resources.Models.Account.ResetPasswordViewModel), ErrorMessageResourceName = "InvalidEmailErrorMessage")]
        public String Email { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public Boolean PasswordSent { get; set; }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.ResetPasswordViewModel
@{
    ViewBag.Title = @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ResetPassword.PageTitle;
}
 
<article id="Article1">
    <div class="content">
        <h1>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ResetPassword.ResetPasswordTitle</h1>
        @if (this.Model.PasswordSent)
        {
            <div class="confirmation">
                <p class="info">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ResetPassword.PasswordSentText</p>
            </div>
        }
        @using (Html.BeginForm())
        {
            @Html.ValidationSummary(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ResetPassword.InvalidFormErrorMessage)
         
            @Html.EditorForModel()
            <div class="buttons">
                <ul>
                    <li>
                        <button class="highlight">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ResetPassword.SendButtonText</button>
                    </li>
                </ul>
            </div>
        }
    </div>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        //...
 
        /// <summary>
        /// Get reset password action 
        /// </summary>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        public ActionResult ResetPassword(String returnUrl)
        {
            return this.View(new ResetPasswordViewModel { ReturnUrl = returnUrl });
        }
 
        /// <summary>
        /// Post reset password action
        /// </summary>
        /// <param name="viewModel">ViewModel associated with the action</param>
        /// <returns>Action result</returns>
        [HttpPost]
        public ActionResult ResetPassword(ResetPasswordViewModel viewModel)
        {
            viewModel.PasswordSent = false;
            if (ModelState.IsValid)
            {
                String userName = Membership.GetUserNameByEmail(viewModel.Email);
                if (!String.IsNullOrEmpty(userName))
                {
                    WebStoreSampleMembershipUser user = Membership.GetUser(userName, false).AsSampleSiteUser();
                    String newPassword = user.ResetPassword();
                    if (!String.IsNullOrWhiteSpace(newPassword))
                    {
                        // TODO : Send newPassword by Email logic here
                        viewModel.PasswordSent = true;
                    }
                }
                if (!viewModel.PasswordSent)
                {
                    this.ModelState.AddModelError("Email", Resources.Controllers.AccountController.ResetPasswordErrorMessage);
                }
            }
            return this.View(viewModel);
        }
    }
}

The only thing left to do is to provide a link allowing the user to access this functionality:

<p class="forgot">@Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Logon.PasswordLostLinkText, "ResetPassword")</p>

Changing user password:

In addition to being able to reset their password, a user must be able to change the current password:

In addition to being able to reset their password

Here again we use the classic methods provided by ASP .NET Membership. This time we use the method GetUser in order to find the user in the saved users database, then the method ChangePassword to modify their password:

using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using CompareAttribute = System.ComponentModel.DataAnnotations.CompareAttribute;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class ChangePasswordViewModel : IValidatableObject
    {
        [Display(ResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), Name = "OldPasswordLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordRequiredErrorMessage")]
        [DataType(DataType.Password)]
        public String OldPassword { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), Name = "PasswordLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordRequiredErrorMessage")]
        [DataType(DataType.Password)]
        [PasswordLength(ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordLengthErrorMessage")]
        [PasswordStrength(ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordStrengthErrorMessage")]
        public String Password { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), Name = "ConfirmPasswordLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordRequiredErrorMessage")]
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessageResourceType = typeof(Resources.Models.Account.ChangePasswordViewModel), ErrorMessageResourceName = "PasswordNotMatchErrorMessage")]
        public String ConfirmPassword { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public Boolean PasswordChanged { get; set; }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (!Membership.ValidateUser(HttpContext.Current.User.Identity.Name, this.OldPassword))
            {
                yield return new ValidationResult(Resources.Models.Account.ChangePasswordViewModel.WrongOldPasswordErrorMessage);
            }
        }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.ChangePasswordViewModel
@{
    ViewBag.Title = Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ChangePassword.PageTitle;
}
<article id="Article3">
    <div class="content">
        <h1>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ChangePassword.ChangePasswordHeader</h1>
        @if (this.Model.PasswordChanged)
            {
                <div class="confirmation">
                    <p class="info">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ChangePassword.ConfirmationText</p>
                </div>
            }
            @using (Html.BeginForm("ChangePassword", "Account"))
            {   
                @Html.ValidationSummary()
                <div class="editor-label">
                    @Html.LabelFor(m => m.OldPassword)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.OldPassword)
                    @Html.ValidationMessageFor(m => m.OldPassword)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Password)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.Password)
                    @Html.ValidationMessageFor(m => m.Password)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.ConfirmPassword)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.ConfirmPassword)
                    @Html.ValidationMessageFor(m => m.ConfirmPassword)
                </div>
                <div class="buttons">
                    <ul>
                        <li>
                            @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ChangePassword.BackButtonText, "Index")
                        </li>
                        <li>
                            <button class="highlight" type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.ChangePassword.UpdateButtonText</button>
                        </li>
                    </ul>
                </div>
            }
    </div>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        //... 
 
        /// <summary>
        /// Get change password action
        /// </summary>
        /// <returns>Action result</returns>
        [HttpGet]
        [Authorize]
        public ActionResult ChangePassword()
        {
            return this.View(new ChangePasswordViewModel());
        }
 
        /// <summary>
        /// Post change password action
        /// </summary>
        /// <param name="viewModel">ViewModel associated with the action</param>
        /// <returns>Action result</returns>
        [HttpPost]
        [Authorize]
        public ActionResult ChangePassword(ChangePasswordViewModel viewModel)
        {
            viewModel.PasswordChanged = false;
            if (this.ModelState.IsValid)
            {
                WebStoreSampleMembershipUser user = Membership.GetUser().AsSampleSiteUser();
                user.ChangePassword(viewModel.OldPassword, viewModel.Password);
                viewModel.PasswordChanged = true;
            }
            else
            {
                viewModel.PasswordChanged = false;
            }
            return this.View(viewModel);
        }
    }
}

The only thing left to do is to provide a link allowing the user to have access to this function:

<li>
    @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.ChangePasswordLinkText, "ChangePassword")
</li>

How to Manage User Addresses

Magelia WebStore offers the possibility of easily managing different addresses for a single user. A user may save several addresses. For example: a billing address, a shipping address, etc.

In the following sections, we are going to see how to easily manage different use addresses by adding, changing, or deleting one or several addresses.

Listing addresses:

In the previous sections, we saw how to find the user’s information. To find and grab addresses, it will be necessary to add the retrieved addresses at the model level, via the property Addresses of the user profile, then adapt the view to display the different addresses:

using Magelia.WebStore.Client.Web.Security;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using CompareAttribute = System.ComponentModel.DataAnnotations.CompareAttribute;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class IndexViewModel : IValidatableObject
    {
        //...
 
        /// <summary>
        /// Get the IndexViewModel with the user information
        /// </summary>
        /// <param name="user">User membership</param>
        /// <param name="returnUrl">Return url</param>
        /// <returns>IndexViewModel with user information</returns>
        private IndexViewModel GetIndexViewModel(WebStoreSampleMembershipUser user, String returnUrl = null)
        {
            return new IndexViewModel
            {
                FirstName = user.Profile.FirstName,
                MiddleName = user.Profile.MiddleName,
                LastName = user.Profile.LastName,
                TitleId = (int)user.Profile.Title,
                Email = user.Email,
                Question = user.PasswordQuestion,
                ReturnUrl = returnUrl,
                AvailableTitles = WebStoreContext.Titles,
                RawEmail = user.Profile.MailFormat == MailFormat.Raw,
                Addresses = user.Profile.Addresses.Select(a => new IndexViewModel.AddressReference { AddressId = a.AddressId, Name = a.Name })
            };
        }
 
        /// <summary>
        /// Nested class for displayable addresses
        /// </summary>
        public class AddressReference
        {
            public Guid AddressId { get; set; }
            public String Name { get; set; }
        }
 
        /// <summary>
        /// List of addresses references 
        /// </summary>
        private IEnumerable<AddressReference> _addresses;
 
        /// <summary>
        /// Public properties for addresses references
        /// </summary>
        public IEnumerable<AddressReference> Addresses
        {
            get
            {
                if (this._addresses == default(IEnumerable<AddressReference>))
                {
                    this._addresses = Enumerable.Empty<AddressReference>();
                }
                return this._addresses;
            }
            set
            {
                this._addresses = value;
            }
 
        }
    }
}
<section>
    <h2>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.AddressesTitle</h2>
    @if (this.Model.Addresses.Any())
        {
            <table>
                <thead>
                    <tr>
                        <th>
                            @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.NameHeader
                        </th>
                        <th>
                            @Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.OptionsHeader
                        </th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var address in this.Model.Addresses)
                    { 
                        <tr>
                            <td>
                                @address.Name
                            </td>
                            <td>
                                <div class="actions">
                                    <ul>
                                        <li>
                                            @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.EditLinkText, "EditAddress", new { addressId = address.AddressId })
                                        </li>
                                        <li>
                                            @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.DeleteLinkText, "DeleteAddress", new { addressId = address.AddressId })
                                        </li>
                                    </ul>
                                </div>
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        }
        <div class="buttons">
            <ul>
                <li>
                    @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.AddLinkText, "NewAddress")
                </li>
            </ul>
        </div>
</section>

Adding an address:

To add an address, we also use the Addresses property from the user’s profile, as well as the Add method:

using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class AddressViewModel : IValidatableObject
    {
        private IEnumerable<SelectListItem> _availableCountries;
        private IEnumerable<SelectListItem> _availableRegions;
        private IEnumerable<SelectListItem> _availableTitles;
 
        public Guid? AddressId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "NameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "NameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "NameLengthErrorMessage")]
        public String Name { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "TitleIdLabel")]
        public Int32 TitleId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FirstNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FirstNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FirstNameLengthErrorMessage")]
        public String FirstName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "MiddleNameLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "MiddleNameLengthErrorMessage")]
        public String MiddleName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "LastNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "LastNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "LastNameLengthErrorMessage")]
        public String LastName { get; set; }
 
        [DataType(DataType.EmailAddress)]
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "EmailLabel")]
        [Email(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "EmailErrorMessage")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "EmailLengthErrorMessage")]
        public String Email { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FloorLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FloorLengthErrorMessage")]
        public String Floor { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "DigicodeLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "DigiCodeLengthErrorMessage")]
        public String Digicode { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line1Label")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line1RequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line1LengthErrorMessage")]
        public String Line1 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line2Label")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line2LengthErrorMessage")]
        public String Line2 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line3Label")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line3LengthErrorMessage")]
        public String Line3 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "ZipCodeLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "ZipCodeLengthErrorMessage")]
        public String ZipCode { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CityLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CityRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CityLengthErrorMessage")]
        public String City { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CountryIdLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CountryIdRequiredErrorMessage")]
        public Int32? CountryId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "RegionIdLabel")]
        [RequiredRegion(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "RegionRequiredErrorMessage")]
        public Guid? RegionId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CompanyLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CompanyLengthErrorMessage")]
        public String Company { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "MobileNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "MobileNumberLengthErrorMessage")]
        public String MobileNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "PhoneNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "PhoneNumberLengthErrorMessage")]
        public String PhoneNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FaxNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FaxNumberLengthErrorMessage")]
        public String FaxNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CommentLabel")]
        [DataType(DataType.MultilineText)]
        public String Comment { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
 
        public IEnumerable<SelectListItem> AvailableCountries
        {
            get
            {
                if (this._availableCountries == default(IEnumerable<SelectListItem>))
                {
                    this._availableCountries = Enumerable.Empty<SelectListItem>();
                }
                return this._availableCountries;
            }
            set
            {
                this._availableCountries = value;
            }
        }
 
        public IEnumerable<SelectListItem> AvailableRegions
        {
            get
            {
                if (this._availableRegions == default(IEnumerable<SelectListItem>))
                {
                    this._availableRegions = Enumerable.Empty<SelectListItem>();
                }
                return this._availableRegions;
            }
            set
            {
                this._availableRegions = value;
            }
        }
 
        public IEnumerable<SelectListItem> AvailableTitles
        {
            get
            {
                if (this._availableTitles == default(IEnumerable<SelectListItem>))
                {
                    this._availableTitles = Enumerable.Empty<SelectListItem>();
                }
                return this._availableTitles;
            }
            set
            {
                this._availableTitles = value;
            }
        }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Membership.GetUser().AsStarterSiteUser().Profile.Addresses.Any(a => a.Name.Equals(this.Name, StringComparison.InvariantCultureIgnoreCase) && a.AddressId != this.AddressId))
            {
                yield return new ValidationResult(Resources.Models.Account.AddressViewModel.NameAlreadyUsedErrorMessage, new String[] { "Name" });
            }
        }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.AddressViewModel
@{
    ViewBag.Title = Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.NewAddress.PageTitle;
}
<article id="new">
    <div class="content">
        <h2>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.NewAddress.AddressTitle</h2>
        @using (Html.BeginForm("NewAddress", "Account", FormMethod.Post))
        {
            @Html.ValidationSummary()
            @Html.EditorForModel();
            <div class="buttons">
                <ul>
                    @if (String.IsNullOrEmpty(this.Model.ReturnUrl))
                    {
                        <li>
                            @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.NewAddress.BackButtonText, "Index")
                        </li>
                    }
                    else
                    { 
                        <li><a href="@Model.ReturnUrl">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.NewAddress.BackButtonText</a>
                        </li>
                    }
                    <li>
                        <button class="highlight" type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.NewAddress.SaveButtonText</button>
                    </li>
                </ul>
            </div>
        }
    </div>
</article>
/// <summary>
/// Get new address action
/// </summary>
/// <param name="returnUrl">Return Url</param>
/// <returns>Action result</returns>
[HttpGet]
[Authorize]
public ActionResult NewAddress(String returnUrl)
{
    WebStoreSampleMembershipUser user = Membership.GetUser().AsStarterSiteUser();
    AddressViewModel viewModel = new AddressViewModel { TitleId = (Int32)user.Profile.Title, LastName = user.Profile.LastName, MiddleName = user.Profile.MiddleName, FirstName = user.Profile.FirstName, Email = user.Email, ReturnUrl = returnUrl };
    this.SetAddressParameters(viewModel);
    return this.View(viewModel);
}
 
/// <summary>
/// Post new address action
/// </summary>
/// <param name="viewModel">ViewModel associated with the action</param>
/// <returns>Action result</returns>
[HttpPost]
[Authorize]
public ActionResult NewAddress(AddressViewModel viewModel)
{
    if (!this.ModelState.IsValid)
    {
        this.SetAddressParameters(viewModel);
        return this.View(viewModel);
    }
 
    WebStoreSampleMembershipUser user = Membership.GetUser().AsStarterSiteUser();
    WebStoreSampleCustomerAddress address = new WebStoreSampleCustomerAddress();
    this.UpdateCustomerAddress(address, viewModel, true);
 
    user.Profile.Addresses.Add(address);
    user.Profile.Save();
 
 
    if (String.IsNullOrEmpty(viewModel.ReturnUrl))
    {
        return this.RedirectToAction("Index");
    }
    else
    {
        return this.Redirect(viewModel.ReturnUrl);
    }
}

Changing an address:

In the same way, we use the Addresses property from the user’s profile to retrieve the address that we want to change:

using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Validation;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Models.Account
{
    public class AddressViewModel : IValidatableObject
    {
        private IEnumerable<SelectListItem> _availableCountries;
        private IEnumerable<SelectListItem> _availableRegions;
        private IEnumerable<SelectListItem> _availableTitles;
 
        public Guid? AddressId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "NameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "NameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "NameLengthErrorMessage")]
        public String Name { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "TitleIdLabel")]
        public Int32 TitleId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FirstNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FirstNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FirstNameLengthErrorMessage")]
        public String FirstName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "MiddleNameLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "MiddleNameLengthErrorMessage")]
        public String MiddleName { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "LastNameLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "LastNameRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "LastNameLengthErrorMessage")]
        public String LastName { get; set; }
 
        [DataType(DataType.EmailAddress)]
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "EmailLabel")]
        [Email(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "EmailErrorMessage")]
        [StringLength(256, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "EmailLengthErrorMessage")]
        public String Email { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FloorLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FloorLengthErrorMessage")]
        public String Floor { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "DigicodeLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "DigiCodeLengthErrorMessage")]
        public String Digicode { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line1Label")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line1RequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line1LengthErrorMessage")]
        public String Line1 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line2Label")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line2LengthErrorMessage")]
        public String Line2 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "Line3Label")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "Line3LengthErrorMessage")]
        public String Line3 { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "ZipCodeLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "ZipCodeLengthErrorMessage")]
        public String ZipCode { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CityLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CityRequiredErrorMessage")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CityLengthErrorMessage")]
        public String City { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CountryIdLabel")]
        [Required(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CountryIdRequiredErrorMessage")]
        public Int32? CountryId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "RegionIdLabel")]
        [RequiredRegion(ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "RegionRequiredErrorMessage")]
        public Guid? RegionId { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CompanyLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "CompanyLengthErrorMessage")]
        public String Company { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "MobileNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "MobileNumberLengthErrorMessage")]
        public String MobileNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "PhoneNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "PhoneNumberLengthErrorMessage")]
        public String PhoneNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "FaxNumberLabel")]
        [StringLength(50, ErrorMessageResourceType = typeof(Resources.Models.Account.AddressViewModel), ErrorMessageResourceName = "FaxNumberLengthErrorMessage")]
        public String FaxNumber { get; set; }
 
        [Display(ResourceType = typeof(Resources.Models.Account.AddressViewModel), Name = "CommentLabel")]
        [DataType(DataType.MultilineText)]
        public String Comment { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public String ReturnUrl { get; set; }
 
        public IEnumerable<SelectListItem> AvailableCountries
        {
            get
            {
                if (this._availableCountries == default(IEnumerable<SelectListItem>))
                {
                    this._availableCountries = Enumerable.Empty<SelectListItem>();
                }
                return this._availableCountries;
            }
            set
            {
                this._availableCountries = value;
            }
        }
 
        public IEnumerable<SelectListItem> AvailableRegions
        {
            get
            {
                if (this._availableRegions == default(IEnumerable<SelectListItem>))
                {
                    this._availableRegions = Enumerable.Empty<SelectListItem>();
                }
                return this._availableRegions;
            }
            set
            {
                this._availableRegions = value;
            }
        }
 
        public IEnumerable<SelectListItem> AvailableTitles
        {
            get
            {
                if (this._availableTitles == default(IEnumerable<SelectListItem>))
                {
                    this._availableTitles = Enumerable.Empty<SelectListItem>();
                }
                return this._availableTitles;
            }
            set
            {
                this._availableTitles = value;
            }
        }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Membership.GetUser().AsStarterSiteUser().Profile.Addresses.Any(a => a.Name.Equals(this.Name, StringComparison.InvariantCultureIgnoreCase) && a.AddressId != this.AddressId))
            {
                yield return new ValidationResult(Resources.Models.Account.AddressViewModel.NameAlreadyUsedErrorMessage, new String[] { "Name" });
            }
        }
    }
}
@model Magelia.WebStore.Client.Web.UI.Sample.Models.Account.AddressViewModel
@{
    ViewBag.Title = Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.EditAddress.PageTitle;
}
<article id="Article2">
    <div class="content">
        <h2>@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.EditAddress.AddressTitle</h2>
        @using (Html.BeginForm("NewAddress", "Account", FormMethod.Post))
        {
            @Html.ValidationSummary()
            @Html.EditorForModel();
            <div class="buttons">
                <ul>
                    @if (String.IsNullOrEmpty(this.Model.ReturnUrl))
                    {
                        <li>
                            @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.EditAddress.BackButtonText, "Index")
                        </li>
                    }
                    else
                    { 
                        <li><a href="@Model.ReturnUrl">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.EditAddress.BackButtonText</a>
                        </li>
                    }
                    <li>
                        <button class="highlight" type="submit">@Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.EditAddress.SaveButtonText</button>
                    </li>
                </ul>
            </div>
        }
    </div>
</article>
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Data;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        public AccountController()
        {
            WebStoreContext context = new WebStoreContext();
            this.WebStoreSampleContext = context;
        }
 
        public WebStoreContext WebStoreSampleContext { get; private set; }
 
        //...
 
        /// <summary>
        /// Get edit address action
        /// </summary>
        /// <param name="addressId">Address identifier to edit</param>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        [Authorize]
        public ActionResult EditAddress(Guid addressId, String returnUrl)
        {
            WebStoreSampleMembershipUser user = Membership.GetUser().AsSampleSiteUser();
            AddressViewModel viewModel = this.GetCustomerAddress(user.Profile.Addresses.Where(a => a.AddressId == addressId).AsStarterSiteCustomerAddresses().First());
            viewModel.ReturnUrl = returnUrl;
            this.SetAddressParameters(viewModel);
 
            return this.View(viewModel);
        }
 
        /// <summary>
        /// Post edit address action
        /// </summary>
        /// <param name="viewModel">ViewModel associated with the action</param>
        /// <returns>Action result</returns>
        [HttpPost]
        [Authorize]
        public ActionResult EditAddress(AddressViewModel viewModel)
        {
            if (this.ModelState.IsValid)
            {
                WebStoreSampleMembershipUser user = Membership.GetUser().AsSampleSiteUser();
                WebStoreSampleCustomerAddress address = user.Profile.Addresses.Where(a => a.AddressId == viewModel.AddressId).AsSampleSiteCustomerAddresses().FirstOrDefault();
                this.UpdateCustomerAddress(address, viewModel, false);
 
                user.Profile.Save();
 
                if (String.IsNullOrEmpty(viewModel.ReturnUrl))
                {
                    return this.RedirectToAction("Index");
                }
                else
                {
                    return this.Redirect(viewModel.ReturnUrl);
                }
            }
            else
            {
                this.SetAddressParameters(viewModel);
            }
            return this.View(viewModel);
        }
 
        /// <summary>
        /// Get the address ViewModel information from customer address
        /// </summary>
        /// <param name="address">Customer address</param>
        /// <returns>ViewModel information</returns>
        private AddressViewModel GetCustomerAddress(WebStoreSampleCustomerAddress address)
        {
            return new AddressViewModel
            {
                Name = address.Name,
                TitleId = (int)address.Title,
                AddressId = address.AddressId,
                FirstName = address.FirstName,
                MiddleName = address.MiddleName,
                LastName = address.LastName,
                Email = address.Email,
                Floor = address.Floor,
                Digicode = address.DigiCode,
                Line1 = address.Line1,
                Line2 = address.Line2,
                Line3 = address.Line3,
                ZipCode = address.ZipCode,
                City = address.City,
                CountryId = address.CountryId,
                RegionId = address.RegionId,
                Company = address.Company,
                PhoneNumber = address.PhoneNumber,
                MobileNumber = address.MobileNumber,
                FaxNumber = address.FaxNumber,
                Comment = address.Comments.Select(c => c.Content).FirstOrDefault()
            };
        }
 
        /// <summary>
        /// Set the address parameters for the ViewModel
        /// </summary>
        /// <param name="viewModel">ViewModel assosiated with the action</param>
        private void SetAddressParameters(AddressViewModel viewModel)
        {
            if (!viewModel.CountryId.HasValue)
            {
                viewModel.CountryId = this.WebStoreSampleContext.Location.CountryId;
            }
            viewModel.AvailableCountries = this.WebStoreSampleContext.StoreContext.AvailableCountries.Select(c => new SelectListItem { Text = c.Name, Value = c.CountryId.ToString() });
            if (viewModel.CountryId.HasValue)
            {
                viewModel.AvailableRegions = this.WebStoreSampleContext.StoreClient.GetRegions(viewModel.CountryId.Value, this.WebStoreSampleContext.Culture.LCID).Select(c => new SelectListItem { Text = c.Name, Value = c.RegionId.ToString(), Selected = c.RegionId == viewModel.RegionId });
            }
            viewModel.AvailableTitles = WebStoreContext.Titles;
        }
    }
}

Delete an address:

The user must be able to delete an address that is no longer in use. Here again, we retrieve the address to be deleted via the Addresses property from the user’s profile, then we use the Remove method:

@foreach (var address in this.Model.Addresses)
{ 
    <tr>
        <td>
            @address.Name
        </td>
        <td>
            <div class="actions">
                <ul>
                    <li>
                        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.EditLinkText, "EditAddress", new { addressId = address.AddressId })
                    </li>
                    <li>
                        @Html.ActionLink(Magelia.WebStore.Client.Web.UI.Sample.Resources.Views.Account.Index.DeleteLinkText, "DeleteAddress", new { addressId = address.AddressId })
                    </li>
                </ul>
            </div>
        </td>
    </tr>
}
using Magelia.WebStore.Client.Web.UI.Sample.Models.Account;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Profile;
using Magelia.WebStore.Client.Web.UI.Sample.Runtime.Security;
using Magelia.WebStore.Services.Contract.Data;
using Magelia.WebStore.Services.Contract.Parameters.Store;
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
 
namespace Magelia.WebStore.Client.Web.UI.Sample.Controllers
{
    public class AccountController : Controller
    {
        //...
 
        /// <summary>
        /// Get delete address action
        /// </summary>
        /// <param name="addressId">Address identifier to delete</param>
        /// <param name="returnUrl">Return Url</param>
        /// <returns>Action result</returns>
        [HttpGet]
        [Authorize]
        public ActionResult DeleteAddress(Guid addressId, String returnUrl)
        {
            WebStoreSampleMembershipUser user = Membership.GetUser().AsStarterSiteUser();
            WebStoreSampleCustomerAddress addressToDelete = user.Profile.Addresses.Where(a => a.AddressId == addressId).AsStarterSiteCustomerAddresses().FirstOrDefault();
            if (addressToDelete != null)
            {
                user.Profile.Addresses.Remove(addressToDelete);
                user.Profile.Save();
            }
            if (String.IsNullOrEmpty(returnUrl))
            {
                return this.RedirectToAction("Index");
            }
            else
            {
                return this.Redirect(returnUrl);
            }
        }
    }
}

Download the code sample of this tutorial:
How To Use The Membership And Profile Provider samples - ZIP - 20.6 mo