Asp.net Routing - Route constraints and empty Route - asp.net

I have a url that I want to map routing to:
http://siteurl.com/member/edit.aspx?tab=tabvalue
where tabvalue is one of: "personal", "professional", "values" or nothing.
I want to map it to a route like:
Member/Edit/{tab}
But my problem is - I don't know how to specify such constraints. I'm trying this regex:
^[personal|professional|values]{0,1}$
but it only works when I use url
http://siteurl.com/member/edit/personal
-or-
http://siteurl.com/member/edit/professional
and doesn't work for
http://siteurl.com/member/edit/
Any ideas how to specify the correct constraint?
P.S. I'm not using MVC, just asp.net WebForms
Thanks!

[ ] is for character set.
use ( ) instead
^(personal|professional|values){0,1}$

It's possible this doesn't quite meet your requirements, but if you build an enum such as this...
public enum TabValue
{
Personal,
Professional,
Values,
}
... and define your Action as ...
public ActionResult Edit(TabValue? tabvalue)
{
return View("Index");
}
... then the nullable value type of TabValue? will ensure that the following urls...
http://localhost/member/Edit?tabvalue=Professional
http://localhost/member/Edit?tabvalue=Personal
http://localhost/member/Edit?tabvalue=Values
... all supply a value for tabvalue (and the casing here isn't import), where as these urls..
http://localhost:51590/Home/Edit?tabvalue=Cheese
http://localhost:51590/Home/Edit
... hit your action with a tabvalue of null. No special routing is required to make this work.

try specifying a default value of UrlParameter.Optional in the route declaration for tab.
ps. it should work, but maybe you have to do the above explicitely

Try this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("",
"Member/Edit/{tab}",
"~/member/edit.aspx",
true,
new RouteValueDictionary
{{"tab", ""}},
new RouteValueDictionary
{{"tab", "^[personal|professional|values]{0,1}$"}}
);
}

I have used one framework before to do this. I am not sure if you want to use a framework or if you are using one already but check this out:
http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx
I have used it on a website, it is relatively easy to set up -- all rules are specified in the web.config file and you have certain freedom in designing your routes.
Hope it helps

Consider having 3 (or 4) routes. If the value of {tab} is not dynamic at runtime, having 3 static routes is cleaner than a regex. The regex is usually only useful when there are many values at runtime, such as matching a number, date, etc.

Related

ASP.NET MVC 4 C# - Get Sectioned Elements or full URL to Parse

Being kind of a newb to MVC 4 (or really any of the MVC's for ASP.NET) I cant help but feel theres more to the URL helper than what I'm seeing.
Basically I've read the tutorials on populating the attributes in a controllers methods using a query string in the URL.
I dont liek query strings though and prefer a sectioned "folder" like style.
Without much further adu, this is the sample URL:
http://something.com/DataTypes/Search/searchString
this approach is actually pretty safe as there will only ever be single worded searches
I have tried in the DataTypes controller
[HttpGet]
public ActionResult Search(String q)
{
ViewBag.ProvidedQuery = q;
return View();
}
and a few other small variations, right now im just trying to get the string to show up in the view but I dont seem to be getting anything there.
Is there anyway to inject the 3rd string in the url into an attribute?
If not, which URL helper class am I supposed to use to acquire the string data in the URL? Even if I have to parse the whole URL manually so be it, i just need to acquire that 3rd element in the URL as a string
Extremely n00b question im sure, but either im not finding this simple guide somewhere, or im not searching google correctly...
What you're missing is that the default route parameter name is "id". So you want to do this:
[HttpGet]
public ActionResult Search(String id)
{
ViewBag.ProvidedQuery = id;
return View();
}
If you don't want to use the variable name id, then you can modify your Route to look like this:
routes.MapRoute(
name: "Search",
url: "DataTypes/Search/{searchString}",
defaults: new { controller = "DataTypes", action = "Search",
searchString = UrlParameter.Optional });
If you don't want the string to be optional, then you can remove the last field from the defaults object.
you can use RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext)) to get the routedata
String URL to RouteValueDictionary
You need to look at the routing in the Global.asax.cs. For example for your case you could add a route to the routes collection like this:
routes.MapRoute("Search",
"DataTypes/Search/{q}",
new { controller = "DataTypes", action = "Search" }
);
Then the q parameter will automatically get mapped to your action. The default controller mapping is likely mapping it to "id".

Elegant way of avoiding ASP.NET MVC routing errors

I have a route:
routes.MapRoute("ResetPasswordConfirm", "reset-password-confirm", new { controller = "Membership", action = "ResetPasswordConfirm" });
and the code
public ActionResult ResetPasswordConfirm(int userid, string key)
{
// ...
}
in my application. So that i have url to be executed like this:
http://localhost/reset-password-confirm?userid=1&key=bla_bla_something
That is absolutely okay, until someone decides to go to
http://localhost/reset-password-confirm
...and look what will happen. ASP.NET will generate predictable error:
The parameters dictionary contains a null entry for parameter 'userid' of non-nullable type 'System.Int32'...
It could be done also by a search robot trying to grab all the possible urls. It's okay, but generates a lot of errors during usage of application in the wild. I want to avoid that, but feel uncomfortable with writing a stub for every possible case for such kind of errors.
Is there any elegant way of doing that? Thanks.
Another way is to handle global errors, just set <customErrors mode="On"></customErrors> on your web.config and create an Error.cshtml on your Shared view folder. MVC3 templates actually include that page.
On the other hand, if you want to be more specific, you should try Action Filters, that's a cool way to handle errors.
[HandleError(View = "YourErrorView", ExceptionType=typeof(NullReferenceException))]
public ActionResult ResetPasswordConfirm(int? userid, string key)
{
if (!userid.HasValue)
throw new NullReferenceException();
// ...
}
Use nullables for your parameters, i.e.:
public ActionResult ResetPasswordConfirm(int? userid, string key)

MVC3 how to minimize the number of controllers

i am new to MVC3 and our project needs something like:
http://www.abc.com/product_1/product_1_subpage/...
http://www.abc.com/product_2/product_2_subpage/...
right now, i have product_1 as a controller; product_1_subpage as an action of this controller, however, think about i have over 100 different products, i cannot keep create over 100 controllers for each single product, i need to do something on this structure, any idea?
thank you very much for your help, really appreciate any input.
You would probably want to have only a single Controller called Products, for all your products, instead of having to add a new controller for every product.
With custom routes, or the default routing for that matter, you would still be able to generate individual links for individual products. Also, if you were to use your approach with a new controller for every product (which you really shouldn't!), you would have to re-compile and deploy your application every time you want to add another product - which would be a pain to maintain.
It sounds like you should have a look at the tutorials about MVC provided by the .Net team to get some basic understand of MVC, and how to think about it.
Use custom routes:
routes.MapRoute(
"ProductsRoute", // Route name
"products/{productName}/{subName}/{id}", // URL with parameters
new { controller = "Product", action = "View", id = UrlParameter.Optional } // Parameter defaults
);
That would make the following work:
public class ProductController : Controller
{
// http://yourweb/products/goggles/xray/Elite2000
public ActionResult View(string productName, string subName, string id)
{
}
}
how about changing the format of the url a little to take advantage of the routing:
http://www.abc.com/product/subpage/1

Orchard: Custom Registration fields

For my Orchard project, I need some additional information from the user at registration time. (Say, First Name, Last Name, Pants Color). This information must be entered while registering and can not be deferred until later (as per client's orders).
I tried using the Profile and Extended Registration plugins to ask for those, but as far as I see, this only gives me optional fields to display in the registration form. Is there a way to present fields that are mandatory?
I also had a quick foray into overwriting the AccountController's Register method, as per this discussion, but I couldn't get it to work: The controller is in a different place, it can't be subclassed and even if I force it to, code is never executed. I presume they are using a much older version of Orchard.
So, in which direction should I go to create a mandatory field that is close to the Orchard philosophy? Should I create a new field type that rejects empty values maybe? (is that even possible)?
I wrote the ExtendedRegistration module because of that same need.
You need to create a custom part, e.g.: MyRegistrationPart.
Then you add that part to the User ContentType.
In your part just add the [Required] attribute (Data annotations) to any properties that are mandatory.
Registration will not succeed until those mandatory values have been filled out!
Hope it's clear now.
While this probably won't answer your question just wanted to point out that it is my understanding that you don't need to override/subclass the AccountController class. Instead you need to "overwrite" the Users/Account/Register route by adding your own with a higher priority. To do that you need to implement an IRouteProvider as part of our module. Since it's an IDependency it will be loaded and processed automagically at run time. Something like:
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
routes.AddRange(GetRoutes());
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
// Make sure to be higher than the default
Priority = ##### PRIORITY HERE (int) ######,
Route = new Route(
"Users/Account/Register",
new RouteValueDictionary {
{"area", "#### YOUR MODULE AREA HERE ####"},
{"controller", "#### YOUR ACCOUNT CONTROLLER HERE ####"},
{"action", "#### YOUR REGISTER ACTION HERE ####"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "#### YOUR MODULE AREA HERE ####"}
},
new MvcRouteHandler())
}
};
}
}

Category is special word in ASP.NET MVC2? So how can I use something else?

I have just realized that, by chance, I implemented a category browse type situation in my project:
// GET: /Category/Browse?Category=Fruit
public ActionResult Browse(string category)
{
...
}
It turns out this is special case and there must be something behind the scenes. My next one I want to implement something like
//GET: /Category/Browse?Color=Blue
public ActionResult Browse(string color)
{
...
}
You get the idea...
Where/how do I register the different url values?
You don't need to register anything. Action parameters are automatically mapped to URL values by the default model binder. You can also map to complex type, list and dictionary parameters.

Resources