ASP .Net MVC Routing: Url only with string ID

2019-03-18 19:27发布

very simple question but I couldn't find an answer for this:

I have the default {controller}/{action}/{id} pattern in my global.asax.

I need also something will give me something like www.example.com/microsoft or www.example.com/apple while Microsoft and apple are id stored in database. Using the default pattern would be: www.example.com/brands/detail/microsoft

any idea how the pattern should be? i tried: {id} and set the controller and action to brands and detail it work to serve my need but ruins all others pattern.

thanks

2条回答
Animai°情兽
2楼-- · 2019-03-18 20:00

Your route order matters. So create a first route definition which handles all available controllers and then mention one which will handle the rest of the requests. There you will handle the www.yousite.com/apple kind of request

routes.MapRoute("Default",  // Route name
                  "{controller}/{action}/{id}", // URL with parameters
                    new { controller = "Home", action = "Index", id = "" },
                    new { controller = new FromValuesListConstraint("Home", "Account","OtherOne") }
                );

 // to handle personalize user url
routes.MapRoute("user","{url}", new {controller="Home",action="Profile",url = "" });

Now create a new class called FromValuesListContraint which inherit from IRouteConstraint

public class FromValuesListConstraint : IRouteConstraint
{
    private string[] _values;

    public FromValuesListConstraint(params string[] values)
    {
        this._values = values; 
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName,
    RouteValueDictionary values, RouteDirection routeDirection)
    {
        // Get the value called "parameterName" from the
        // RouteValueDictionary called "value"

        string value = values[parameterName].ToString();

        // Return true is the list of allowed values contains
        // this value.

        for (int i = 0; i < _values.Length; i++)
            if (SContains(_values[i], value, StringComparison.OrdinalIgnoreCase ))
                return true;

        return false;
    }    

    public bool SContains(string source, string toCheck, StringComparison comp)
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
}

Have your Profile action method in Home read the parameter value and get data from your database.

 public ActionResult Profile(string url)
 {
    //url variable will have apple or microsoft . You may get data from db and return a view now.
 }

So whenever a request comes, It will check whether it is a controller available ( which you passed into the FromValuesListContraint class constructor in your first route definition), if available then it will go for that routing, else, it will go for the general (default) route mentioned as the second route.

In this example, Home, Account and OtherOnes are my available controllers. whenever you add a new controller to your project, you want to add that to the constrctor of FromValuesListConstraint class constructor.

Simply saying it works like Catching some specific exception and going to the general exception if none of them are caught! :) (just an example to understand)

查看更多
\"骚年 ilove
3楼-- · 2019-03-18 20:03

I would suggest a separate route with a constraint that the id either can't match one of your controllers or must match one of the ids in the database. List it before the default route so it matches first, if the qualifications are met.

Example using a simple regex for a fixed constraint, though you'd probably want to create a custom constraint deriving from IRouteConstraint that limits the values dynamically.

routes.MapRoute(
  "Brands",
  "{id}",
  new { controller = "brand", action = "detail" },
  new { id = "^(Microsoft)|(Apple)$" }
);

You might want to look at http://stephenwalther.com/blog/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints.aspx for more ideas.

查看更多
登录 后发表回答