Skip to content

Instantly share code, notes, and snippets.

@aolde
Last active December 26, 2015 16:59
Show Gist options
  • Save aolde/7184165 to your computer and use it in GitHub Desktop.
Save aolde/7184165 to your computer and use it in GitHub Desktop.
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