Showing posts with label MVC 4. Show all posts
Showing posts with label MVC 4. Show all posts

Wednesday, March 30, 2016

@Html.EnumDropDownListFor in MVC

For MVC v5.1 use Html.EnumDropDownListFor

        @Html.DropDownList("MyType", 
           Html.GetEnumSelectList(typeof(MyType)) , 
           "Select My Type", 
           new { @class = "form-control" })
    

For MVC v5 use EnumHelper

        @Html.DropDownList("MyType", 
           EnumHelper.GetSelectList(typeof(MyType)) , 
           "Select My Type", 
           new { @class = "form-control" })
    

For MVC >5 and lower

I rolled Rune's answer into an extension method:
        namespace MyApp.Common
        {
            public static class MyExtensions{
                public static SelectList ToSelectList(this TEnum enumObj)
                    where TEnum : struct, IComparable, IFormattable, IConvertible
                {
                    var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                        select new { Id = e, Name = e.ToString() };
                    return new SelectList(values, "Id", "Name", enumObj);
                }
            }
        }
    
This allows you to write:
     ViewData["taskStatus"] = task.Status.ToSelectList();
    
by
using MyApp.Common

Alternatively:
Create a custom helper class and use Html.EnumDropDownListFor for all lower version MVC < 5.1 (i.e. 3.x, 4.x, 5.0). Here is the class code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Mvc.Html;
/// 
/// Class ENUM Helper
/// 
public static class EnumHelper
{
    /// 
    /// The single empty item
    /// 
    private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = string.Empty, Value = string.Empty } };
    /// 
    /// Gets the ENUM description.
    /// 
    /// The type of the ENUM.
    /// The value.
    /// ENUM Description
    public static string GetEnumDescription(TEnum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
        if ((attributes != null) && (attributes.Length > 0))
        {
            return attributes[0].Description;
        }
        else
        {
            return value.ToString();
        }
    }
    /// 
    /// ENUMS the drop down list for.
    /// 
    /// The type of the model.
    /// The type of the ENUM.
    /// The HTML helper.
    /// The expression.
    /// MVC Html String
    public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper, Expression> expression)
    {
        return EnumDropDownListFor(htmlHelper, expression, null);
    }
    /// 
    /// ENUMS the drop down list for.
    /// 
    /// The type of the model.
    /// The type of the ENUM.
    /// The HTML helper.
    /// The expression.
    /// The HTML attributes.
    /// MVC Html String
    public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper, Expression> expression, object htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        Type enumType = GetNonNullableModelType(metadata);
        IEnumerable values = Enum.GetValues(enumType).Cast();
        IEnumerable items = from value in values
                                            select new SelectListItem
                                            {
                                                Text = GetEnumDescription(value),
                                                Value = value.ToString(),
                                                Selected = value.Equals(metadata.Model)
                                            };
        // If the enum is nullable, add an 'empty' item to the collection
        if (metadata.IsNullableValueType)
        {
            items = SingleEmptyItem.Concat(items);
        }
        return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
    }
    /// 
    /// Gets the type of the non null-able model.
    /// 
    /// The model metadata.
    /// real Model Type
    private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
    {
        Type realModelType = modelMetadata.ModelType;
        Type underlyingType = Nullable.GetUnderlyingType(realModelType);
        if (underlyingType != null)
        {
            realModelType = underlyingType;
        }
        return realModelType;
    }
}

Usage:

   @Html.EnumDropDownListFor(model => model.EnumProperty, "Select Enum", new { @class = "form-control", type = "text"})

Monday, December 2, 2013

Free 6 hour online course - Developing ASP.NET MVC 4 Web Applications Jump Start

Free 6 hour online course - Developing ASP.NET MVC 4 Web Applications Jump Start

The videos for the Developing ASP.NET MVC 4 Web Applications Jump Start Jump Start event are live on Microsoft Virtual Academy. This is an entire 9 session course, covering the official ASP.NET MVC certification course material.
If you've been wanting to learn more about ASP.NET MVC - or are perhaps studying for the ASP.NET MVC 4 certification (70-486), this is a great way to get started.
If you have friends or co-workers who are learning ASP.NET MVC, please share this with them.
I had the privilege of working with Christopher Harrison, an actual professional trainer who knows this course material pretty well. I think the end result turned out really well - just as I was typing this post I heard from someone who told me how much they enjoyed it:  "It's definitely a solid ramp up for people who are new (like myself) to MVC. Also, much more entertaining then most other tutorials I've seen around." That's exactly what we were hoping for - serious training that's fun to watch.

Saturday, June 22, 2013

Trouble Deleting Users in SimpleMembership

I came across a question in StackOverflow the other day where someone was having trouble deleting a user in the SimpleMembership provider that is now the default provider in ASP.NET MVC 4 Internet Applications.  The problem he was having was that when he called SimpleMembershipProvider.DeleteUser it was deleting the data in the UserProfiletable and not in the webpages_Membership table. First a little bit on what these two tables are about.

SimpleMembership is designed to put the user information in these two tables, which have a one-to-zero-or-one relationship.  The UserProfile table has a unique UserId and a UserName, and UserProfile can be customized by the developer.  This UserId is a foreign key for the webpages_Membership table, which contains the password and other security information in it.  The reason for keeping information in these table separate is that the data in webpages_Membership is not required if OAuth is being used. If OAuth is being used then the password and other security details will be on another system.

Now back to the problem. I found it hard to believe that using DeleteUser did not remove both tables because here is what the documentation says.

This method deletes the entry in the membership account table (by default, webpages_Membership). If deleteAllRelatedData is true, all user data that is stored in the user table is also deleted.

So here is the quick and dirty test I ran.

?
1
2
3
4
5
6
7
8
9
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
if (membership.GetUser("test", false) == null)
{
    membership.CreateUserAndAccount("test", "test");
}
bool wasDeleted = membership.DeleteUser("test", true);

I stepped through with the debugger after the CreateUserAndAccount and saw an entry for the user in both tables. Then I stepped over DeleteUser and checked the database again. The entry in UserProfile was gone but the one inwebpages_Membership was still there.  This was a far cry from what the documentation described as the behavior for this method and verified what the person asking the question in StackOverflow observed.

So I thought I would try something else to see if I could come up with a workaround for this issue. Here is the code I tried.

?
1
2
3
4
5
6
7
8
9
10
11
var roles = (SimpleRoleProvider)Roles.Provider;
var membership = (SimpleMembershipProvider)Membership.Provider;
if (membership.GetUser("test", false) == null)
{
    membership.CreateUserAndAccount("test", "test");
}
bool wasDeleted = membership.DeleteAccount("test");
wasDeleted = membership.DeleteUser("test", true);

Now when I stepped through with the debugger when I hit DeleteAccount the entry from webpages_Membershipwas removed and then when I hit DeleteUser the entry in UserProfile was removed. Now we do not have any orphans hanging around.  Not sure if and when Microsoft will fix this bug but at least there is a workaround.

I should also point out that if you have a user mapped to roles using DeleteUser will throw a foreign key exception. You have to remove any mapped roles before you can use it.

Find a cool free stuff everyday

Giveaway of the Day

Hiren Bharadwa's Posts

DotNetJalps