Monday 8 February 2010

DisplayNameAttribute Localized

So here is a simple Attribute, extending the DisplayNameAttribute, inspired from a post on stackoverflow


using System;
using System.Linq;
using System.ComponentModel;
using System.Reflection;
using System.Resources;

namespace MvcExtensions.Attributes
{
[AttributeUsage(AttributeTargets.Property AttributeTargets.Field, AllowMultiple = false)]
public class DisplayNameLocalizedAttribute : DisplayNameAttribute
{
public DisplayNameLocalizedAttribute(Type resourceType, string resourceKey)
: base(LookupResource(resourceType, resourceKey)) { }

internal static string LookupResource(Type resourceType, string resourceKey)
{
PropertyInfo property = resourceType.GetProperties().FirstOrDefault(p => p.PropertyType == typeof(System.Resources.ResourceManager));
if (property != null)
{
return ((ResourceManager)property.GetValue(null, null)).GetString(resourceKey);
}
return resourceKey;
}
}
}

An I use it simply like this:


using MvcExtensions.Attributes;
using MyMvc2Rc2TestApp.App_LocalResources;

namespace MyTestMVC2App.Areas.UserManagement.Models
{
public class User
{
[DisplayNameLocalized(typeof(DisplayName), "User_UserName")]
public string UserName { get; set; }
[DisplayNameLocalized(typeof(DisplayName), "User_Password")]
public string Password { get; set; }
[DisplayNameLocalized(typeof(DisplayName), "User_FirstName")]
public string FirstName { get; set; }
[DisplayNameLocalized(typeof(DisplayName), "User_LastName")]
public string LastName { get; set; }
[DisplayNameLocalized(typeof(DisplayName), "User_Email")]
public string Email { get; set; }
}
}

I have a DisplayName.resx file in App_LocalResources, it is an Embedded Resource with Public Access Modifier

Asp.Net MVC Manager for javascript include and Css files

I was trying to figure a way to automatically include javascript from html helpers and from view without having to check if it wasn't already in the master so i came up with a simple manager. It is greatly inspired by Frugal Coder Blog and Chris Pietschmann. I build an abstarct manager to perform the operation required by the javascript and css manager.
so here it is :


using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;

namespace MvcExtensions
{
public abstract class MvcManager
{
protected HtmlHelper _htmlHelper;
protected Dictionary<string, TagBuilder> _include = new Dictionary<string, TagBuilder>();

public MvcManager(HtmlHelper htmlHelper)
{
this._htmlHelper = htmlHelper;
}

public virtual MvcManager Include(string path)
{
if (!this._include.ContainsKey(path))
{
this._include.Add(path, this.BuildTag(UrlHelper.GenerateContentUrl(path, this._htmlHelper.ViewContext.HttpContext)));
}
return this;
}

public virtual MvcHtmlString Render()
{
StringBuilder sb = new StringBuilder();
foreach (var item in this._include.Values)
{
sb.AppendLine(item.ToString());
}
return MvcHtmlString.Create(sb.ToString());
}

protected abstract TagBuilder BuildTag(string src);
}
}


And now for the javascript manager:





using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

namespace MvcExtensions
{
public class MvcClientScriptManager : MvcManager
{
private List<string> _readyLine = new List<string>();

public MvcClientScriptManager(HtmlHelper htmlHelper) : base(htmlHelper) { }

public new MvcClientScriptManager Include(string path)
{
return (MvcClientScriptManager)((MvcManager)this).Include(path);
}
public MvcClientScriptManager Include(string path, string debugPath)
{
string file = this._htmlHelper.ViewContext.HttpContext.IsDebuggingEnabled ? debugPath : path;
return this.Include(file);
}

public MvcClientScriptManager AddToReady(string code)
{
this._readyLine.Add(code);
return this;
}

protected override TagBuilder BuildTag(string src)
{
TagBuilder scriptTag = new TagBuilder("script");
scriptTag.MergeAttribute("type", "text/javascript");
scriptTag.MergeAttribute("src", src);
return scriptTag;
}

public override MvcHtmlString Render()
{
if (this._readyLine.Any())
{
StringBuilder sb = new StringBuilder(base.Render().ToString());
sb.AppendLine("<script type=\"text/javascript\">");
sb.AppendLine("$(function() {");
foreach (var item in this._readyLine)
{
sb.AppendLine("\t" + item);
}
sb.AppendLine("});");
sb.AppendLine("</script>");
return MvcHtmlString.Create(sb.ToString());
}
return base.Render();
}
}
}


The CssManager :


using System.Web.Mvc;

namespace MvcExtensions
{
public class MvcCssManager : MvcManager
{
public MvcCssManager(HtmlHelper htmlHelper) : base(htmlHelper) { }

public new MvcCssManager Include(string path)
{
return (MvcCssManager)base.Include(path);
}

protected override TagBuilder BuildTag(string src)
{
TagBuilder linkTag = new TagBuilder("link");
linkTag.MergeAttribute("type", "text/css");
linkTag.MergeAttribute("rel", "stylesheet");
linkTag.MergeAttribute("href", UrlHelper.GenerateContentUrl(src, this._htmlHelper.ViewContext.HttpContext));
return linkTag;
}
}
}


my master page now looks like this:


<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<% Html.MvcCssManager().Include("~/Content/Css/Site.css"); %>
<asp:ContentPlaceHolder ID="HeadContent" runat="server" />

<%= Html.MvcCssManager().Render()%>
</head>

<body>
<div class="page">

<div id="header">
<div id="title">
<h1>My MVC Application</h1>
</div>

<div id="logindisplay">
<% Html.RenderPartial("LogOnUserControl"); %>
</div>

<div id="menucontainer">

<ul id="menu">
<li><%= Html.ActionLink("Home", "Index", "Home")%></li>
<li><%= Html.ActionLink("About", "About", "Home")%></li>
<li><%= Html.ActionLink("Users", "List", "UserManagement")%></li>
</ul>

</div>
</div>

<div id="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />

<div id="footer">
</div>
</div>
</div>

<%= Html.MvcClientScriptManager().Render() %>

</body>
</html>



And finally a sample view in which I use it:





<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyTestMVC2App.Areas.UserManagement.Models.User>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="HeadContent" runat="server">
<%
Html.MvcClientScriptManager()
.Include("~/Scripts/MicrosoftAjax.js", "~/Scripts/MicrosoftAjax.debug.js")
.Include("~/Scripts/MicrosoftMvcValidation.js", "~/Scripts/MicrosoftMvcValidation.debug.js");
Html.MvcCssManager().Include("~/Content/Css/Jquery.UI/base/ui.all.css");
%>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Edit</h2>

<% Html.EnableClientValidation(); %>

<% using (Html.BeginForm()) {%>

<fieldset>
<legend>Fields</legend>

<%= Html.EditorForModel() %>

<p>
<input type="submit" value="Save" />
</p>
</fieldset>

<% } %>

<div>
<%=Html.ActionLink("Back to List", "List") %>
</div>

</asp:Content>



So now I'm only referencing script and css hosted on my site but thats for another post...


Feel free to leave comment, I would love to have some feed-back on this.