MVC Highlight Active Navigation Tab

The top navigation bar on most sites has some form of highlight to allow the user to quickly see what section of the site they are viewing. In MVC this can be accomplished with a simple HTML and CSS modification.

Modify the Controller(s)

You will need to pass a variable <code>@currentPage</code> to your view from the appropriate controller(s).

//
// GET: /Product/

public ActionResult Index()
{
	ViewBag.CurrentPage = "Products";

	return View();
}

Modify the Shared View

You will need to modify the <body> tag of _Layout.cshtml to include an id. In the code (below) I go the extra step of converting the string to lowercase to match the CSS no matter how a developer types the CurrentPage in the controller.

@{
    string currentPage = @ViewBag.CurrentPage.ToLower();
}
<body class="homepage" id="@currentPage">

Modify the CSS

If using a minified CSS this part can be a bit of a pain, but still possible. In your CSS file add code or modify an existing block, a:hover for example, to include the body tags.

body#home a#home,
body#blog a#blog,
body#apparel a#apparel,
body#comics a#comics,
body#gadgets a#gadgets,
body#games a#games,
body#movies a#movies
{
	background: #d52349;
	color: #fff !important;
	font-weight: 700;
}

Tying it All Together

Whenever a bodyID matches the CSS, the active section will be highlighted.

07072014_001

Further Reading

Original credit goes to Bhavin Surela – Highlighting current page in MVC 3 – Slick Trick.

POST a Model with an Image Attachment

MVC POST a Model with Image

When POSTing a model you may need to stream some file content; like an image. The template controller will need to be modified to accomplish this. For this example, we will look at the source code I used to add ‘products’ to theCosmics.com. You will notice the use of the [Authorize] data annotation, which means only a logged in user can submit the POST.

The Product Model

Note that the model has properties for ImageData and ImageMimeType. If you need to update your models, be sure to enable data migrations.

namespace theCosmics.Models
{
    public class Product
    {
        // Product Details
        public int ID { get; set; }
        [Required]
        public string Category { get; set; }
        [Required]
        public string ProductName { get; set; }
        [Required]
        public decimal Price { get; set; }
        [Required]
        public string ProductHeader { get; set; }
        [Required]
        [DataType(DataType.MultilineText)]
        public string LongDescription { get; set; }
        [Required]
        public string TrackingURL { get; set; }

        // Image
        public byte[] ImageData { get; set; }
        public string ImageMimeType { get; set; }

        // Page Hit Tracking
        public int Hits { get; set; }

        // Featured Flag
        public bool Featured { get; set; }
    }
}

The Create View

You will need to modify the default template’s Html form to include the multipart/form-data. Right now my ListItems are hardcoded so please forgive that bit of rough code.

@model theCosmics.Models.Product

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm("Create", "Product", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Product</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Category)
        </div>
        @{
            // TODO: Make this a method to dynamically get/post the data
            List<SelectListItem> listItems = new List<SelectListItem>();
            listItems.Add(new SelectListItem
                {
                    Text = "Apparel",
                    Value = "Apparel"
                });
            listItems.Add(new SelectListItem
            {
                Text = "Comics",
                Value = "Comics"
            });
            listItems.Add(new SelectListItem
            {
                Text = "Gadgets",
                Value = "Gadgets"
            });
            listItems.Add(new SelectListItem
            {
                Text = "Games",
                Value = "Games"
            });
            listItems.Add(new SelectListItem
            {
                Text = "Movies",
                Value = "Movies"
            });
        }

        <div class="editor-field">
            @Html.DropDownListFor(model => model.Category, listItems, "-- Category --")
            @Html.ValidationMessageFor(model => model.Category)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductName)
            @Html.ValidationMessageFor(model => model.ProductName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductHeader)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductHeader)
            @Html.ValidationMessageFor(model => model.ProductHeader)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LongDescription)
        </div>
        <div class="editor-field">
            @Html.TextAreaFor(model => model.LongDescription, new {style = "width: 50%; height: 200px;"})
            @Html.ValidationMessageFor(model => model.LongDescription)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.TrackingURL)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.TrackingURL)
            @Html.ValidationMessageFor(model => model.TrackingURL)
        </div>
        <div>
            <label>Image</label>
            <p>Upload new image: <input type="file" name="Image" /></p>
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Product", "Admin", new { Category = @ViewBag.Category } , null)
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Modifying the Edit Method for the Product Controller

//
// POST: /Product/Create
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Product product, HttpPostedFileBase image)
{
	if (ModelState.IsValid)
	{
		if (image != null)
		{
			product.ImageMimeType = image.ContentType;
			product.ImageData = new byte[image.ContentLength];
			image.InputStream.Read(product.ImageData, 0, image.ContentLength);
		}

		product.Hits = 0;
		db.Products.Add(product);
		db.SaveChanges();

		// Send user back to the appropriate admin
		return RedirectToAction("Product", "Admin", new { Category = product.Category });
	}

	return View(product);
}

In the code (above) I have modified the parameters of the Create method to include a second parameter
HttpPostedFileBase. As long as the image is not null, it will save two columns of data to the database; the first column is the MIME type (jpg, gif, png, etc.) and the second column is the byte data of the image. NOTE: You will need to modify your EDIT controller method, too.

Using the Image

The webapp can use the SQL data to reassemble the data into a usable image using a new controller.

//
// GET: /Product/GetImage/5

public FileContentResult GetImage(int id)
{
	Product product = db.Products.Find(id);
	if((product.ImageData != null) && (product.ImageMimeType != null))
	{
		return File(product.ImageData, product.ImageMimeType);
	}
	else
	{
		return null;
	}
}

This controller will accept the model’s ID and return the image for that product.

Further Reading

Pro ASP.NET MVC 2 Framework

  • Much of the code (above) is derived from this book.

Create a BootStrap Enabled MVC5 Web Application

About MVC

The Model-View-Controller (MVC) architectural pattern separates an application into three main components: the model, the view, and the controller. The ASP.NET MVC framework provides an alternative to the ASP.NET Web Forms pattern for creating MVC-based Web applications. The ASP.NET MVC framework is a lightweight, highly testable presentation framework that (as with Web Forms-based applications) is integrated with existing ASP.NET features, such as master pages and membership-based authentication. The MVC framework is defined in the System.Web.Mvc namespace and is a fundamental, supported part of the System.Web namespace.
http://www.asp.net/mvc/tutorials/older-versions/overview/asp-net-mvc-overview

About Bootstrap

Bootstrap was created at Twitter in mid-2010 by @mdo and @fat. Prior to being an open-sourced framework, Bootstrap was known as Twitter Blueprint. A few months into development, Twitter held its first Hack Week and the project exploded as developers of all skill levels jumped in without any external guidance. It served as the style guide for internal tools development at the company for over a year before its public release, and continues to do so today.
http://getbootstrap.com/about/

What you need to get started

Creating your new project

With MVC4 templates you had to remove/replace the css and html, which was a time consuming practice. The MVC4 template require a lot more work so MVC5 is a boon for developers needing to crank out multiple sites.

  1. Open Visual Studio
  2. Click File, hover over New, and select Project
  3. In the left navigation tree go to click Installed, select Visual C#, then select Web
  4. Name your project and click the OK button
  5. Select MVC as the template and click the OK button
    • You can also select Web API and Unit Test in the add folders and core references section
      • Unit tests are a must for professional/production projects
      • The Web API is a RESTful http service that can be called from other projects like a mobile app
  6. Press [F5] to preview the web application in debug mode
  7. (Optional) Change the web.config file’s database settings
    • By default, the template will create and mount databases as needed.
    • Change the connection string if;
      • You cannot create and mount databases programmatically (an issue I ran into with Arvixe web hosting)
      • You are using database first rather than model first or code first

Further Reading

Getting started with MVC5

  • An in-depth guide from Microsoft

Bootstrap Components

  • An overview of everything included in Bootstrap