I have the following action :
public class IntegrationController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ContentResult Feed(string feedKey)
{
...
}
}
I have tried to use this URL :
http://MyServer/Integration/Feed/MyTest
but feedKey is null? Does this have something to do with routes?
Edit 1 :
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Ad", action = "List", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"TreeEditing", // Route name
"{controller}/{action}/{name}/{id}", // URL with parameters
new { controller = "AdCategory", action = "Add", name = string.Empty, id = -1 }
);
Edit 2 :
routes.MapRoute(
"IntegrationFeed", // Route name
"{controller}/{action}/{name}/{feedKey}", // URL with parameters
new { controller = "Integration", action = "Feed", name = string.Empty, feedKey = "" }
);
Do you have a route defined for feedKey? Using the default routes, the following should work (change feedKey to id).
[AcceptVerbs(HttpVerbs.Get)]
public ContentResult Feed(string id)
{
// ...
}
Related
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.
i dont understand the rooting in ASP.net ; im missing something with this ?
this is my root :
routes.MapRoute(
name: "ChampionID",
url: "Champion/ChampionById/id",
defaults: new { controller = "Champion", action = "ChampionById", id = "5" }
);
this is my Controler :
public class ChampionController : Controller
{
public ActionResult ChampionById(string x)
{
ChampionId ch = new ChampionId();
ch.Id = x;
return View(ch);
}
if you can help me with this i will be thankful
Forget routes.MapRoute. Just wire up all routes and then put the route as an attribute like this:
public class ChampionController : Controller
{
[Route("Champion/ChampionById/{id}")]
public ActionResult ChampionById(string id)
{
ChampionId ch = new ChampionId();
ch.Id = id;
return View(ch);
}
}
Also x should be id. Then just remove routes.MapRoute. Then make sure you have a corresponding cshtml file called ChampionById.
Change your route to below to fit you ActionResult like below:
routes.MapRoute(
name: "ChampionID",
url: "Champion/ChampionById/{id}",
defaults: new { controller = "Champion", action = "ChampionById", id = UrlParameter.Optional }
);
Note what I have updated with 'id'
Here all requests with 'Champion/ChampionById/' pattern will be mapped to this route and any thing after 'Champion/ChampionById/' will be the 'id parameter'. Since it is marked as optional on the route this can be null too. So better check for it.
public class ChampionController : Controller
{
public ActionResult ChampionById(string id)
{
ChampionId ch = new ChampionId();
if( !string.IsNullOrEmpty(id))
{
ch.Id = id;
return View(ch);
}
//<TODO> : handle when your id parameter is null
return View(ch);
}
edit your route.
routes.MapRoute(
name: "ChampionID",
url: "Champion/ChampionById/{x}",
defaults: new { controller = "Champion", action = "ChampionById", x = UrlParameter.Optional }
);
As the title says all about what I want but to be kind of specific I would like to have a URL pattern like localhost/Product/List/Category/Page but I couldn't succeed finding a solution for it. I am sure it's belong to routing and as it is difficult topic in MVC I would need your help to find a solution for it.
My route config is:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(null, "",
new
{
controller = "Home",
action = "Shop",
});
routes.MapRoute(null, "",
new
{
controller = "Product",
action = "list",
category = (string)null,
page = 1
}
);
routes.MapRoute(null, "Page{page}",
new
{
controller = "Product",
action = "List",
category = (string)null,
subcategory = (string)null
},
new { page = #"\d+" }
);
routes.MapRoute(null,
"{category}",
new { controller = "Product", action = "List", page = 1 }
);
routes.MapRoute(null,
"{category}/Page{page}",
new { controller = "Product", action = "List" },
new { page = #"\d+" }
);
routes.MapRoute(null, "{controller}/{action}");
}
}
My Controller product is:
public class ProductController : Controller
{
EFDbContext db = new EFDbContext();
private IProductsRepository repository;
public int PageSize = 4;
public ProductController (IProductsRepository productrepository)
{
this.repository = productrepository;
}
public ViewResult List(string category, int page = 1)
{
ProductsListViewModel model = new ProductsListViewModel()
{
Products = repository.Products
.Where(p => category == null || p.ProductCategory == category || p.MenSubCategory == category)
.OrderBy(p => p.ProductID)
.Skip((page - 1) * PageSize)
.Take(PageSize),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = category == null ? repository.Products.Count():repository.Products.Where(e => e.ProductCategory == category).Count()
},
CurrentCategory = category
};
return View(model);
}
public PartialViewResult Menu(string subcategory = null )
{
ViewBag.SelectedCategory = subcategory;
IEnumerable<string> categories = repository.MenSubCategories
.Select(x => x.MenSubCategory)
.Distinct()
.OrderBy(x => x);
return PartialView(categories);
}
}
I hope I get answer for this as far as I really tried but couldn't find how to do it.
To generate an URL like you want: localhost/Product/List/Cars you can create a custom route like this:
routes.MapRoute(
name: "ProductList",
url: "Product/List/{category}",
defaults: new { controller = "Product", action = "List" }
);
Remember that custom routes have to come before the most general route (the one that comes with the default template).
Regarding your page parameter, if you are comfortable with this URL: localhost:3288/Product/List/teste?page=10 the above already work. But if you want this: localhost:3288/Product/List/teste/10 10 meaning the page number, then the simplest solution would be create two different routes:
routes.MapRoute(
name: "ProductList",
url: "Product/List/{category}",
defaults: new { controller = "Product", action = "List" }
);
routes.MapRoute(
name: "ProductListPage",
url: "Product/List/{category}/{page}",
defaults: new { controller = "Product", action = "List" , page = UrlParameter.Optional}
);
Another cleaner way, is to create a custom route constraint for your optional parameter. This question has a lot of answers to that:
ASP.NET MVC: Route with optional parameter, but if supplied, must match \d+
With attribute routing, you just need to decorate your action method with your specific route pattern.
public class ProductController : Controller
{
EFDbContext db = new EFDbContext();
private IProductsRepository repository;
public int PageSize = 4;
public ProductController (IProductsRepository productrepository)
{
this.repository = productrepository;
}
[Route("Product/list/{category}/{page}")]
public ViewResult List(string category, int page = 1)
{
// to do : Return something
}
}
The above route definition will send the request like yourSite/Product/list/phones and yourSite/Product/list/phones/1 to the List action method and the url segments for category and page will be mapped to the method parameters.
To enable attribute routing, you need to call the method MapMvcAttributeRoutes
method inside the RegisterRoutes method.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
i have project with Map Route (that's all):
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
);
and I have method in controller:
public ViewResult List(int id = 1)
{
...
}
and in List.cshtml:
#Html.ActionLink(i.ToString(), "List", "Product", new { id = i }, null)
but i want to change id to page, but not change it in RouteConfig.cs, i think that's some attribute which can config my route for action. I want this solution:
#Html.ActionLink(i.ToString(), "List", "Product", new { page = i }, null)
and
[maybe here I can add my specify route?]
public ViewResult List(int page = 1)
{
...
}
You can use attribute routing to override the convention.
First make sure attribute routing is enabled:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
);
}
}
Then add appropriate attribute to your controller method, for example:
[Route("YourControllerName/List/{page?}")]
public ViewResult List(int page = 1)
{
...
}
Question mark makes the page parameter optional.
If it's a default controller and action
[Route("")]
[Route("YourControllerName/List/{page?}")]
public ViewResult List(int page = 1)
{
...
}
More about attribute routing can be found here:
http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
I'm at a loss for why this routing issue is occurring.
Route in Global.asax.cs file:
routes.MapRoute(
"Archives", //Route name
"{controller}/{action}/{month}", // URL with parameters
new { controller = "Articles", action = "Archives" },
new { month = #"^\d+" } // Parameter.defaults
);
Controller:
public ActionResult Archives(int month)
{
ViewData["month"] = month;
return View(article);
}
Which keeps throwing the error:
The parameters dictionary contains a null entry for parameter 'month' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Archives(Int32)'
in 'AppleWeb.Controllers.ArticlesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
Which is bogus because the URL is: http://localhost:64529/Articles/Archives/12
EDIT- Full routing for all to see:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.IgnoreRoute("tellerSurvey.htm/{*pathInfo}");routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Appleweb", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Contact", //Route name
"{controller}/{action}/{page}", //URL with parameters
new { controller = "Appleweb", action = "Contact", page = UrlParameter.Optional } // Paramter defaults
);
routes.MapRoute(
"FormDetails", //Route name
"{controller}/{action}/{formid}", // URL with parameters
new { controller = "Resources", action = "FormDetails", formid = 0}
);
routes.MapRoute(
"_calc",
"{controller}/{action}/{calcid}", // URL with parameters
new { controller = "Resources", action = "Calc", calcid = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Article", //Route name
"{controller}/{action}/{articleid}", // URL with parameters
new { controller = "Articles", action = "Article", id = 0 } // Parameter.defaults
);}
This is an MVC 3 project, so no routingconfig.cs.
Here is the problem:
The URL http://localhost:64529/Articles/Archives/12 matches the other routes. It will match the Default, Contact, etc routes.
Edit
Simplest solution
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Archives",
"{controller}/{action}/{month}",
new { controller = "Articles", action = "Archives" },
new { month = #"\d+"}
);
//short-circuit for all URLs where the month is not numeric
//Warning: the 404 will not be handled in <customErrors>
//Its handled in <httpErrors>
routes.IgnoreRoute("Articles/Archives/{month}");
//place all other routes here
Other possibilities
1) replace {controller} with the hard-coded controller name so that /Articles won't match the route. Sample:
routes.MapRoute(
"Contact",
"Appleweb/{action}/{page}",
new { controller = "Appleweb", action = "Contact", page = UrlParameter.Optional }
);
Only match URLs that start with /Appleweb
2) use constraint
routes.MapRoute(
"Archives", //Route name
"Appleweb/{action}/{page}",
new { controller = "Appleweb", action = "Contact", page = UrlParameter.Optional },
new { controller = "^(?!articles$).*$" } //don't match articles
);
or
routes.MapRoute(
"Archives", //Route name
"Appleweb/{action}/{page}",
new { controller = "Appleweb", action = "Contact", page = UrlParameter.Optional },
new { controller = "appleweb|resources" } //only allow appleweb and resources
);
3) make the URL of archive unique like http://XXXX/Archives/12
routes.MapRoute(
"Archives",
"Archives/{month}",
new { controller = "Articles", action = "Archives" },
new { month = #"\d+" }
);
Your route has not given a default value for the month and the action method has a non nullable parameter (int month).
Change your route map to:
routes.MapRoute(
"Archives",
"{controller}/{action}/{month}",
new { controller = "Articles", action = "Archives",
month = UrlParameter.Optional }
);
Or action method to accept nullable int for the month parameter:
public ActionResult Archives(int? month) //nullable int
{
ViewData["month"] = month;
return View(article);
}