I need to have a variable before every controller.
I want something like that:
www.mysite.com/SYSTEMVARIABLE/Controller/Action
Example:
www.mysite.com/internalevent/Inscricao/Index
www.mysite.com/externalevent/Inscricao/Index
And i need to get the "internalevent" or "externalevent"
Example of values array
At this example, i need the [0] value of array, be the SYSTEMVARIABLE, not "Inscricao (Controller)"
So, how can i get the "SYSTEMVARIABLE" value and work with this ?
I have the following now (not working...)
routes.MapRoute(
name: "Default",
url: "{sistema}/{controller}/{action}/{id}",
defaults: new { controller = "Inscricao", action = "Index", id = UrlParameter.Optional },
constraints: new { sistema = new SistemaRouteConstraint() }
);
I need to get the value from "{sistema}", and i need to do some logic on this value.
Below is the class i want to get it, but ALWAYS the "{sistema}" only gets me the controller value (controller come twice on RouteValueDictionary)
public class SistemaRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object sistema;
if(values.TryGetValue(parameterName, out sistema) && values != null)
{
var NomeSistema = values["sistema"].ToString();
using (Entities db = new Entities())
{
/*some logic here*/
}
}
return true;
}
}
I'm trying to write a route with a nullable int in it. It should be possible to go to both /profile/ but also /profile/\d+.
routes.MapRoute("ProfileDetails", "profile/{userId}",
new {controller = "Profile",
action = "Details",
userId = UrlParameter.Optional},
new {userId = #"\d+"});
As you can see, I say that userId is optional but also that it should match the regular expression \d+. This does not work and I see why.
But how would I construct a route that matches just /profile/ but also /profile/ followed by a number?
The simplest way would be to just add another route without the userId parameter, so you have a fallback:
routes.MapRoute("ProfileDetails", "profile/{userId}",
new {controller = "Profile",
action = "Details",
userId = UrlParameter.Optional},
new {userId = #"\d+"});
routes.MapRoute("Profile", "profile",
new {controller = "Profile",
action = "Details"});
As far as I know, the only other way you can do this would be with a custom constraint. So your route would become:
routes.MapRoute("ProfileDetails", "profile/{userId}",
new {controller = "Profile",
action = "Details",
userId = UrlParameter.Optional},
new {userId = new NullableConstraint());
And the custom constraint code will look like this:
using System;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
namespace YourNamespace
{
public class NullableConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.IncomingRequest && parameterName == "userId")
{
// If the userId param is empty (weird way of checking, I know)
if (values["userId"] == UrlParameter.Optional)
return true;
// If the userId param is an int
int id;
if (Int32.TryParse(values["userId"].ToString(), out id))
return true;
}
return false;
}
}
}
I don't know that NullableConstraint is the best name here, but that's up to you!
It's possible something changed since this question was answered but I was able to change this:
routes.MapPageRoute(
null,
"projects/{operation}/{id}",
"~/Projects/ProjectWizard.aspx",
true,
new RouteValueDictionary(new
{
operation = "new",
id = UrlParameter.Optional
}),
new RouteValueDictionary(new
{
id = new NullableExpressionConstraint(#"\d+")
})
);
With this:
routes.MapPageRoute(
null,
"projects/{operation}/{id}",
"~/Projects/ProjectWizard.aspx",
true,
new RouteValueDictionary(new
{
operation = "new",
id = UrlParameter.Optional
}),
new RouteValueDictionary(new
{
id = #"\d*"
})
);
Simply using the * instead of the + in the regular expression accomplished the same task. The route still fired if the parameter was not included, but if included it would only fire if the value was a valid integer. Otherwise it would fail.
ASP.NET MVC 3 has solved this problem, and as Alex Ford brought out, you can use \d* instead of writing a custom constraint. If your pattern is more complicated, like looking for a year with \d{4}, just make sure your pattern matches what you want as well as an empty string, like (\d{4})? or \d{4}|^$. Whatever makes you happy.
If you are still using ASP.NET MVC 2 and want to use Mark Bell's example or NYCChris' example, please be aware that the route will match as long as the URL parameter contains a match to your pattern. This means that the pattern \d+ will match parameters like abc123def. To avoid this, wrap the pattern with ^( and )$ either when defining your routes or in the custom constraint. (If you look at System.Web.Routing.Route.ProcessConstraint in Reflector, you'll see that it does this for you when using the built in constraint. It also sets the CultureInvariant, Compiled, and IgnoreCase options.)
Since I already wrote my own custom constraint with the default behavior mentioned above before realizing I didn't have to use it, I'll leave it here:
public class OptionalConstraint : IRouteConstraint
{
public OptionalConstraint(Regex regex)
{
this.Regex = regex;
}
public OptionalConstraint(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)
{
object value = values[parameterName];
if(value == UrlParameter.Optional)
return true;
if(this.Regex.IsMatch(value.ToString()))
return true;
}
return false;
}
}
And here's an example route:
routes.MapRoute("PostsByDate",
"{year}/{month}",
new { controller = "Posts",
action = "ByDate",
month = UrlParameter.Optional },
new { year = #"\d{4}",
month = new OptionalConstraint(#"\d\d") });
should your regex be \d*?
Thanks to Mark Bell for this answer, it helped me quite a bit.
I'm wondering why you hard coded the check for "userId" in the constraint? I slightly rewrote your class like to user the parameterName parameter, and it seems to be working just fine.
Am I missing anything by doing it this way?
public class OptionalRegExConstraint : IRouteConstraint
{
private readonly Regex _regEx;
public OptionalRegExConstraint(string matchExpression=null)
{
if (!string.IsNullOrEmpty(matchExpression))
_regEx = new Regex(matchExpression);
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.IncomingRequest)
{
if (values[parameterName] == UrlParameter.Optional) return true;
return _regEx != null && _regEx.Match(values[parameterName].ToString()).Success;
}
return false;
}
}
I needed to validate a few things with more than just a RegEx but was still getting an issue similar to this. My approach was to write a constraint wrapper for any custom route constraints I may already have:
public class OptionalRouteConstraint : IRouteConstraint
{
public IRouteConstraint Constraint { get; set; }
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
var value = values[parameterName];
if (value != UrlParameter.Optional)
{
return Constraint.Match(httpContext, route, parameterName, values, routeDirection);
}
else
{
return true;
}
}
}
And then, in constraints under a route in RouteConfig.cs, it would look like this:
defaults: new {
//... other params
userid = UrlParameter.Optional
}
constraints: new
{
//... other constraints
userid = new OptionalRouteConstraint { Constraint = new UserIdConstraint() }
}
I have a custom MvcRouteHandler which checks database if a Url exists and pairs it with some controller action and Id.
However if this route handler can not find a matching pair in database, I'd like MVC to keep try with other defined route handlers in route table.
How can I do that?
Update: (Example code added)
routes.MapRoute(
name: "FriendlyRoute",
url: "{FriendlyUrl}").RouteHandler = new FriendlyRouteHandler();
FriendlyRouteHandler is:
public class FriendlyRouteHandler : MvcRouteHandler
{
private TancanDbContext db = new MyDbContext();
protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
if (requestContext.RouteData.Values["FriendlyUrl"] != null)
{
string friendlyUrl = requestContext.RouteData.Values["FriendlyUrl"].ToString();
//Here, you would look up the URL Record in your database, then assign the values to Route Data
//using "where urlRecord.Url == friendlyUrl"
try
{
UrlRecord urlRecord = db.UrlRecords.Single(u => u.URL == friendlyUrl);
//Now, we can assign the values to routeData
if (urlRecord != null)
{
requestContext.RouteData.Values["controller"] = urlRecord.Controller;
requestContext.RouteData.Values["action"] = urlRecord.Action;
if(urlRecord.EntityId != null)
requestContext.RouteData.Values["id"] = urlRecord.ObjectId;
}
}
else
{
//Here, I want to redirect to next RouteHandler in route Table
requestContext.RouteData.Values["controller"] = friendlyUrl;
}
}
catch (Exception ex)
{
//throw;
//Here too, I want to redirect to next RouteHandler in route Table
requestContext.RouteData.Values["controller"] = friendlyUrl;
}
}
return base.GetHttpHandler(requestContext);
}
}
After adding this line it seems to work:
requestContext.RouteData.Values["controller"] = friendlyUrl;
Am I lucky or this is right way to do ? Do I need to use IRouteConstraint somewhere?
By the way, my influence was this article by Adam Riddick.
You want to use a custom Constraint, not a custom Handler for this.
routes.MapRoute(
name: "example",
url: "{friendly}",
defaults: new { controller = "FriendlyController", action = "Display" },
constraints: new { friendly = new FriendlyUrlConstraint() }
);
and then the constraint becomes:
public class FriendlyUrlConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var friendlyUrl = values[parameterName];
// Your logic to return true/false here
}
}
I am trying to create a plugin which will override the TopicsDetails.cshtml page. I added a route like this:
routes.MapRoute("Nop.Plugin.Other.CustomTopic.ViewCustomTopic", "{SeName}",
new { controller = "CustomTopic", action = "TopicDetails", SeName = UrlParameter.Optional },
new[] { "Nop.Plugin.Other.CustomTopic.Controllers" });
This is getting all the {SeName} to my CustomTopicController .Even the products SeName.
If I add this instead of the older one:
routes.MapRoute("Nop.Plugin.Other.CustomTopic.ViewCustomTopic",
new { controller = "CustomTopic", action = "TopicDetails" },
new[] { "Nop.Plugin.Other.CustomTopic.Controllers" });
I get an error because the TopicDetails(int itemId) Action receives an integer which is not provided as we know that GenericPathRoutes.cs Provides that integer.
How can I override the Rules of GenericPathRoutes.cs to do it so that only the topic SeName would hit my Controller or is there other way to do that kind of work or is it even possible to do?
Recently i wrote an article which shows how to override localized route and i used the TopicDetails view as an example. There article is here.
Inshort, your route provider shall look like this;
public class RouteProvider : IRouteProvider
{
private const string NAMESPACES = "Nop.Plugin.Misc.Custom.Controllers";
private const string CONTROLLER = "MiscCustom";
public void RegisterRoutes(RouteCollection routes)
{
//Public Override
routes.MapGenericPathRoute("Plugin.Misc.Custom.GenericUrl",
"{generic_se_name}",
new { controller = "Common", action = "GenericUrl" },
new[] { NAMESPACES });
}
public int Priority
{
get { return Int32.Max; }
}
}
I am not sure whether i understand your question
can you try it by adding
id = UrlParameter.Optional
here any id parameter is optional it wont throw that error
I build a site in mvc3 , i want to restrict my site on firefox .
i mean to say that when anyone open my site on firefox it open correctly but when anyone opens it on chrome or IE it give an customze error . I am using c# with mvc3
You could write a global action filter which will test the User-Agent HTTP request header:
public class FireFoxOnlyAttribute : ActionFilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var userAgent = filterContext.HttpContext.Request.Headers["User-Agent"];
if (!IsFirefox(userAgent))
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Unauthorized.cshtml"
};
}
}
private bool IsFirefox(string userAgent)
{
// up to you to implement this method. You could use
// regular expressions or simple IndexOf method or whatever you like
throw new NotImplementedException();
}
}
and then register this filter in Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new FireFoxOnlyAttribute());
}
You are looking for the user-agent of the user connected to your website, which may be retrieved via this call in your controller:
Request.UserAgent
Not that I agree with such a pattern, though.
This is a simple javascript function you may add to your code and perform the actions against.
function detect_browser() {
var agt=navigator.userAgent.toLowerCase();
if (agt.indexOf("firefox") != -1) return true;
else{
window.location="";//Here within quotes write the location of your error page.
}
}
On main page you may call the function on page load event. Though this practice is not recommended.
You could test the Request.UserAgent as part of a constraint on the route.
For example, you could define a route constraint routine as follows:
public class UserAgentConstraint : IRouteConstraint
{
private string requiredUserAgent;
public UserAgentConstraint(string agentParam)
{
requiredUserAgent = agentParam;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(requiredUserAgent);
}
}
Then add the following constraint to a route:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, //Parameter defaults
new { customConstraint = new UserAgentConstraint("Firefox") } //Constraint
);