Last active
December 26, 2015 16:59
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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