Sitecore MVC Area Controller Rendering Type


I saw this post a couple weeks back about working with Areas in Sitecore MVC. One of the issues was that you had to specify the view path in all of the actions because Sitecore didn’t understand what area you are in. To get around this I created my own rendering type that allows me to specify an Area field. The Area is then added to the Route Values Dictionary. I’m expecting this would also fix other problems with working in areas, like linking. I do however recomend that you strongly type the controller name when entering it as Sitecore is not using the Area field when it resolves the controller. Perhaps that code could be updated as well.

The code is here and the package to install it is here.

There are three classes that I will describe below :

AreaController
This class checks to see if the Rendering Item inherits the Area Controller Template. If it does we Assign the AreaControllerRenderer as the Renderer.

AreaControllerRender

This class passes the Action, Controller and Area to the AreaControllerRunner and returns the html to Sitecore.

AreaControllerRunner

This class executes the controller.  The big change is made here where I pass the Area in the Route Values Colleciton.  The important line to get area support is below.

requestContext.RouteData.DataTokens[“area”] = this.Area;

 

There is also a Sitecore.MVC.SitecoreAreas.config file that causes the code to execute in the GetRenderer Pipeline and a new template ‘Sitecore/Templates/User Defined/Mvc Areas/Area Controller’ that has the template to inherit from your rendering.

I personally think everything should be done in areas as it makes things more portable to other projects.  If you’re not using areas you can also use this project as a sample on how to extend Sitecore to support your own rendering type.

Advertisements

Auto Complete in Razor MVC with JQuery and LINQ to Entities


I had to create an auto-complete text box this week in Razor and didn’t see anything specific to doing it in Razor so I thought I’d throw this out there. I would like to say this post for getting it to work in MVC was very helpful and it didn’t take much effort to move from that to Razor and the Entity Framework.

In my example below I’ll be auto populating the product name based on the existing product names in the database using LINQ to Entities.

Step 1 : Download the JQuery Auto-Complete Library from google code

http://code.google.com/p/jquery-autocomplete/downloads/list

Step 2: Extract the following files into your scripts directory

jquery.autocomplete.js
jquery.autocomplete.css
indicator.gif

You can move them around later but for now lets keep them all in one folder and modify the css file to point to our new location for the loading gif.

background : url(‘/scripts/indicator.gif’) right center no-repeat;

Step 3 : Build your controller class

I’m selecting the top 10, distinct where the product name contains the typed in text.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyNameSpace.Models;

namespace MyNameSpace.Controllers
{
    public class AutoCompleteController : Controller
    {
        MyNameSpaceEntities mhgDb = new MyNameSpaceEntities();

        public ActionResult ProductName(string q)
        {
            var productNames = (from p in mhgDb.Products where p.ProductName.Contains(q) select p.ProductName).Distinct().Take(10);

            string content = string.Join<string>("\n", productNames);
            return Content(content);
        }

    }
}

Step 4:  Add the JS and CSS files to your view


<script src="@Url.Content("~/Scripts/jquery.autocomplete.js")" type="text/javascript"></script>
<link href="@Url.Content("~/Scripts/jquery.autocomplete.css")" rel="stylesheet" type="text/css" />

Step 5 : Bind the Textbox to the Controller


<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>

<script type="text/javascript">

$(document).ready(function () {
$("#ProductName").autocomplete('@Url.Action("ProductName", "AutoComplete")', { minChars: 3 });
});

</script>

Step 6 : Build and Test

That’s all, there’s some tips around styling and parameters for autocomplete in the link to the other blog post I linked to above. I’d be interested in seeing a better LINQ statement if anyone has one.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyHobbyGear.Models; 

namespace MyHobbyGear.Controllers
{
public class AutoCompleteController : Controller
{
MyHobbyGearEntities mhgDb = new MyHobbyGearEntities();
//
// GET: /AutoComplete/

public ActionResult Manufacturer(string q)
{
var manufacturers = (from p in mhgDb.Products where p.ManufacturerName.Contains(q) select p.ManufacturerName).Distinct().Take(10);

string content = string.Join<string>(“\n”,manufacturers);
return Content(content);
}

public ActionResult ProductName(string q)
{
var productNames = (from p in mhgDb.Products where p.ProductName.Contains(q) select p.ProductName).Distinct().Take(10);

string content = string.Join<string>(“\n”, productNames);
return Content(content);
}

}
}

.net MVC Validation with Data Annotation


With MVC you can validate data in the UI and before sending to the database auto-magically if you add Data Annaotation Validators to your model classes. Here are some of the more commonly used validators and samples on how to use them.

Add using System.ComponentModel.DataAnnotations; to your model.

[Required] – States the field is required

sample :
[Required( AllowEmptyStrings=false,ErrorMessage=”You must eneter a name”)]
public string Name { get; set; }

[StringLength] – Used to set min and max string length.

sample:
[StringLength (20,MinimumLength=5,ErrorMessage=”Name must be between 5 and 20 characters”)]

[MaxLength] – Max length of a string

sample:
[MaxLength(20,ErrorMessage=”Name must be less than 20 Characters”);
public string Name { get; set; }

[MinLength] – minimum length of a string

sample:
[MinLength (5,ErrorMessage=”Name must be more than 5 characters”)]
public string Name { get; set; }

[Range] – States the value of a number must be between x and y.

sample:
[Range (1,99,ErrorMessage=”Age must be between 1 and 99″)]
public int age {get;set;}

[RegularExpression] – Used to validate the format of a string

sample:
[RegularExpression(“[a-z0-9!#$%&’*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&’*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?”, ErrorMessage=”Invalid Email Address”)]
public string Email { get; set; }

[PropertiesMustMatch] – Class level attribute used to validate something like Password1 = Password2.

sample:
[PropertiesMustMatch(“Password”, “ConfirmPassword”, ErrorMessage = “The password and confirmation password do not match.”)]
public class user {

public string name {get;set;}

public string Password {get;set;}

public string ConfirmPassword {get;set;}

}

Rich Text Editing with CKEditor, MVC 3 and the Razor Engine


I was creating a model /view for editing large chunks of text on my website with MVC and the Razor engine. I created everything following Sott Gu’s tutorial on how to build a music store. When all was said and done I had a 50 character wide single line textbox for editing a large html block and thought ok this isn’t I deal.  Here are the steps I took to get a rich text editor in there.

Most of this came from this post on code project but it’s a bit outdated and doesn’t have everything.

The FCK Editor became the CK Editor, I guess they opted to drop the F over adding a U.

Step 1  : Change to Text Area

You should  have something like this in your Create and Edit Views

@Html.EditorFor(model => model.Text)

Lets change that to :

@Html.TextAreaFor(model => model.Text, new { @class = “adminRichText” })

Step 2 : Widen the text area

In your Site.Css file add the folowing to widen the text area :

.adminRichText
{
width:450px;
}

Step 3 : Add the CK Editor (formerly FCK Editor) to your project

a. Download here

b. Create a ‘Javascript’ folder under ‘Content’ in your website.

c. Extract to /Javascript/Content.

Step 4 : Include the scripts in your View

Below the validation scripts add

<script type=”text/javascript” src=”@Url.Content(“~/content/javascript/ckeditor/ckeditor.js”)”></script>

<script type=”text/javascript” src=”@Url.Content(“~/content/javascript/ckeditor/adapters/jquery.js”)”></script>

Step 5 : Turn the text area into a Rich Text Box

At bottom of view after controls are initialized add:

<script language=”javascript” type=”text/javascript”>
jQuery(“.adminRichText”).ckeditor();
</script>

Step 6 : Enable Post Back of Rich Text for your Edit and Create Methods in your controller class

[HttpPost, ValidateInput(false)]
public ActionResult Create(AreaText areaText)

[HttpPost, ValidateInput(false)]
public ActionResult Edit(string id, FormCollection collection)

Step 7: Use Html.Raw to display the data

On your index view update the output area to decode the html.

item.Text

becomes

@Html.Raw(item.Text)

ckEditor in mvc

ckEditor in mvc

Note : There are some good suggestions in the comments on ways to continue using validation :

Option 1 from Micheal.
“In your CKEditor config file add the following line:
config.htmlEncodeOutput = true;”

Option 2 from Blair.
“I was able to get this to work without having to turn off validation by putting in
[AllowHtml] in the property definition”

MVC Routes and SEO


I’ve been looking at Micrsofts MVC engine lately and I can’t help but think why isn’t the default route more SEO friendly.

When I create a new project this code is placed inside of my global.asax.cs file.

public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 routes.MapRoute(
 "Default", // Route name
 "{controller}/{action}/{id}", // URL with parameters
 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
 );

 }

That will give me a product url like this :

www.somewebsite.com/products/view/1.aspx

But I’d rather have a friendly name in there somewhere like this :

www.somewebsite.com/products/view/my-friendly-product-name/1.aspx

So I think if you go with defualt routing you’re making a mistake.