I'm quite new to both ASP.Net and MVC.
I got the following code in my master page:
  <div id="main-menu" class="menu">
  <%
   var items = (IList<CompanyName.Framework.Web.MenuItem>)ViewData["MainMenu"];
   if (items.Count > 0)
   {
    %><ul><%
    foreach (var item in items)
    {
     if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
      continue;
     %><li><a href="<%= item.Uri %>"><%= item.Title %></a></li><%
    }
    %></ul><%
   }
  %>
 </div>
Can I move the code to another file or refactor the code in any way?
edit:
My ApplicationController that all controllers derive:
public class ApplicationController : Controller
{
    List<MenuItem> _mainMenu = new List<MenuItem>();
    List<MenuItem> _contextMenu = new List<MenuItem>();
    protected IList<MenuItem> MainMenu
    {
        get { return _mainMenu; }
    }
    protected IList<MenuItem> ContextMenu
    {
        get { return _contextMenu; }
    }
    protected string PageTitle { get; set; }
    protected override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        ViewData["PageTitle"] = PageTitle;
        ViewData["MainMenu"] = MainMenu;
        ViewData["ContextMenu"] = ContextMenu;
        base.OnResultExecuting(filterContext);
    }
}
                Here are a couple of suggestions:
Improvement number 1: use view models and strongly typed views instead of ViewData
public ActionResult Index()
{
    // TODO: Fetch this data from a repository
    var menus = new[] {
        new MenuItem(), new MenuItem()
    }.ToList();
    return View(menus);
}
and then in your view:
<div id="main-menu" class="menu">
    <%
        if (Model.Count > 0)
        {
            %><ul><%
            foreach (var item in Model)
            {
                if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
                    continue;
                %><li><a href="<%= item.Uri %>"><%= item.Title %></a></li><%
            }
            %></ul><%
        }
    %>
</div>
Still horrible and completely unreadable tag soup.
Improvement number 2: use editor/display templates:
In ~/Views/Home/DisplayTemplates/MenuItem.ascx:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (!string.IsNullOrEmpty(Model.RequiredRole) &&
       System.Threading.Thread.CurrentPrincipal.IsInRole(Model.RequiredRole)) { %>
    <li>
        <a href="<%= Model.Uri %>"><%= Model.Title %></a>
    </li>
<% } %>
And then in your main view:
<div id="main-menu" class="menu">
    <ul>
        <%= Html.DisplayForModel() %>
    </ul>
</div>
Improvement number 3: Avoid coding business rules in a view. So in your view model add a property:
public bool IsLinkVisible
{
    get
    {
        return !string.IsNullOrEmpty(RequiredRole) &&
               Thread.CurrentPrincipal.IsInRole(RequiredRole);
    }
}
so that your display template now looks like this:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (Model.IsLinkVisible) { %>
    <li>
        <a href="<%= Model.Uri %>"><%= Model.Title %></a>
    </li>
<% } %>
Improvement number 4: Write a custom HTML helper to render this anchor because writing C# in a view is still ugly and untestable:
public static class HtmlExtensions
{
    public static MvcHtmlString MenuItem(this HtmlHelper<MenuItem> htmlHelper)
    {
        var menuItem = htmlHelper.ViewData.Model;
        if (!menuItem.IsLinkVisible)
        {
            return MvcHtmlString.Empty;
        }
        var li = new TagBuilder("li");
        var a = new TagBuilder("a");
        a.MergeAttribute("href", menuItem.Uri);
        a.SetInnerText(menuItem.Title);
        li.InnerHtml = a.ToString();
        return MvcHtmlString.Create(li.ToString());
    }
}
and finally your display template:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<%= Html.MenuItem() %>
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With