mccalltd / attributerouting Goto Github PK
View Code? Open in Web Editor NEWDefine your routes using attributes on actions in ASP.NET MVC and Web API.
Home Page: http://mccalltd.github.io/AttributeRouting/
License: MIT License
Define your routes using attributes on actions in ASP.NET MVC and Web API.
Home Page: http://mccalltd.github.io/AttributeRouting/
License: MIT License
Hi Tim,
I've been playing with AR in some xUnit tests/facts .. and i've had some problems with trying to retrieve a list of routes for a particular context.
eg. routes.GetRouteData(httpContext);
So after debugging a lot, i finally came across this bit of AR code..
class: mvcExtensions, line 14
public static string GetHttpMethod(this HttpRequestBase request)
{
return request.SafeGet(r => r.Headers["X-HTTP-Method-Override"]) ??
request.SafeGet(r => r.GetFormValue("X-HTTP-Method-Override")) ??
request.SafeGet(r => r.GetQueryStringValue("X-HTTP-Method-Override")) ??
request.SafeGet(r => r.HttpMethod, "GET");
}
Now, becuase i'm in a TEST class, I need to mock my context stuff, like the request. Kewl. What I wasn't (read: forgot) to mock was the HttpMethod property. When I mocked that property to return "GET", then everything worked again. Kewl :)
So my question is this .. should that last line in the above code snippet do a check for string.IsNullOrEmpty(HttpMethod) ? "GET" : HttpMethod
?
(What made me lead to this was that I notice the stack trace was giving me a First Chance Null Exception in AR .. somewhere .. and i -think- this is where it might have happened?)
Or maybe i've not set up my AR attribute(s) right?
Here's a sample attribute :-
[GET("1.0/location")]
public JsonResult .....
so yeah .. thoughts?
Hello,
I am able to access Routes.axd when using VS Development Server.
However when I use IIS Express I get a 404 error when accessing Routes.axd.
I added the following on Web.Config:
<system.webServer>
<handlers>
<add verb="*" path="routes.axd" type="AttributeRouting.Logging.LogRoutesHandler, AttributeRouting" />
But this didn't solved it. Any idea?
Thank You,
Miguel
Hi,
I'm not sure if it's a bug with MVC or with AR, this is what happens: I'm using a controller with this pattern /show/{id}/{?param1}
.
Then I create a link under the same view to the same controller only without the param1
parameter, but it is still filled by Html.ActionLink
and I get wrong routes to that controller (that include this param).
It does work if I add new {param1 = ""}
to every link, but that's not very convenient.
Thank you
Hello,
I am trying to implement a SiteMap service compatible with AttributeRouting
[Sitemap(Priority = 0.8, Frequency = Frequency.Hourly)]
[GET("Articles/Recent")]
public ActionResult Index()
{
return View();
}
I created the attribute which can be used without or with parameters (Priority, Frequency).
My idea is to have a Sitemap/Index action where I would:
1 - Get all routes with Sitemap attribute together with custom info.
2 - Generate custom routes. For example, a route like:
[GET("Post/{id}")]
[Sitemap(Priority = 0.8, Frequency = Frequency.Hourly)]
public ActionResult Index(int id)
{
return View();
}
In this case I would get the route and on the Sitemap/Index action I would generate N sitemap entries.
Each entry would be created with a new ID gotten from the database.
How to link this idea with AttributeRouting?
Did anyone ever did something like this?
Thank You,
Miguel
I would love to add localization support. However, I have not yet had a need for localizing routes. So to try and come up with a good solution, I would like to open the floor for comments. Please leave your requests and ideas so that I (or a willing contributor) can build something out.
What would be nice to have, and what would AR do?
/{areaUrl}/{prefix}/{routeUrl}/{param}
having a default generated route of
/sea/scape/goat/milk
and ending up with
/easay/apescay/oatgay/milk
with milk left alone cause it's a route param, but could have been supplied from translation for route default, and would apply translated route constraints as well.)
Would this be useful? This is just a stab at what could be done. The simplest way to fully support localization is what I'd want to build in. So suggestions are welcome!
I'm not sure how to replicate this issue or even if it's a bug, just figured I should let you know. I've been getting heaps of traffic to my blog about AR and someone made a comment about Query String Parameter Names being lowercased.
http://www.philliphaydon.com/2011/08/mvc-routing-with-attributes-makes-routing-awesome/
Works pretty great – although it did lower case my query string parameters as will which may not be desirable. Does anyone know of a good way to ensure a url like this
http://www.something.com/Controller/Action/paramName=ParamValue
goes to
http://www.something.com/controller/action/paramname=ParamValue
This would be ideal.
I would love to see the addition of the ApiController Methods to the list here
When using the "routes.MapAttributeRoutes();" from my test project I got an empty RouteCollection. It was solved by copying the assemblyBinding element in the Web.config to an App.config file in my test project.
I'm using Mvc3 and obviously everything works fine when I run the web application because the Web.config has the redirect by default:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Obviously not a bug per se, and I am unsure whether there are any reasonable ways to solve this automagically for users. But it did take some time to figure out nevertheless. Perhaps it could be added to the docs?
Hi,
I added a GET route via attribute (pretty simple /show/{user})
But when using Html.ActionLink, it refused to work and appended ?Length=4 instead of the value I tried to put there using RouteValueDictionary.
Only after adding the fourth parameter (html attributes object) it worked as expected.
Any idea why it works this way?
Thanks
Hi,
I'd like to have something like the following:
[GET("/show/{id}/{slug}/user-{?username}")]
but when the username is not there, not show the user-
part in generated links
Is this somehow possible to accomplish? I've added strings in all kinds of places and it worked in the past - but it don't know how to accomplish this when the parameter is optional.
Thank you
This appears to be my only way of contacting you.
I wanted to show you this web page.
http://blog.maartenballiauw.be/post/2009/11/26/Supporting-multiple-submit-buttons-on-an-ASPNET-MVC-view.aspx
I will experiment with it next week and see if it works with AR.
Cheers,
Mike
It would be a great nice to have if AttributeRouting allowed routing to a subdomain. Haven't found any code that currently does that in the project.
If you are planning something to add this, or need any help it would be nice to aid in this feature.
I think at least it should be implemented at a RouteArea level, something like:
[RouteArea("admin", Subdomain="admin")]
Or specifying both prefix and subdomain:
[RouteArea("admin", Subdomain="internal", AreaUrl="admin")]
Let me know your thoughts on this feature.
Hello,
I am using the new Localization version.
In some cases I might need to add the culture code to the route:
/{culture}/area/prefix/controller/action/id
What is the best way to do this?
Thank You,
Miguel
A head request returns a 404 error, shouldn't it be added to the GET httpmethod, or added as a httpMethod possibility?
Hi Tim,
This is difficult to explain :)
I have two MVC projects. One is called Admin where all the m/v/c are compiled and consumed by any other web project that needs a /admin. I will call the consumer project, Derived.
(For further information on the method, see my bottom comment on http://stackoverflow.com/questions/6656843/area-as-a-virtual-on-other-websites).
There is a HomeController in both projects, Derived inherits Admin. The index method is Virtual in Admin and override in Derived.
When i visit Derived - /Home/Index, the Admin home controller has preference even though it appears to use the correct view. I have a ViewData magic string which is setting which controller was used. Both website tests i setup, http://webadmin.local and http://webderived.local the magic string as always coming from the Admin Home controller.
I have uploaded a sample project to my skydrive.
https://skydrive.live.com/embedicon.aspx/Public/InheritController.zip?cid=e7737d00ff5b25e9&sc=documents
The route debugging on http://webderived.local/ is showing both home controller routes.
I wonder if there is another way around this or if I have created an undocumented feature. Maybe the Admin Home controller route should not be there because it is overridden.
(btw: i accidentally clicked fork. Trying to undo that now).
thanks, Mike
Hello,
On a project where I use Attribute Routing I have the following action:
[POST("Files"), Authorize(Roles = "Master"), ValidateAntiForgeryToken]
public virtual ActionResult Create(FileNewModel model) {
}
When I submit an Image with 80 KB everything works fine.
But when I submit a Video with 6 MB I get the following error:
"Maximum request length exceeded"
STACK TRACE:
at System.Web.HttpRequest.GetEntireRawContent()
at System.Web.HttpRequest.GetMultipartContent()
at System.Web.HttpRequest.FillInFormCollection()
at System.Web.HttpRequest.get_Form()
at System.Web.HttpRequestWrapper.get_Form()
at AttributeRouting.Helpers.HttpRequestBaseExtensions.GetFormValue(HttpRequestBase request, String key) in C:\Development\AttributeRouting\src\AttributeRouting\Helpers\HttpRequestBaseExtensions.cs:line 13
at lambda_method(Closure , HttpRequestBase )
at AttributeRouting.Helpers.ObjectExtensions.SafeGet[T,TResult](T obj, Expression1 memberExpression, TResult defaultValue) in C:\Development\AttributeRouting\src\AttributeRouting\Helpers\ObjectExtensions.cs:line 17 at AttributeRouting.Helpers.ObjectExtensions.SafeGet[T,TResult](T obj, Expression
1 memberExpression) in C:\Development\AttributeRouting\src\AttributeRouting\Helpers\ObjectExtensions.cs:line 10
at AttributeRouting.Helpers.MvcExtensions.GetHttpMethod(HttpRequestBase request) in C:\Development\AttributeRouting\src\AttributeRouting\Helpers\MvcExtensions.cs:line 16
at AttributeRouting.RestfulHttpMethodConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) in C:\Development\AttributeRouting\src\AttributeRouting\RestfulHttpMethodConstraint.cs:line 26
at System.Web.Routing.HttpMethodConstraint.System.Web.Routing.IRouteConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
at System.Web.Routing.Route.ProcessConstraint(HttpContextBase httpContext, Object constraint, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
at System.Web.Routing.Route.ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
at System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext)
at AttributeRouting.Framework.AttributeRoute.GetRouteData(HttpContextBase httpContext) in C:\Development\AttributeRouting\src\AttributeRouting\Framework\AttributeRoute.cs:line 61
at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)
at System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context)
at System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Any idea? This seems to be a bug.
Thank You,
Miguel
Hello,
I just installed version 1.6 and have the following configuration:
RouteTable.Routes.MapAttributeRoutes(x => {
x.ScanAssembly(Assembly.GetExecutingAssembly());
x.AddDefaultRouteConstraint(@"^id$", new RegexRouteConstraint(@"^\d+$"));
x.AddTranslationProvider<RouteTranslationProvider>();
x.ConstrainTranslatedRoutesByCurrentUICulture = true;
x.UseLowercaseRoutes = true;
x.UseRouteHandler(() => new CultureRouteHandler());
});
I defined only one culture PT. I tried to access the URL "pt/cms/home/index" and it worked fine.
But when I type in the URL "en/cms/home/index" it goes to the PT version!
Shouldn't a 404 error fire? I have set "x.ConstrainTranslatedRoutesByCurrentUICulture = true"
My CultureRouteHandler is the following:
public class CultureRouteHandler : MvcRouteHandler {
private const String _culture = "culture";
protected override IHttpHandler GetHttpHandler(RequestContext context) {
Thread.CurrentThread.CurrentCulture = new CultureInfo("pt");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("pt");
context.RouteData.Values[_culture] = culture;
}
return base.GetHttpHandler(context);
} // GetHttpHandler
} // CultureRouteHandler
Thank You,
Miguel
Hi there,
may be, I'm to damn stupid, but I try now for one hour to do the following:
Litte information, I'm a german developer and I have german mvc project.
OK,
On my local system, I have the following url http://localhost:4711/Tierlexikon <- german word for animal lexicon
and I have an area "Tierlexikon" with (at the moment) one controller with the name "AnimalLexiconController", and this controller have an action "Index".
All I want to do is route the url above to the action Index.
I tried:
I think I know the problem, there are not enough information, MVC needs in the url area and controller, so if I'm not to stupid, can you please provide an attribute with which I can do want I want?
Best regards
The most recent release of AttributeRouting updated the GetHttpMethod extension method to be defined as:
public static string GetHttpMethod(this HttpRequestBase request)
{
return request.Headers["X-HTTP-Method-Override"] ??
request.Unvalidated().Form["X-HTTP-Method-Override"] ??
request.Unvalidated().QueryString["X-HTTP-Method-Override"] ??
request.HttpMethod;
}
The use of the Unvalidated() method prevents this code from being executed in a unit test. A null reference exception will be thrown because the Unvalidated() method tries to access HttpContext. For example:
var context = new HttpContextMock(requestPath: "shorturl/test");
var routes = new RouteCollection();
routes.MapAttributeRoutes(config => config.ScanAssemblyOf<MyController>());
RouteData routeData = routes.GetRouteData(context);
That will throw an exception with the following stack trace:
System.NullReferenceException : Object reference not set to an instance of an object.
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext context)
at System.Web.Helpers.Validation.Unvalidated(HttpRequest request)
at AttributeRouting.Extensions.MvcExtensions.GetHttpMethod(HttpRequestBase request) in C:\Development\AttributeRouting\src\AttributeRouting\Extensions\MvcExtensions.cs: line 17
at AttributeRouting.RestfulHttpMethodConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) in C:\Development\AttributeRouting\src\AttributeRouting\RestfulHttpMethodConstraint.cs: line 27
at System.Web.Routing.Route.ProcessConstraint(HttpContextBase httpContext, Object constraint, String parameterName, RouteValueDictionary values, RouteDirection routeDirection)
at System.Web.Routing.Route.ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
at System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext)
at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)
I am not sure what the best solution to this problem will be besides to create a version of Unvalidated that does not depend on HttpContext.
Could not figure out how to edit for myself....
This page is missing a menu at the top
https://github.com/mccalltd/AttributeRouting/wiki/1.-Getting-Started
This page and all others have the menu at the top
https://github.com/mccalltd/AttributeRouting/wiki/2.-Usage
Hi Tim,
Due to the dynamic nature of my application. I am unable to utilize the attribute [AllowHtml] on a model property to get a Request.Form value with an unsafe value.
Here is an example form
<form action="/Home/Save" method="post">
<textarea name="txt">
<b>Hello Html Tags</b>
</textarea>
<input type="submit" value="submit" />
</form>
I have two scenarios to accept the post. One without and one with AttributeRouting.
The first scenario works without AttributeRouting [project: Unvalidated.csproj]
[HttpPost]
public ActionResult Save()
{
string value = Request.Unvalidated().Form["txt"];
return View("Success");
}
This AttributeRouting version errors [project: ValidateInputFalse.csproj]
[POST("Home/Save")]
public ActionResult Save()
{
string value = Request.Unvalidated().Form["txt"]; // ERROR
return View("Success");
}
Here is the stack trace
A potentially dangerous Request.Form value was detected from the client (txt=" Hello Html Tags</...").
[HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (txt=" Hello Html Tags</...").]
System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8855748
System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) +122
System.Web.HttpRequest.get_Form() +150
System.Web.HttpRequestWrapper.get_Form() +11
AttributeRouting.Extensions.MvcExtensions.GetHttpMethod(HttpRequestBase request) in C:\Development\AttributeRouting\src\AttributeRouting\Extensions\MvcExtensions.cs:16
AttributeRouting.RestfulHttpMethodConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) in C:\Development\AttributeRouting\src\AttributeRouting\RestfulHttpMethodConstraint.cs:27
System.Web.Routing.HttpMethodConstraint.System.Web.Routing.IRouteConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +22
System.Web.Routing.Route.ProcessConstraint(HttpContextBase httpContext, Object constraint, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +56
System.Web.Routing.Route.ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection) +150
System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext) +215
System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +287
System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +60
System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +86
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
Also, I have uploaded a solution which contains the scenarios above. (sorry for the confusing project names).
https://skydrive.live.com/embedicon.aspx/Public/AttributeRouting^_InputValidation.zip?cid=e7737d00ff5b25e9&sc=documents
Thank you
Mike
I have the following AR (Example 1)
public ActionResult _CenterImage(Guid? guid_Gallery, bool? slideShow, string currentController, string image)```
Due to a javascript construction of the action like this:
``` var action_CenterImage = '@Url.Action(GalleryRoutes.RouteAction("", "Gallery", "_CenterImage"))'
.concat('/', guid_Gallery, '/False/', controller);
The action returns blank.
To rectify the problem, I create a AR like this. (Example 2)
[GET("Gallery/_CenterImage", Order = 2)]
public ActionResult _CenterImage(Guid? guid_Gallery, bool? slideShow, string currentController, string image)
Are my nullable params incorrect because i thought the the first AR example would cater for both situations. Thanks
When using something along the lines of:
@{
Html.RenderAction("LoginControl", "Auth");
}
Any postback that occurs is met with an exception:
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
Inner:
{"Execution of the child request failed. Please examine the InnerException for more information."}
Inner:
{"A public action method 'LoginControl' was not found on controller 'TestMVC.Controllers.AuthController'."}
Create a page that has both a GET/POST, with a form on it:
@using(Html.BeginForm("Index", "Home", FormMethod.Post))
{
@Html.TextAreaFor(m => m.Text);
<input type="submit" value="Submit" />
}
[GET("", IsAbsoluteUrl = true)]
public ActionResult Index()
{
return View(new HomeModel());
}
[POST("", IsAbsoluteUrl = true)]
public ActionResult Index(HomeModel homeModel)
{
return View(homeModel);
}
Create a partial view, and on the same page render is like:
@{
Html.RenderAction("LoginControl", "Auth");
}
[ChildActionOnly]
[GET("Auth/LoginControl")]
public ActionResult LoginControl()
{
return PartialView("LoginControl");
}
Then when you post the page it will throw an exception.
Can submit a test project that reproduces this if need be. (not sure how to on github, first time submitting issue)
hi,
sorry for posting in Issues as i cant see a way to post a request,
what i want is to create custom rules like your lowercase one,
for example
i want to replace a word occurances in route with another one like
www.mysite.com/politic
into
www.mysite.com/politics-articles
i know that that i can reroute or redirect, but that is just a trivial example,
sometimes i need to change 2 different words.
if this possible this would be awesome, as the automatic nature of your lowercase is lovely and want to apply concept with other custom rules of mine
thanks alot in advanced.
Add attribute for enforcing canonical URLs.
Hello,
I have been using the new Translation Provider and it is great. I have one suggestion:
At the moment, if I am not wrong, it is only possible to use one translation provider:
routes.MapAttributeRoutes(config =>
{
config.AddRoutesFromController<TranslationController>();
config.AddRoutesFromController<TranslationWithCustomKeysController>();
config.TranslationProvider = translations;
});
I think it would be useful to have many TranslationProviders. For example:
RouteTranslationProvider
AreaXYZRouteTranslationProvider
...
In this case I have the global translation provider and one specific for the routes in one area.
This helps not only on organization, and area portability, but also avoid namespaces issues.
For example, usually there are main controllers and area controllers with the same name.
And some people might want to have a AreaLocalizationProvider, ActionLocalizationProvider, ...
I would suggest something as Profiles in Automapper:
Mapper.Initialize(x => {
x.AddProfile<MapperProfile>();
x.AddProfile<AreaXYZMapperProfile>();
});
So it would becomes something like:
routes.MapAttributeRoutes(config =>
{
config.AddRoutesFromController<TranslationController>();
config.AddRoutesFromController<TranslationWithCustomKeysController>();
config.AddTranslationProvider<RouteTranslationProvider>;
config.AddTranslationProvider<AreaXYZRouteTranslationProvider>;
});
What do you think?
Thank You,
Miguel
I want to have hypens in the url like:
[GET("company-overview")]
public ActionResult CompanyOverview()
{
return View(Service.GetCompanyOverview());
}
In a View I do:
@Html.ActionLink("Company Overview", "company-overview", new { area = "MediaRoom" })
But that will not work and I just see a hyperlink generated with an empty href.
I am forced to have my GET declared like:
[GET("companyOverview")]
public ActionResult CompanyOverview()
{
return View(Service.GetCompanyOverview());
}
In the markup of a View I do:
@Html.ActionLink("Company Overview", "companyOverview", new { area = "MediaRoom" })
and now the hyperlink is generated correctly.
I have not experienced this issue before and I am at a loss at how to fix it.
Hello,
I have the following action:
[GET("Users")]
public virtual ActionResult Index(Int32 p = 1) {
}
When I add a translation I get the following:
AddTranslations().ForController<UserController>()
.RouteUrl(x => x.Index(), new Dictionary<String, String> {
{ "pt", "Utilizadores" }
});
I get the following error:
An expression tree may not contain a call or invocation that uses optional arguments
Any idea how to solve this?
Thank You,
Miguel
Add QUnit tests to test routes.
Hello,
I am setting Attribute Routing (I installed the package) on a MVC 3 and I have the following:
namespace MVCSite.Areas.CMS.Controllers {
public partial class RoleController : Bontroller {
[GET("Roles")]
public virtual ActionResult Index() {
return View();
} // Index
}
}
And I have the following on my Home/Index view (I am using T4MVC):
@Html.ActionLink("Test", MVC.CMS.Role.Index());
But it renders as:
Test
Instead of
Test
I also tried to type on the URL CMS/roles but I keep having the 404 error.
What am I missing?
Thank you,
Miguel
Hello Tim,
I am using Attribute Routing on a CMS I develop and I have a few questions.
1 - CONVENTIONS
I am planning to use the RestfulRouteConvention but I have a few questions:
A) Do you consider Post / Index as Post / List?
Or it can be just the "entry" page?
B) Instead of:
Edit — GET ControllerName/{id}/Edit (Post/34/Edit)
Wouldn't be better to have:
Edit — GET ControllerName Pluralized/{id}/Edit (Posts/34/Edit)
Reference: http://edgeguides.rubyonrails.org/routing.html
You pluralize the controller or add an attribute to the controller?
I suppose both can be used, correct?
C) I see that all forms must have the HttpMethodOverride.
I need to a "Delete" link in each row of a table. How would you do it?
Maybe using Ajax? But can I do the HttpVerbs.Delete?
$('table.Data a.Delete').click(function (e) {
e.preventDefault();
if (confirm("Delete this item?")) {
$.ajax({ type: 'POST', url: $(this).href });
};
});
2 - SLUG IN URLs
I would like to have friendly slugs on the URLs. A few options:
A) posts/124/learn-about-attribute-routing (SLUG = TITLE)
In this case when the TITLE / SLUG changes I will not have broken links.
This is because the post is retrieved using the ID.
The only problem is if the title is changed I get 2 URLs indexed to the same page:
OLD: posts/124/learn-about-attribute-routing
NEW: posts/124/learn-about-mvc
I think this is penalized by Search Engines. In fact, aren't you penalized when using:
[GET("", Order = 1)]
[GET("Posts", Order = 2)]
[GET("Posts/Index", Order = 3)]
public void Index()
{
return View();
}
You have multiple routes to the same page.
B) posts/124-learn-about-attribute-routing (SLUG = ID + TITLE)
In this case when the TITLE / SLUG changes I will have broken links.
That is a problem worse then the previous one.
On both cases the Slug is saved on the Database when creating the post ...
... probably it is better then creating it on the fly. What do you think?
Which approach would you use?
And is this compatible with Restfull convention?
3 - LOCALIZATION
We already talked about localization before. In fact created a branch when we talked.
After reading and researching a lot I think there is a better approach.
(A) Use different Country Top Level domains for each version.
ENGLISH: www.domain.com; PORTUGAL: www.domain.pt; FRANCE: www.domain.fr
"At the SMX Confernece in Sydney Australia, Priyank Garg and Greg Grothaus, Yahoo’s and
Google’s search engineers, shared some issue:
If you use multiple country domains (ccTLD), even if content is in the same language (identical content)
on all of your localized sites (for instance you have it all in English, as it commonly happens with USA,
UK and Australia), you will not experience any duplicated content issues / penalties. This is true for both
Google and Yahoo, however, you might get some penalty if you abuse this feature (spammy sites) and
if you don’t localize your site properly."
(B) If Top Level domains are not available then use sub domains.
ENGLISH: en.domain.com; PORTUGAL: pt.domain.com; FRANCE: fr.domain.com
HOW IT WORKS
When a page is requested the MVC application detects the domain of the request and sets the culture.
ADVANTAGES
The portuguese version is indexed by Google.pt, the french version by Google.fr, etc.
I did a search for MSN in Google.com, Google.pt and Google.fr and in fact I got:
www.msn.com, pt.msn.com and fr.msn.com.
ISSUES
A route translation would be necessary to do the following:
- Go from "www.domain.pt/contacto" to "www.domain.com/contacto"
- Go from "www.domain.pt/post/ola-mundo" to "www.domain.com/post/hello-world"
The problem is that for the last route the title can change ...
And in fact a post can have no translation so it would be redirected to home/index or other defined route.
I am not sure if the best option would be to have a table to hold routes.
What do you think?
Cheers,
Miguel
Add MVC2 and MVC3 CodeTemplates for generating MVC-style and RESTful-style controllers with actions decortated with RouteAttributes. Also add templates for generating RESTful method-compatible views.
Hi :)
i'm trying to use this with a pretty small website.
It's a single ASP.NET MVC3 project. When I run my site, I only get an IIS 404.20 error -> no default document found.
I commented out the default route which is auto created inside the stock RegisterRoutes global.asax method.
This is when i try and goto the route www.foo.com/ <-- notice there's no controller/actionMethod
do i need to define that default route, somewhere?
cheers!
Hello,
I am defining a base route system for a CMS using Attribute Routing and I have the following:
[GET("users/page/{page=1}")]
public virtual ActionResult Index(Int32 page) {
return View();
} // Index
I am displaying "users/page/1" to because "users/1" is Users > Show.
If I need to filtrer users by Age and define a Sort Direction and Field I could use:
[GET("users/age/{age=10}/page/{page=1}/field/{field=username}/direction/{direction=asc} ")]
public virtual ActionResult Index(Int32 page, Int32 age, String field, String direction) {
return View();
} // Index
So I would get:
"users/age/10/page/1/field/username/direction/asc"
Does this make sense? Or should I use only something like:
"users?age=10&page=1&field=username&direction=asc"
I could also pass some of the parameters inside the model.
But I think having them on the url is better.
Thank You,
Miguel
Add dynamic filter to generated HTML to allow filtering by URL, controller, and area.
Hello,
Can you an optioin to read to value for the url from a resource file?
Hello,
A minor issue is I find the file AttributeRouting.xml is locked by devenv.exe
This is an issue because it is preventing a backup script from completing. It appears to have been introduced in v1.
The location of the file is Solution\Packages\AttributeRouting.1.0.30808\lib\net40\AttributeRouting.xml
While I can work around this; i thought it would be worth mentioning because it may not be by design that the resource is not being released.
thank you,
Mike
I've been reading through the documentation and while it was never stated somewhere explicitly, I assume that AttributeRouting should also work for MVC 2 projects? I've just started using it and keep getting the error: "Could not load file or assembly 'System.Web.WebPages, Version=1.0.0.0' or one of its dependencies."
I saw this entry in your changelog: "Used System.Web.WebHelpers to sniff the form and querystring collections hanging off the request for an http method override without triggering request xss validation", and when I looked it up, it appears that System.Web.WebHelpers is defined in System.Web.WebPages.dll. Is there any way around this? I can't switch to MVC 3 due to restrictions of my host.
Thanks!
Hello,
When I build my MVC site I get two files on the Bin folder:
AttributeRouting.dll and AttributeRouting.xml.
Why do I get the AttributeRouing.xml?
Is there a way to avoid it?
Thank you,
Miguel
Hello,
I installed AR 1.6 and I am not able to access "routes.axd" in IIS and in VS Development Server.
I checked by Web.Config file and I have:
<system.webServer>
<handlers>
<add name="Routes" verb="*" path="routes.axd" type="AttributeRouting.Logging.LogRoutesHandler, AttributeRouting" />
</handlers>
</system.webServer>
And I also have:
<system.web>
<httpHandlers>
<add verb="*" path="routes.axd" type="AttributeRouting.Logging.LogRoutesHandler, AttributeRouting" />
</httpHandlers>
</system.web>
And in Global.asax I have the following routes:
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.([iI][cC][oO]|[gG][iI][fF])(/.*)?" });
RouteTable.Routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }, typeof(HomeController).Assembly);
When I try to access "routes.axd" I get the error:
"A first chance exception of type 'System.NullReferenceException' occurred in AttributeRouting.DLL"
Any idea what I might be missing?
Thank you,
Miguel
Hi, I've read about this module, got all excited, but can't seem to make it work.
I added the package from Nuget and tried to add the config option to use lowercase URLs in the file that was created in App_Start, but nothing happened, all links were still CamelCase.
I tried to disable the default RegisterRoutes in Global.asax, but that broke everything.
Only thing that is differs in my code from the examples in the wiki, is that my controllers inherit from Controller and not ControllerBase, could that be the problem? Isn't this package supposed to work with MVC3?
I'm really new to MVC, so forgive me if I missed something really obvious.
Thank you
Hi,
awesome library, that i cant work without it anymore, thanks so much for you for giving us such a tool to ease up our lives.
i had my site working fine up until i upgraded to your latest build, now i get
HTTP 404 Not Found
i have made a test by disabling the route attribute temporarily and use normal ASP MVC routing and it is working, so my code is fine.
now i dug a little deeper and found out that if i remove registration to global.asax.cs everything works fine again, so the problem is in the App_Start file that you provide
here is my code in the appstart
[assembly: WebActivator.PreApplicationStartMethod(typeof(MyWebApplication.App_Start.AttributeRouting), "Start")]
namespace Syrianmartyrs.App_Start
{
public static class AttributeRouting
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapAttributeRoutes(config =>
{
config.ScanAssembly(Assembly.GetExecutingAssembly());
config.UseLowercaseRoutes = true;
config.AddRoutesFromControllersOfType<AdminController>();
});
}
public static void Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
}
When a request contains html or any potentially dangerous data, AtributeRouting fails when retrieving HttpMethod.
This is no good for example when using [AllowHtml] or [ValidateInput(false)] in models and controller actions.
This is a stack trace that will point to the issue immediately:
[HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (Description="<span class="Apple-s...").]
System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8855748
System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) +122
System.Web.HttpRequest.get_Form() +150
System.Web.HttpRequestWrapper.get_Form() +11
AttributeRouting.Extensions.MvcExtensions.GetHttpMethod(HttpRequestBase request) in C:\Development\AttributeRouting\src\AttributeRouting\Extensions\MvcExtensions.cs:16
AttributeRouting.RestfulHttpMethodConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) in C:\Development\AttributeRouting\src\AttributeRouting\RestfulHttpMethodConstraint.cs:29
System.Web.Routing.HttpMethodConstraint.System.Web.Routing.IRouteConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +22
System.Web.Routing.Route.ProcessConstraint(HttpContextBase httpContext, Object constraint, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +56
System.Web.Routing.Route.ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection) +150
System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext) +215
System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +287
System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +60
System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +86
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
Hi,
First off, this is a great library. Thanks so much for the investment of time and effort... very well put together.
Earlier this week I spent a bunch of time faffing around with culture switching based on locale route parameters. Any thoughts on adding some defaults into your library to help with this?
I'm a little crunched for time right now, but if you think it's a good idea, I wouldn't mind throwing a few hours towards a nice implementation.
Thanks again,
...brent
Hi,
First let me say I love this project - was looking for something like this for hours and posted on StackOverflow but couldn't find anything and was about to give up - then found this via NuGet. Works perfectly!
The only small problem I came across is that I was using actions that return a string just for testing but those were missed by MapAttributeRoutes(). It took me a bit of time and head scratching until I looked at the code and realized that AttributeRouting.Extensions.ReflectionExtensions.GetActionMethods() only looks for methods that return ActionResult!
The definition of an ASP.MVC action is any public method on a controller class, so I think the search criteria should change. However if for some reason you have to live this limitation, I think at least the AttributeRouting documentation should mention this so that others won't spend as much time as I did head scratching... :-)
Great Work. Thanks again!
We have an action on our base controller with a JavaScriptResult to serialize page translations to another language, it simply outputs a JSON object for us to use in JavaScript.
The action is defined in the base controller since the implementation is identical in every controller, the sub-class has a property which defines a parameter to query the db with to get the correct translations.
It seems however that defining a route in the base class:
[GET("GetPageTranslation")]
public JavaScriptResult GetPageTranslation()
{
...
}
Doesn't get mapped.
I've added a work-around for this by defining the route in the global asax file:
routes.MapRoute("PageTranslations", "{area}/{controller}/GetPageTranslation", new { action = "GetPageTranslation" });
This over-comes the issue. But think this is something that AR should handle.
When configured this way, for example, [GET("/some/location")]
, with or without a querystring would generate /some/location/
or /some/location/?test=x
for outbound URLs.
I slapped together a pull request for this behavior that I will submit right after this.
Hi Tim, First, thank you for an awesome project.
The issue I am having is that when the user fills in and posts a form, on error, I return them to the same form to allow them to correct their mistake by passing back the model. Onsuccess I redirect.
However, I get an error "A public action method '_Control' was not found on controller 'AttributeRoutingTest.Areas.Admin.Controllers.NewsController'." This is because it appears I need both GET and POST verbs to cater for the above POST and redirect(GET) in the save method.
I have uploaded a sample project to my sky drive:
https://skydrive.live.com/embedicon.aspx/Public/AttributeRoutingTest.zip?cid=e7737d00ff5b25e9&sc=documents
Here is some sample code.
Note the RenderAction
-- VIEW
@using (Html.BeginForm("Save", "News", new { area = "Admin" }, FormMethod.Post)) { <h2>Edit</h2> Html.RenderAction("_Control", "News", new { area = "Admin", controlId = "category", currentValue = "1" }); <br /> <input type="submit" value="Save" /> }
-- CONTROLLER: I have set it up for both get and post as per the following save action
[POST("News/_Control/{controlId}/{currentValue}")]
public ActionResult _Control(string controlId, int? currentValue)
{
return PartialView("_Control");
}```
-- SAVE ACTION
[POST("News/Save")]
public ActionResult Save()
{
bool saveErrored = true;
if (saveErrored)
return View("Edit"); // with model so previous values can be filled back in, allowing the user to make any corrections.
else
return RedirectToAction("Index");
}```
thank you very much,
Mike
Hi,
I have found an issue in the area routing.
If you add a controller to the area routing which starts with the same name as the area, the routing goes wrong.
So in your demo project you have an area called Admin.
I've added the following controller:
public class AdministratorController : AdminControllerBase
{
[GET("Administrators")]
public ActionResult Index()
{
return View();
}
}
I've added the corresponding View.
I assume that the following route will be added to the routing table:
http://localhost/Admin/Administrators
But instead the following route is added to the routing table:
http://localhost/Administrators
Could you please look in to this issue?
Thanks
Jan Saris
Hello,
I have the following routes on a controller:
[GET("Users")]
public virtual ActionResult Index(Int32 p = 1)
[GET("Users/New")]
public virtual ActionResult New()
[POST("Users"), ValidateAntiForgeryToken]
public virtual ActionResult Create(UserNewModel model)
[GET("Users/{id}")]
public virtual ActionResult Show(Int32 id)
[GET("Users/{id}/Edit")]
public virtual ActionResult Edit(Int32 id)
[PUT("Users/{id}"), ValidateAntiForgeryToken]
public virtual ActionResult Update(Int32 id, UserEditModel model)
[GET("Users/{id}/Delete")]
public virtual ActionResult Delete(Int32 id)
[DELETE("Users/{id}"), ValidateAntiForgeryToken]
public virtual ActionResult Destroy(Int32 id)
[GET("Users/SignIn")]
public virtual ActionResult SignIn()
[POST("Users/SignIn"), ValidateAntiForgeryToken]
public virtual ActionResult SignIn(UserSignInModel model)
When I try to access Users/SignIn I get a 404 error.
If I move this action to the top in the controller then it works fine.
But I don't see why.
Any idea?
Thank You,
Miguel
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.