23.09.2011 00:37:00
Die Möglichkeit des Url-Mappings bringt in ASP.NET einige nette Möglichkeiten mit sich. Macht man davon jedoch, zum Beispiel im Zuge der Implementierung von REST-Services, intensiv Gebrauch, wirkt die Tatsache, dass das Mapping nicht im Rahmen der Action-Methoden sondern Global.asax zu hinterlegen ist, nervig. Aus diesem Grund habe ich mich diese Woche an der Implementierung eines UrlMapping-Attributes versucht. Dieses wird wie nachfolgend dargestellt verwendet:
public class FlugRessourceController : Controller
{
[UrlMapping("/fluege/{flugId}/buchungen")]
public ActionResult Buchungen(int flugId)
{
var rep = new Repository();
var fluege = rep.FindBuchungenByFlugId(flugId);
return Json(fluege, JsonRequestBehavior.AllowGet);
}
}
Das Attribut an sich gestaltet sich relative einfach.
public class UrlMappingAttribute: Attribute
{
public UrlMappingAttribute(string url)
{
Url = url;
}
public String Url { get; set; }
}
Um es „zum Leben zu erwecken“, habe ich die nachfolgend dargestellte Erweiterungsmethode MapController<T> entwickelt. Sie nimmt den Typ eines Controllers als Typ-Parameter entgegen und erstellt dafür anhand der in den UrlMapping-Attributen enthaltenen Informationen Routen.
public static class UrlMappingRouteCollectionTools
{
public static void MapController<T>(this RouteCollection routes) where T : IController
{
var controller = typeof(T);
var methods = controller.GetMethods();
int i = 0;
foreach (var method in methods)
{
Debug.WriteLine(method.Name);
var attribute = method.GetCustomAttributes(inherit: false)
.Where(a => a is UrlMappingAttribute)
.FirstOrDefault();
if (attribute == null) continue;
var urlMappingAttribute = attribute as UrlMappingAttribute;
var controllerName = RemovePostfix(controller.Name, "Controller");
var url = RemovePrefix(urlMappingAttribute.Url, "/");
var routeName = CreateRouteName<T>(method, ++i);
var actionName = method.Name;
routes.MapRoute(
routeName,
url,
new { controller = controllerName, action = actionName }
);
}
}
private static string RemovePostfix(string str, string postfix)
{
if (str.EndsWith(postfix)) {
str = str.Substring(0, str.Length - postfix.Length);
}
return str;
}
private static string RemovePrefix(string str, string prefix)
{
if (str.StartsWith(prefix))
{
str = str.Substring(prefix.Length, str.Length - prefix.Length);
}
return str;
}
private static string CreateRouteName<T>(System.Reflection.MethodInfo m, int number) where T : IController
{
return typeof(T).Name + "_" + m.Name + "_autogenerated_" + number;
}
}
Diese Methode kann man nun in der Global.asax in der Methode RegisterRoutes aufrufen und schon kommt man in den Genuss der über die Attribute definierten Routen.
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapController<FlugRessourceController>();
[…]
}
|