pr0g33k

 collapse all
  1. Clearing Containers with overflow: hidden

    I recently completed a side-project where I needed to create two columns of text floated left and right. The text of each column was laid out in an unordered list and was dynamically generated using data from a database. This meant that one column could, at any point, be taller than the other column. This was fine until I wanted to place a vertical line separating the two columns. I could have used a border on the left or right of either unordered list but if one grew taller, the border of the other wouldn't grow with it. Then it hit me, why not use a background image in the container? Here's the markup and corresponding CSS:

    <div class="columns">
        <div class="column1">
            <ul>
                <li>Column 1, Item 1</li>
                <li>Column 1, Item 2</li>
                <li>Column 1, Item 3</li>
                <li>Column 1, Item 4</li>
            </ul>
        </div>
        <div class="column2">
            <ul>
                <li>Column 2, Item 1</li>
                <li>Column 2, Item 2</li>
                <li>Column 2, Item 3</li>
                <li>Column 2, Item 4</li>
                <li>Column 2, Item 5</li>
                <li>Column 2, Item 6</li>
                <li>Column 2, Item 7</li>
                <li>Column 2, Item 8</li>
            </ul>
        </div>
    </div>
        
    <style>
        .columns {
            background: url(/images/vertical-line.png) repeat-y 50% 0;
            width: 402px;
        }
    
        .column1 {
            float: left;
            width: 200px;
        }
    
        .column2 {
            float: right;
            width: 200px;
        }
    </style>
        

    Unfortunately, this is what I got:

    • Column 1, Item 1
    • Column 1, Item 2
    • Column 1, Item 3
    • Column 1, Item 4
    • Column 2, Item 1
    • Column 2, Item 2
    • Column 2, Item 3
    • Column 2, Item 4
    • Column 2, Item 5
    • Column 2, Item 6
    • Column 2, Item 7
    • Column 2, Item 8

    Where's my background image? It turns out that a container of floated elements does not automatically clear the floats of its child elements. The container instead assumes its default height (0px in the case of  a div) or whatever height it is assigned. I don't want to assign a height in this case, though; I want the container to size to the height of whichever child is tallest.

    The solution is to set the overflow to hidden on the container. If I change the CSS to this:

        <style>
            .columns {
                background: url(/images/vertical-line.png) repeat-y 50% 0;
                overflow: hidden;
                width: 402px;
            }
    
            .column1 {
                float: left;
                width: 200px;
            }
    
            .column2 {
                float: right;
                width: 200px;
            }
        </style>
        

    Then this is what I get:

    • Column 1, Item 1
    • Column 1, Item 2
    • Column 1, Item 3
    • Column 1, Item 4
    • Column 2, Item 1
    • Column 2, Item 2
    • Column 2, Item 3
    • Column 2, Item 4
    • Column 2, Item 5
    • Column 2, Item 6
    • Column 2, Item 7
    • Column 2, Item 8

    It also means that I don't have to follow the container with an element assigned "clear: both" to clear the preceding floats.

    Posted on 7/23/2013 at 02:07 PM , Edited on 7/23/2013 at 02:07 PM
    Tags: HTML5CSS
  2. Displaying an enum in an MVC DropDown with custom text using the DisplayAttribute

    I'm working on a project that has several classes with enum-backed properties. When rendering those properties in an MVC view, I wanted to display them as a dropdown list. Here's an extension method I created that does that:

    public static IHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        Type enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
        IEnumerable<Object> enumValues = Enum.GetValues(enumType).Cast<Object>();
        IEnumerable<SelectListItem> items = from enumValue in enumValues
                                            select new SelectListItem
                                            {
                                                Text = enumValue.ToString(),
                                                Value = ((Int32)enumValue).ToString(),
                                                Selected = enumValue.Equals(metadata.Model)
                                            };
        return html.DropDownListFor(expression, items, String.Empty, null);
    }
        

    This extension takes the enum and displays each enumerator exactly as it's written. That seemed to work pretty well for the simple enums I had in my project. Then I created and enum that looked like this:

    public enum DeliveryMethod
    {
        CompetitiveSealedProposal,
        ConstructionManagerRisk,
        ConstructionManagerAgent
    }
        

    That gave me a pretty ugly dropdown list and didn't match up with the customer's definitions for those items and what they wanted to see in the UI. Then it hit me: I can use the DisplayAttribute and give each enumeration a "Name."

    public enum DeliveryMethod
    {
        [Display(Name = "Competitive Sealed Proposal")]
        CompetitiveSealedProposal,
        [Display(Name = "Construction Manager @ Risk")]
        ConstructionManagerRisk,
        [Display(Name = "Construction Manager - Agent")]
        ConstructionManagerAgent
    }
        

    Next, I added a function to extract the value from the DisplayAttribute:

    private static String GetText(Object e)
    {
        FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
        DisplayAttribute[] displayAttributes = fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];
        return null != displayAttributes && displayAttributes.Length > 0 ? displayAttributes[0].Name : e.ToString();
    }
        

    Then I updated the extension to take advantage of the new function:

    public static IHtmlString DropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        Type enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
        IEnumerable<Object> enumValues = Enum.GetValues(enumType).Cast<Object>();
        IEnumerable<SelectListItem> items = from enumValue in enumValues
                                            select new SelectListItem
                                            {
                                                Text = GetText(enumValue),
                                                Value = ((Int32)enumValue).ToString(),
                                                Selected = enumValue.Equals(metadata.Model)
                                            };
        return html.DropDownListFor(expression, items, String.Empty, null);
    }
        

    Voila! Using the extension is as simple as this:

    @Html.DropDownListFor(m => m.DeliveryMethod)
        

    The extension also takes care of the selected value.

  3. SimpleMembershipProvider Error When Restarting Application After Authentication

    If you're using the SimpleMembershipProvider in MVC4 and using the MVC template that includes the InitializeSimpleMembershipAttribute class in the Filters directory, you might have come across an issue when you restart your application after logging in. The error that's thrown states that, “You must call the 'WebSecurity.InitializeDatabaseConnection' method before you call any other method of the 'WebSecurity' class. It appears that the filter does not initialize the database connection early enough in the lifecycle to be picked up by the SimpleRoleProvider. For example, this will occur if you have methods decorated with the [Authorize] attribute and you're limiting access to a particular set of roles (e.g. [Authorize(Roles = "Administrator")]). Attempting to access the roles provider in this case causes the error to occur if the application is restarted (e.g. as a result of making a change to the Web.Config or a recompile).

    The solution is to move the initialization to Application_Start(). In keeping with the existing code in Application_Start(), I added a new class in the App_Start directory called "WebSecurityConfig"

    public class WebSecurityConfig
    {
        public static void Initialize()
        {
            Database.SetInitializer<UsersContext>(null);
    
            try
            {
                if (!WebSecurity.Initialized)
                    WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("The database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
            }
        }
    }
        

    Then, in Application_Start(), add: WebSecurityConfig.Initialize();

    Delete the InitializeSimpleMembershipAttribute from your project as well as any [InitializeSimpleMembership] attributes on your controller methods.

  4. Goodbye, Kona. Hello, Prism for the Windows Runtime!

    I've been waiting for a long time to get my hands on a good MVVM library for WinRT. I was excited to hear about Kona, the Prism port for WinRT, and when it came out in beta I snapped it up. I have a WinRT project I've been working on for a while but I didn't want to dedicate too much time to the UI until Kona was released in full. Well, the wait is over!

    http://prismwindowsruntime.codeplex.com/

    I was initially shocked and saddened to hear that Kona was dead. WHAT?! Come to find out, "Kona" was just the working name for the project. Once it was solid, the Patterns & Practices group released it as Prism for the Windows Runtime. Evidently they released it last month when I wasn't looking. I'm always last to the party, it seems.

  5. Creating a RSS Feed Using a Custom ActionResult

    When it came time to create an RSS feed for this blog, I almost fell back on what I'd done in the past - create a generic handler to output the XML. Since I'm doing everything I can to use MVC these days, I wanted to find the "MVC way" to output an RSS feed. I figured there was a way to use a controller but when I used Bing to Google it (special thanks to Scott Hanselman for that joke), all I could find was people using a controller to pass data to a view and then run a loop in the markup to assemble the XML. That just seemed gross to me. I wanted more of a C# code approach - especially since the good folks at Microsoft went to the trouble of creating the System.ServiceModel.Syndication namespace. Finally I stumbled across a forum post that referenced a video of Scott Hanselman using System.Web.Mvc.FileResult as a base to create a custom ActionResult. Bingo! The RssController looks like this:

    public class RssController : Controller
    {
        public ActionResult Index()
        {
            return new RssResult();
        }
    }
        

    That's just sexy. The RssResult looks like this:

    public class RssResult : FileResult
    {
        public RssResult() : base("application/rss+xml") { }
    
        protected override void WriteFile(HttpResponseBase response)
        {
            List<SyndicationItem> syndicationItems = new List<SyndicationItem>();
            List<Blog> blogs = BlogManager.Instance.GetEntitiesForRss(HttpContext.Current.Request.Url.Host, 1, 25);
            String url;
    
            foreach (Blog blog in blogs)
            {
                url = String.Format("http://www.pr0g33k.com/blog/{0}/{1}", blog.Id, blog.Title.ToSlug());
                syndicationItems.Add(new SyndicationItem(blog.Title, String.Format("{0}<p><a href=\"{1}\">Read more...</a></p>", blog.Body, url), new Uri(url), url, blog.CreateDate.ToUniversalTime())
                {
                    PublishDate = blog.CreateDate.ToUniversalTime()
                });
            }
    
            SyndicationFeed syndicationFeed = new SyndicationFeed("pr0g33k's Blog", "pr0g33k (Robert Gaut) is a Dallas-area Microsoft .NET developer who specializes in C#, MVC 4, WPF, Silverlight, WCF, HTML5, jQuery/JavaScript, and code generation. pr0g33k's blog covers those technologies as well as other technologies that he finds cool and interesting.", new Uri("http://www.pr0g33k.com/rss"), syndicationItems);
            syndicationFeed.Authors.Add(new SyndicationPerson("pr0g33k@hotmail.com", "Robert Gaut", "http://www.pr0g33k.com"));
            SyndicationFeedFormatter feedFormatter = new Rss20FeedFormatter(syndicationFeed);
    
            using (XmlWriter xmlWriter = XmlWriter.Create(response.Output))
            {
                feedFormatter.WriteTo(xmlWriter);
            }
        }
    }
        

    The BlogManager.Instance.GetEntitiesForRss() function is part of my code-generated DAL. Everything else is pretty standard. You can see the output here. This is also very testable using automated testing if you're into that sort of thing - much moreso than generating the RSS/XML in a view.

    Posted on 5/14/2013 at 08:05 PM , Edited on 5/24/2013 at 06:05 PM
    Tags: C#MVC