asp.net mvc - Is there a way to have a RoutePrefix that starts with an optional parameter? -


i want reach bikes controller these url's:

/bikes     // (default path us) /ca/bikes  // (path canada) 

one way of achieving using multiple route attributes per action:

[route("bikes")] [route("{country}/bikes")] public actionresult index() 

to keep dry i'd prefer use routeprefix, multiple route prefixes not allowed:

[routeprefix("bikes")] [routeprefix("{country}/bikes")] // <-- error: duplicate 'routeprefix' attribute     public class bikescontroller : basecontroller      [route("")]     public actionresult index() 

i've tried using route prefix:

[routeprefix("{country}/bikes")] public class bikescontroller : basecontroller 

result: /ca/bikes works, /bikes 404s.

i've tried making country optional:

[routeprefix("{country?}/bikes")] public class bikescontroller : basecontroller 

same result: /ca/bikes works, /bikes 404s.

i've tried giving country default value:

[routeprefix("{country=us}/bikes")] public class bikescontroller : basecontroller 

same result: /ca/bikes works, /bikes 404s.

is there way achieve objective using attribute routing? (and yes, know can stuff registering routes in routeconfig.cs, that's not i'm looking here).

i'm using microsoft.aspnet.mvc 5.2.2.

fyi: these simplified examples - actual code has irouteconstraint {country} values, like:

[route("{country:countrycode}/bikes")] 

i bit late party, have working solution problem. please find detailed blog post on issue here

i writing down summary below

you need create 2 files given below

      using system;     using system.collections.generic;     using system.collections.objectmodel;     using system.web.http.controllers;     using system.web.http.routing;      namespace _3btechtalk.multiplerouteprefixattributes {      public class _3btechtalkmultipleprefixdirectrouteprovider: defaultdirectrouteprovider {       protected override ireadonlylist  getactiondirectroutes(httpactiondescriptor actiondescriptor, ireadonlylist  factories, iinlineconstraintresolver constraintresolver) {        return createrouteentries(getrouteprefixes(actiondescriptor.controllerdescriptor), factories, new [] {         actiondescriptor        }, constraintresolver, true);       }        protected override ireadonlylist  getcontrollerdirectroutes(httpcontrollerdescriptor controllerdescriptor, ireadonlylist  actiondescriptors, ireadonlylist  factories, iinlineconstraintresolver constraintresolver) {        return createrouteentries(getrouteprefixes(controllerdescriptor), factories, actiondescriptors, constraintresolver, false);       }        private ienumerable  getrouteprefixes(httpcontrollerdescriptor controllerdescriptor) {        collection  attributes = controllerdescriptor.getcustomattributes  (false);        if (attributes == null)         return new string[] {          null         };         var prefixes = new list  ();        foreach(var attribute in attributes) {         if (attribute == null)          continue;          string prefix = attribute.prefix;         if (prefix == null)          throw new invalidoperationexception("prefix can not null. controller: " + controllerdescriptor.controllertype.fullname);         if (prefix.endswith("/", stringcomparison.ordinal))          throw new invalidoperationexception("invalid prefix" + prefix + " in " + controllerdescriptor.controllername);          prefixes.add(prefix);        }         if (prefixes.count == 0)         prefixes.add(null);         return prefixes;       }         private ireadonlylist  createrouteentries(ienumerable  prefixes, ireadonlycollection  factories, ireadonlycollection  actions, iinlineconstraintresolver constraintresolver, bool targetisaction) {        var entries = new list  ();         foreach(var prefix in prefixes) {         foreach(idirectroutefactory factory in factories) {          routeentry entry = createrouteentry(prefix, factory, actions, constraintresolver, targetisaction);          entries.add(entry);         }        }         return entries;       }         private static routeentry createrouteentry(string prefix, idirectroutefactory factory, ireadonlycollection  actions, iinlineconstraintresolver constraintresolver, bool targetisaction) {        directroutefactorycontext context = new directroutefactorycontext(prefix, actions, constraintresolver, targetisaction);        routeentry entry = factory.createroute(context);        validaterouteentry(entry);         return entry;       }         private static void validaterouteentry(routeentry routeentry) {        if (routeentry == null)         throw new argumentnullexception("routeentry");         var route = routeentry.route;        if (route.handler != null)         throw new invalidoperationexception("direct route handler not supported");       }      }     }  
      using system;     using system.collections.generic;     using system.linq;     using system.web;     using system.web.http;      namespace _3btechtalk.multiplerouteprefixattributes     {         [attributeusage(attributetargets.class, allowmultiple = true, inherited = true)]         public class _3btechtalkrouteprefix : routeprefixattribute         {             public int order { get; set; }              public _3btechtalkrouteprefix(string prefix) : this(prefix, 0) { }              public _3btechtalkrouteprefix(string prefix, int order) : base(prefix)             {                 order = order;             }                 }     }  

once done, open webapiconfig.cs , add below given line

 config.maphttpattributeroutes(new _3btechtalkmultipleprefixdirectrouteprovider()); 

that's it, can add multiple route prefix in controller. example below

      [_3btechtalkrouteprefix("api/car", order = 1)]     [_3btechtalkrouteprefix("{countrycode}/api/car", order = 2)]     public class carcontroller: apicontroller {      [route("get")]      public ihttpactionresult get() {       return ok(new {        id = 1, name = "honda accord"       });      }     }  

i have uploaded working solution here

happy coding :)


Comments

Popular posts from this blog

How has firefox/gecko HTML+CSS rendering changed in version 38? -

javascript - Complex json ng-repeat -

jquery - Cloning of rows and columns from the old table into the new with colSpan and rowSpan -