简体   繁体   中英

Routing with only {id} parameter returns “resource cannot be found” error

I'm trying to setup routing as follows.

Right now My URL looks like www.mysite.com/Products/index/123

My goal is to setup URL like www.mysite.com/123

Where: Products is my controller name , index is my action name and 123 is nullable id parameter.

This is my route :

public static void RegisterRoutes(RouteCollection routes)
    {         
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


        routes.MapRoute(
          "OnlyId",
          "{id}",
      new { controller = "Products", action = "index", id = UrlParameter.Optional }

     );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

        );


    }

and this is my Action Method

public ActionResult index (WrappedViewModels model,int? id)
    {

        model.ProductViewModel = db.ProductViewModels.Find(id);
        model.ProductImagesViewModels = db.ProductImagesViewModels.ToList();

        if (id == null)
        {
            return HttpNotFound();
        }
        return View(model);
    }

this is my model wrapper :

 public class WrappedViewModels
{          
    public ProductViewModel ProductViewModel { get; set; }               
    public ProductImagesViewModel ProductImagesViewModel { get; set; }
    public List<ProductImagesViewModel> ProductImagesViewModels { get; set; 
}

Error is thrown on this URL : www.mysite.com/123

The question is: Why my view returns this error and how to avoid this behavior?

Thanks in advance.

In RegisterRoutes you need to specify little bit more.

  routes.MapRoute(
    name: "OnlyId",
    url: "{id}",
    defaults: new { controller = "Products", action = "index" },
    constraints: new{ id=".+"});

and then you need to specify the routing of each anchor tag as

@Html.RouteLink("123", routeName: "OnlyId", routeValues: new { controller = "Products", action = "index", id= "id" })

I think this will resolve you immediate.

If you're sure that id parameter is nullable integer value, place a route constraint with \\d regex like this, so that it not affect other routes:

routes.MapRoute(
     name: "OnlyId",
     url: "{id}",
     defaults: new { controller = "Products", action = "index" }, // note that this default doesn't include 'id' parameter
     constraints: new { id = @"\d+" }
);

If you're not satisfied for standard parameter constraints, you can create a class which inheriting IRouteConstraint and apply that on your custom route as in this example:

// adapted from /a/11911917/
public class CustomRouteConstraint : IRouteConstraint
{
    public CustomRouteConstraint(Regex regex)
    {
        this.Regex = regex;
    }

    public CustomRouteConstraint(string pattern) : this(new Regex("^(" + pattern + ")$", RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase)) 
    {
    }

    public Regex Regex { get; set; }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest && parameterName == "id")
        {
            if (values["id"] == UrlParameter.Optional)
                 return true;
            if (this.Regex.IsMatch(values["id"].ToString()))
                 return true;

            // checking if 'id' parameter is exactly valid integer
            int id;
            if (int.TryParse(values["id"].ToString(), out id))
                 return true;
        }
        return false;
    }
}

Then place custom route constraint on id -based route to let other routes work:

routes.MapRoute(
     name: "OnlyId",
     url: "{id}",
     defaults: new { controller = "Products", action = "index", id = UrlParameter.Optional },
     constraints: new CustomRouteConstraint(@"\d*")
);

I think you missed Routing order. So create first route definition which handles all available controllers and then define one which will handle the rest of the requests, say, one that handles the www.mysite.com/{id} kind of requests.

So swap the OnlyId and Default rules and No more changes required. I believe It should work fine now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM