Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Implementing support for wildcard routes in EPiServer CMS 7. The WildcardModelBinder is optional. Blog post about the subject: http://simply.io/blog/2013/10/supporting-wildcard-routes-in-episerver-7-cms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace Project.Core.Mvc.Routing {
/*
// Example of using the modelbinder:
public ActionResult Index(ListPage currentPage, [ModelBinder(typeof(WildcardModelBinder))]List<string> filters) {
return Json(filters);
}
*/
public class WildcardModelBinder : WildcardModelBinder<string> { }
public class WildcardModelBinder<TModelType> : IModelBinder {
public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
string valueString = controllerContext.RouteData.Values[bindingContext.ModelName] as string;
if (string.IsNullOrEmpty(valueString))
return default(TModelType);
Type modelType = bindingContext.ModelType;
Type modelEntityType;
if (modelType == typeof(string)) {
return valueString;
}
if (modelType.IsArray) {
modelEntityType = modelType.GetElementType();
var enumerable = GetEnumerableFromString(valueString, modelEntityType);
return enumerable.ToArray();
}
var typeDefinition = modelType.GetGenericTypeDefinition();
var interfaces = typeDefinition.GetInterfaces();
if (modelType.IsGenericType && IsEnumerable(typeDefinition, interfaces)) {
modelEntityType = modelType.GetGenericArguments().FirstOrDefault();
var enumerable = GetEnumerableFromString(valueString, modelEntityType);
if (IsList(typeDefinition, interfaces))
return enumerable.ToList();
return enumerable;
}
return default(TModelType);
}
protected bool IsEnumerable(Type typeDefinition, Type[] interfaces) {
var ienumerableType = typeof(IEnumerable<>);
return typeDefinition == ienumerableType || interfaces.Any(type => type.Name.Equals(ienumerableType.Name));
}
protected bool IsList(Type typeDefinition, Type[] interfaces) {
var ienumerableType = typeof(IList<>);
return typeDefinition == ienumerableType || interfaces.Any(type => type.Name.Equals(ienumerableType.Name));
}
protected IEnumerable<TModelType> GetEnumerableFromString(string valueString, Type modelEntityType) {
var strings = valueString.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
return strings.Select(value => Convert.ChangeType(value, modelEntityType)).Cast<TModelType>();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using EPiServer.Web.Routing.Segments;
namespace Project.Core.Mvc.Routing {
/*
// Example of generating a link to an action with wildcard route:
@Url.Action("Index", "List", new { node = Model.ListPageRef, filters = new [] {"One", "Two", "Three"} })
@Url.Action("Index", "List", new { node = Model.ListPageRef, filters = "One/Two/Three" })
*/
public class WildcardSegment : SegmentBase {
public WildcardSegment(string name) : base(name) { }
public override bool RouteDataMatch(SegmentContext context) {
string path = context.RemainingPath;
// set the default value if there is no remaining path
if (string.IsNullOrEmpty(path)) {
if (!context.Defaults.ContainsKey(Name))
return false;
context.RouteData.Values[Name] = context.Defaults[Name];
return true;
}
context.RemainingPath = string.Empty;
context.RouteData.Values[Name] = path;
return true;
}
public override string GetVirtualPathSegment(RequestContext requestContext, RouteValueDictionary values) {
if (!values.ContainsKey(Name))
return null;
object value = values[Name];
Type valueType = value.GetType();
// if value is an enumerable or array, concatenate the list to a string
if (valueType.IsGenericType && value is IEnumerable) {
IEnumerable<string> valueList = from object val in value as IEnumerable
select Convert.ToString(val);
value = string.Join("/", valueList);
}
else if (valueType.IsArray) {
var valueArray = value as object[];
if (valueArray != null) {
value = string.Join("/", valueArray);
}
}
return string.Format("{0}/", value);
}
}
}
// Registering a route with ISegment.
routes.MapContentRoute(
name: "List-with-filters",
url: "{language}/{node}/{partial}/{filters}/{action}",
defaults: new { controller = "List", action = "Index" },
parameters: new MapContentRouteParameters {
SegmentMappings = new Dictionary<string, ISegment> {
{ "filters", new WildcardSegment("filters") }
}
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment