An extension method to create a SelectList, make your code neat & clean in MVC

When you have an IEnumerable model list bind to a select list items, you always need to write

var Items = Service.FindAll().Select(p => new SelectListItem() { Text = p.Name, Value = p.Id });

Here I create a extension method of IEnumerable<T> called “ToSelectList”,

    public static class SelectListExtensions
    {
        public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> items,
            Func<T,string> text, Func<T,string> value = null, Func<T,Boolean> selected = null)
        {
            return items.Select(p => new SelectListItem
            {
                Text = text.Invoke(p),
                Value = (value==null? text.Invoke(p): value.Invoke(p)),
                Selected = selected == null? false: selected.Invoke(p)
            });
        }
    }

When you read the list from database and bind to a select list, you can write this way,

var Items = Service.FindAll().ToSelectList(p=>p.Name, p=>p.Id);
Advertisements

Implement FormsAuthentication with custom identity in asp.net/ MVC

Sometimes you want to save more data into the authentication cookie rather than retrieve them from database all the time.

So I come up this way to create a custom Identity to allow you retrieve extra data from authentication cookies.

1. To create an identity, you need to implement the interface IIdentity.

I added Email & Roles as properties of the MyIdentity. And retrieve the data from FormsAuthenticationTicket.UserData (which is passed into MyIdentity’s constructor)


public class MyIdentity : IIdentity
 {
private System.Web.Security.FormsAuthenticationTicket ticket;

public MyIdentity(System.Web.Security.FormsAuthenticationTicket ticket)
{
this.ticket = ticket;
}

public string AuthenticationType
{
get { return "MobileOrder"; }
}

public bool IsAuthenticated
{
get { return true; }
}

public string Name
{
get { return ticket.Name; }
}

public string Email
{
get
{
string[] data = ticket.UserData.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
if (data.Length > 0)
return data[0];
else
return "";
}
}

public string[] Roles
{
get
{
string[] data = ticket.UserData.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
if (data.Length > 1)
{
string[] roles = data[1].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return roles;
}
else
return new string[] { "User" };
}
}
 }

2. I created an AuthenticationHelper to create the cookie and assign the extra data to the Ticket’s UserData.


public class AuthenticationHelper
{
public static void CreateAuthCookie(int id, string email, DateTime expiration, string[] roles, bool rememberMe)
{
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
id.ToString(), // user name
DateTime.Now,
expiration, //Expiration
rememberMe, //Persistent
CreateAuthTags(email, roles));

string encTicket = FormsAuthentication.Encrypt(authTicket);

HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
}

public static string CreateAuthTags(string email, string[] roles)
{
StringBuilder sb = new StringBuilder();
sb.Append(email);
sb.Append("|");
for (int i = 0; i < roles.Length; i++)
{
sb.Append(roles[i]);
if (i < roles.Length - 1)
sb.Append(",");
}
return sb.ToString();
}
}

3. In Global.asax, register MvcApplication_PostAuthenticateRequest event to cast generic Identity to MyIdentity and assign back to the Principal in HttpContext.Current.User


public override void Init()
{
this.PostAuthenticateRequest += new EventHandler(MvcApplication_PostAuthenticateRequest);
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);
MyIdentity id = new MyIdentity(ticket);
GenericPrincipal prin = new GenericPrincipal(id, id.Roles);
HttpContext.Current.User = prin;
}
}
}

4.  To read the MyIdentity from your pages or views

((MyIdentity)HttpContext.Current.User.Identity).Email;

Alternatively you can create PartialView for the login status and put it in _Layout.cshtml. eg.


@if(Request.IsAuthenticated) {

<ul>
<li class="small">@(((Mobile.Order.Web.Common.Identity.MyIdentity)HttpContext.Current.User.Identity).Email)</li>

|

<li>@Html.ActionLink("Account", "Index", "Account")</li>

|

<li>@Html.ActionLink("Log Off", "LogOff", new { controller = "Account", returnUrl = HttpContext.Current.Request.RawUrl })</li>

</ul>

}

else

{

<ul>

<li>

@*@Html.ActionLink("Login", "Login", "Account")*@

<a href="/Account/AjaxLogin" id="loginButton">Login</a>

</li>

|

<li>@Html.ActionLink("Register", "Index", "Register")</li>

</ul>

}