Why would the route http://localhost:2222/2012-adidas-spring-classic/37, not get picked up from the below route match? I get a 404 error.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*vti_inf}", new { vti_inf = #"(.*/)?_vti_inf.html(/.*)?" });
routes.IgnoreRoute("{*vti_rpc}", new { vti_rpc = #"(.*/)?_vti_rpc(/.*)?" });
#region API
routes.MapRouteLowercase(
"NamedHomeEvent",
"{year}-{name}/{Id}",
new { controller = "Event", action = "Index", year = DateTime.Now.Year },
new { year = #"\d{4}", Id = #"\d+" }
);
public virtual ActionResult Index(int? id, int? year, string name)
{
The routing engine cannot help you here. You could write a custom route to handle this case:
public class MyRoute : Route
{
public MyRoute()
: base(
"{year-name}/{id}",
new RouteValueDictionary(new { controller = "Event", action = "Index", id = UrlParameter.Optional }),
new RouteValueDictionary(new { id = #"\d*" }),
new MvcRouteHandler()
)
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var routeData = base.GetRouteData(httpContext);
if (routeData == null)
{
return null;
}
var yearName = (string)routeData.Values["year-name"];
if (string.IsNullOrWhiteSpace(yearName))
{
return null;
}
var parts = yearName.Split(new[] { '-' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2)
{
return null;
}
var year = parts.First();
int yearValue;
if (!int.TryParse(year, out yearValue))
{
return null;
}
var name = parts.Last();
routeData.Values.Add("year", year);
routeData.Values.Add("name", name);
return routeData;
}
}
and then register this route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*vti_inf}", new { vti_inf = #"(.*/)?_vti_inf.html(/.*)?" });
routes.IgnoreRoute("{*vti_rpc}", new { vti_rpc = #"(.*/)?_vti_rpc(/.*)?" });
routes.Add("NamedHomeEvent", new MyRoute());
}
Related
I am trying to create constraint for route.Based on the access info retrieved from Db,i will choose which route to choose.
I have created controller inheriting IRouteConstraint and calling repository,but Unable to get result from httpclient call.
Code snippet of my routeConfig
routes.MapRoute(
name: "Home",
url: "{*routelink}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { routelink = new UserAccessController("Home") }
);
routes.MapRoute(
name: "Reports",
url: "{*routelink}",
defaults: new { controller = "Reports", action = "Index" },
constraints: new { routelink = new UserAccessController("Reports") }
);
Code snippet of Constarint
public class UserAccessController : IRouteConstraint
{
// GET: UserAccess
private readonly string _controller;
public UserAccessController(string Controller)
{
_controller = Controller;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
bool _authorized = false;
var userAccessDetails = GetUserRoleDetails();
switch (_controller)
{
case "Home":
{
_authorized = Convert.ToBoolean(userAccessDetails.CanAccessHome);
return _authorized;
}
case "Reports":
{
_authorized = Convert.ToBoolean(userAccessDetails.Result.CanAccessReports);
return _authorized;
}
}
return _authorized;
}
public async Task<UserRole> GetUserRoleDetails()
{
IRepository _repository = new Repository();
var userRoleDetails = new UserRole();
var currentUser = await _repository.GetCurrentUser(Path.GetFileName(HttpContext.Current.User.Identity.Name.ToUpper()));
if (currentUser != null)
{
var roles = await _repository.GetUserRoles();
userRoleDetails = roles.Where(r => r.RoleId == currentUser.RoleId).FirstOrDefault();
}
return userRoleDetails;
}
}
the repository is calling httpwrapper class to get result from httpclient.
public static async Task<IEnumerable<T>> GetAsync(IEnumerable<T> t, string path)
{
HttpResponseMessage response;
response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
t = await response.Content.ReadAsAsync<IEnumerable<T>>();
}
return t;
}
Not sure whats the issue,not getting result response = await client.GetAsync(path);.
I am able to get result with the same api and parameters when called from Session_Start event in Global.asax. Please let me know whats the issue and how can retrieve result from http.
I have resolved this issue by keeping the route config as it is.
Created a new Action filter and reroute the url based on access.
Placed this filter on the top of default route.
public class StartupFilter:ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var userAccessDetails = HttpContext.Current.Session["Role"] as UserRole;
if (userAccessDetails.HasAccessHome)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(
new
{
controller = "Home",
action = "Index"
}));
}
else if (userAccessDetails.HasAccessReport))
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(
new
{
controller = "Reports",
action = "Index"
}));
}
base.OnActionExecuting(filterContext);
}
}
I'm trying to support both web api and normal controllers.
I have defined different methods for different actions but looks like something is wrong as I'm getting following error again and again
{"Message":"An error has occurred.","ExceptionMessage":"Multiple actions were found that match the request:
\r\nPostFilter on type imaserver.Controllers.OrdersController\r\nPostOrder on type imaserver.Controllers.OrdersController",
"ExceptionType":"System.InvalidOperationException",
"StackTrace":"
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}
Here is my code:
RouteConfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
"CDN",
"cdn/{directory}/{file}",
new { controller = "CDN", action = "Download", directory = UrlParameter.Optional, file = UrlParameter.Optional }
);
routes.MapRoute(
name: "API",
url: "api/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
}
}
OrderController
public class OrdersController : ApiController
{
private FoodDeliveryEntities db = new FoodDeliveryEntities();
// GET: api/Orders
public IQueryable<Order> GetOrders()
{
db.Configuration.ProxyCreationEnabled = false;
return db.Orders;
}
// GET: api/Orders/5
[ResponseType(typeof(Order))]
public IHttpActionResult GetOrder(long id)
{
db.Configuration.ProxyCreationEnabled = false;
Order order = db.Orders.Find(id);
if (order == null)
{
return NotFound();
}
return Ok(order);
}
// PUT: api/Orders/5
[ResponseType(typeof(void))]
public IHttpActionResult PutOrder(long id, Order order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != order.Id)
{
return BadRequest();
}
db.Entry(order).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!OrderExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Orders/filter
[HttpPost]
public IHttpActionResult PostFilter(OrderFilter orderFilter)
{
db.Configuration.ProxyCreationEnabled = false;
if (orderFilter.OrderType != null)
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer).OrderByDescending(o => o.PickupDate).Where(o => o.OrderType.Equals(orderFilter.OrderType)));
else if (orderFilter.Status != null)
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer).OrderByDescending(o => o.PickupDate).Where(o => o.Status.Equals(orderFilter.Status)));
else
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer));
}
// POST: api/Orders
[ResponseType(typeof(Order))]
public IHttpActionResult PostOrder(Order order)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Configuration.ProxyCreationEnabled = false;
order.Status = "New";
order.CreatedAt = DateTime.Now;
order.UpdatedAt = DateTime.Now;
db.Orders.Add(order);
db.SaveChanges();
foreach (var orderItem in order.OrderItems)
{
orderItem.OrderId = order.Id;
orderItem.CreatedAt = DateTime.Now;
orderItem.UpdatedAt = DateTime.Now;
orderItem.IsActive = true;
}
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = order.Id }, order);
}
// DELETE: api/Orders/5
[ResponseType(typeof(Order))]
public IHttpActionResult DeleteOrder(long id)
{
Order order = db.Orders.Find(id);
if (order == null)
{
return NotFound();
}
db.Orders.Remove(order);
db.SaveChanges();
return Ok(order);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool OrderExists(long id)
{
return db.Orders.Count(e => e.Id == id) > 0;
}
public partial class OrderFilter
{
public string Status { get; set; }
public string OrderType { get; set; }
}
}
I also tried to rename PostFilter to Filter but of no use
I am firing this URL:
http://somewebsite/api/Orders/filter
POST
What am I doing wrong?
Since you inherit from ApiController, you can only have 1 POST, GET, PUT or DELETE actions, to have more, update each of your actions to assign its unique route by decorating the methods with the
[ActionName("put_here_your_action_rout")]
attribute.
// POST: api/Orders/filter
[HttpPost]
[ActionName("filter")]
public IHttpActionResult PostFilter(OrderFilter orderFilter)
{
db.Configuration.ProxyCreationEnabled = false;
if (orderFilter.OrderType != null)
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer).OrderByDescending(o => o.PickupDate).Where(o => o.OrderType.Equals(orderFilter.OrderType)));
else if (orderFilter.Status != null)
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer).OrderByDescending(o => o.PickupDate).Where(o => o.Status.Equals(orderFilter.Status)));
else
return Ok(db.Orders.Include(o => o.OrderItems.Select(i => i.Item)).Include(c => c.Customer));
}
For the ApiController, the real name of your methods is irrelevant, you need to use the ActionName attribute.
I am trying to add some Routing rule in Global.ascx im my ASP.NET MVC application. I extend the IRouteHanlder, MVCHandler and registe the rule just as follow.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapRoute(
// "DefaultTT", // Route name
// "test", // URL with parameters
// new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
//);
RouteValueDictionary defaults = new RouteValueDictionary();
RouteValueDictionary constraints = new RouteValueDictionary();
RouteValueDictionary tokens = new RouteValueDictionary();
defaults.Add("controller", "home");
defaults.Add("action", "index");
defaults.Add("data", string.Empty);
constraints.Add("data", #"[a-zA-Z0-9\-]*");
tokens.Add("pageId", 0);
routes.Add(new Route("", defaults, constraints, tokens, new MyRouteHandler()));
}
public class MyRouteHandler : IRouteHandler
{
public System.Web.IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
return new MyMVCHanlder(requestContext);
}
}
public class MyMVCHanlder : MvcHandler
{
public MyMVCHanlder(RequestContext requestContext)
: base(requestContext)
{
}
protected override void ProcessRequest(HttpContext httpContext)
{
int i = 1;
int j = i + 1;
base.ProcessRequest(httpContext);
}
protected override void ProcessRequest(HttpContextBase httpContext)
{
int i = 1;
int j = i + 1;
base.ProcessRequest(httpContext);
}
}
But when I visit localhost:50112/ in my browser, the ProcessRequest method cannot be fired. I don't know why. Do you have any thought? Thank you.
I want to split my controller name..
For Example;
My controller name is For_ExpController.cs
and
I want my url like this;
http://localhost/For/Exp/Action
How can I define it on my RouteConfig.cs??
You could write a custom route:
public class MyRoute: Route
{
public MyRoute()
: base(
"{part1}_{part2}/{action}",
new RouteValueDictionary(new { controller = "for_exp", action = "index" }),
new RouteValueDictionary(new { part1 = #"[a-z]+", part2 = #"[a-z]+" }),
new MvcRouteHandler()
)
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
var part1 = rd.GetRequiredString("part1");
var part2 = rd.GetRequiredString("part2");
rd.Values["controller"] = string.Concat(part1, "_", part2);
return rd;
}
}
which will be registered in your Application_Start:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("MyRoute", new MyRoute());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
}
I have a number of controllers in application:
ApiV1Controller
ApiV2Controller
ApiV3Controller
...
Is it possible to map routes for them with single MapRoute statement to URLs like /api/v1/{action}?
You could write a custom route. Let's suppose that you have the following controllers:
public class ApiV1Controller : Controller
{
public ActionResult Index()
{
return Content("v1");
}
}
public class ApiV2Controller : Controller
{
public ActionResult Index()
{
return Content("v2");
}
}
public class ApiV3Controller : Controller
{
public ActionResult Index()
{
return Content("v3");
}
}
Now write a custom route:
public class ApiRoute : Route
{
public ApiRoute()
: base("api/{version}/{action}", new RouteValueDictionary(new { action = "index" }), new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
rd.Values["controller"] = "Api" + rd.GetRequiredString("version");
return rd;
}
}
That could be registered in your Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add("ApiRoute", new ApiRoute());
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
and that's pretty much it. Now you could play with urls:
/api/v1
/api/v2
/api/v3