Coder Social home page Coder Social logo

restful-routing / restful-routing Goto Github PK

View Code? Open in Web Editor NEW
147.0 15.0 37.0 6.95 MB

A rails inspired restful routing api for asp .net mvc

Home Page: http://restfulrouting.com

License: MIT License

Ruby 0.52% CSS 1.82% C# 72.52% ASP 0.03% JavaScript 24.61% Pascal 0.49%

restful-routing's Introduction

Restful Routing for ASP .NET MVC

Inspired by the rails routing api.

Available via NuGet.

 PM> Install-Package RestfulRouting 

Checkout out the new documentation site included in this project, which can be found hosted at restfulrouting.com. If you find any improvements that need to be made, please feel free to contact us or send a pull request.

Basic usage:

public class Routes : RouteSet
{
	public override void Map(Mapper map)
	{
		map.Root<HomeController>(x => x.Show());
		map.Path("test/{id}").To<TestController>(x => x.Test()).Constrain("id", @"\d+");
		map.Resource<SessionsController>();
		map.Resources<BlogsController>(blogs =>
		{
			blogs.As("weblogs");
			blogs.Only("index", "show");
			blogs.Collection(x => {
				x.Get("latest");
				x.Post("someaction");
			);
			blogs.Member(x => x.Put("move"));

			blogs.Resources<PostsController>(posts =>
			{
				posts.Except("create", "update", "destroy");
				posts.Resources<CommentsController>(c => c.Except("destroy"));
			});
		});
	}
}

public class MvcApplication : System.Web.HttpApplication
{
	protected void Application_Start()
	{
		ViewEngines.Engines.Clear();
		ViewEngines.Engines.Add(new RestfulRoutingViewEngine());
		
		RouteTable.Routes.MapRoutes<Routes>();
	}
}

Read more

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don’t break it in a
    future version unintentionally.
  • Send me a pull request. Bonus points for topic branches.

Contributors

Written by Steve Hodgkiss with contributions from

Latest Release

1.5.0

  • Add support for customizing the name of the resource id parameter. Thanks Dan Malcolm.

1.4.6

  • Fixed a minor issue with resource names when in an area, not sure if anybody uses resource names but it was bugging me. Also nested Roots now reflect their origin. ex. root, area_root, area_nested_root.

1.4.5

  • long overdue helpful exception message. Everyone rejoice and no longer be confused.

1.4.4

  • allow you to nest Areas now properly, thanks again to Adrian Phinney.

1.4.3

  • fix for Area Mapper prefix. Thanks to Adrian Phinney.

1.4.0

  • added new DSL to allow you to redirect dead links, to newer urls.

1.3.5

  • added the ability to ReRoute inside a Resource mapping. Thanks to David Alpert.

1.3.4

  • added the ability to see non Restful Routing (RouteBase) routes in routedebugger, helpful for seeing things like the order of routes. Helped me debug an issue with SignalR.

1.3.3

  • added “staff” to inflector. Thanks Nathan Wood.

1.3.2

  • All routes now get namespaces, by default. This will save a lot of headaches, and the ability to reuse controller names not in the same namespace.

1.3.1

  • Switched route debugger over to use Twitter Bootsrap from CDN sources
  • Merged in namespace additions from woodnathan

1.3.0

  • Removed dependency on RazorEngine so we can start moving to ASP.Net MVC 4.

1.2.3

  • Fixed float parsing on systems with decimal separator other than “.” (thanks irium)

1.2.2

  • Fixes ordering issue with Only (thanks Tommysqueak)
  • Fixes StandardMapper to use RestfulHttpMethodConstraint (thanks Tommysqueak)
  • Fixed version number on dll to match version number of Restful Routing

1.2.0

  • Addition of ExposeResult in FormatResult (thanks SlyNet)

1.1.3

  • New Route Debugger (uses datatables for filtering)
  • Mono Fixes (thanks cdroulers)
  • Released version to Nuget

restful-routing's People

Contributors

ayoung avatar cdroulers avatar corydeppen avatar danmalcolm avatar davidalpert avatar defeated avatar exalted avatar khalidabuhakmeh avatar mbp avatar ro31337 avatar slynet avatar stevehodgkiss avatar thecloudlesssky avatar tt avatar woodnathan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restful-routing's Issues

Route name

For several reasons I'm generating links with Html.RouteLink().
As far as I can see, restful routes don't have names :(

It would be wonderful if they had! For example, "Blogs#Index", "Blogs#New" or similar...

Named Route Example

I am trying to figure out how to get access to the named routes.

My route looks something like this:

map.Path("approve/{guid}")
     .To<QuotesController>(x => x.Approve(new Guid()))
      .Constrain("guid", @"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$")
      .Named("Approved");

I've tried:
<a href="@Url.RouteUrl("Approved", new { guid = Model.Guid })">test</a>

But it results in:
A route named 'Approved' could not be found in the route collection. Parameter name: name

It would be awesome if you could add an example in the readme. You show how to setup complex routes, but not how to access them via the view.

Thank you for this great gem (?)

Andrew

Better Exception when modifying the collection in the wrong scope

System.InvalidOperationException: Collection was modified; enumeration operation may not execute. This gets thrown when you are modifying the collection from within a scope. Example:

map.Area<AdjustmentsDashboardController>("dashboards", dashboards =>
{
        // Oooooops!!! Should be using dasbhoards and not map
    map.Path("adjustments").To<AdjustmentsDashboardController>(x => x.Index(null, null));
    map.Path("discounts").To<AdjustmentsDashboardController>(x => x.Index(null, null));
});

This is user error, but should probably give a more helpful exception.

[InvalidOperationException: Collection was modified; enumeration operation may not execute.]
System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) +52
System.Collections.Generic.Enumerator.MoveNextRare() +10689337
System.Collections.Generic.Enumerator.MoveNext() +64
RestfulRouting.Mapper.RegisterRoutes(RouteCollection routeCollection) +143
RestfulRouting.RouteSet.RegisterRoutes(RouteCollection routes, String[] namespaces) +94
RestfulRouting.MapRoutesExtension.MapRoutes(RouteCollection routes, String[] namespaces) +111

Trying to configure a fairly simple /NameSpace/Controller/id path

      map.Namespace("rest", typeof(OIDCreatorController).Namespace, m =>
                                {
                                    //m.Resource<OIDCreatorController>();
                                    m.Resource<MemberAPIController>();
                                    m.Resource<SudoScheduleController>();
                                });

But when I send a url that is http://localhost/rest/SudoSchedule/2 MVC looks for an action "2" as opposed to passing 2 to the SHOW method.

Here is my entire Application.cs file:

  routes.MapRoute(
                 "Default",                                              // Route name
                 "",
                 new { controller = "Home", action = "Index", id = "" }
            );
        // need to use namespaces when using controllers with the same name
        //var configuration = new RouteConfiguration { Namespaces = new[] { typeof(RestMemberFaxPHIController).Namespace } };
        var map = new RestfulRouteMapper(RouteTable.Routes);

          map.Namespace("rest", typeof(OIDCreatorController).Namespace, m =>
                                {
                                    //m.Resource<OIDCreatorController>();
                                    m.Resource<MemberAPIController>();
                                    m.Resource<SudoScheduleController>();
                                });



        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapRoute(
                 "Default2",                                              // Route name
                 "{controller}/{action}/{id}",                           // URL
                 new { controller = "Home", action = "Index", id = "" }
            );

<<<

Refactor

The way restful routing uses Action has a pretty bad affect on the testability and design of the code. It means that to add a method to resources Resources(() => Something()) it has to be defined on the RouteSet class. Going back to using a typed action i.e. Action<ResourcesMapper> will make the code much cleaner. The RouteSet definition won't look as neat but it'll be more intellisense discoverable. Example:

public class Routes : RouteSet
{
    public override void Map(Mapper map)
    {
        map.Root<RootController>(x => x.Index());
        map.Map("routedebug").To<RouteDebugController>(x => x.Index());
        map.Resources<BlogsController>(blogs =>
                                                {
                                                    blogs.WithFormatRoutes();
                                                    blogs.Member(x => x.Get("test"));
                                                    blogs.Resources<PostsController>();
                                                });
    }
}

I'm not sure when (or if) I'm going to do this but it's been on my mind for a while.

Resources Using ApiController

I am working on an API project using the MVC4 ApiController base class for my controllers. I ran into an issue trying to map resources. Is this something that I am missing or something that makes sense to add. I really like the approach restful routing uses and love the route debug.

Can't map querystring arguments to member route?

Howdy folks,

This is probably a stupid question but I couldn't find any answers to this in the documentation or the source code.

I have a route that looks like this:

"~/project/{id}/dosomething?count=10&offset=0

Here's what the resource routing looks like:

map.Resources<ProjectController>(projects =>
                {
                    versions.Member(x => x.Get("dosomething"));
                });

For the life of me I simply cannot get that route to bind - the controller action method definition looks like this:

    //
    // GET: /LoadScreenshots
    public ActionResult DoSomething(string id, int count = 5, int offset = 0)
    {
        return Json(_projectService.LoadStuff(id, count, offset), JsonRequestBehavior.AllowGet);
    }

Am I doing something wrong, or is this a limitation of RESTful-routing? I can't get this route to match!

Hook into Restful Routing Mappers and generate a client side "RouteTable"?

As applications move closer to living on the client side (SPA). It would be cool to allow users access to the routes in a way that supports cleaner client side access.

map.Resource<SessionsController>();
map.Resources<BlogsController>(blogs =>
{
    blogs.As("weblogs");
    blogs.Only("index", "show");
    blogs.Collection(x => {
        x.Get("latest");
        x.Post("someaction");
    );
    blogs.Resources<PostsController>(posts =>
    {
        posts.Except("create", "update", "destroy");
        posts.Resources<CommentsController>(c => c.Except("destroy"));
    });
});

might generate the following JSON object.

Routes = {
  sessions : {
      index : { url: '/sessions', method:'GET' },
      show : { url: '/sessions/:id', method:'GET', with: function( id ) { ... }  },
      new : { url : '/sessions/new', method:'GET'  },
      //...
      update : { url: '/sessions/:id', method:'PUT' }
  } , 
  blogs : {
   //... all actions
      posts : { //... post actions }
  }
}

you would utilize it using it this way in your JavaScript methods.

//  for update
var route =  Routes.sessions.index;
$.ajax({
    url: route.url,
    type: route.method,
    success : function(result) {
            console.log(result);
    }
});

or for routes that require parameters

//  for update
var route =  Routes.sessions.update.with('1');

$.ajax({
    url: route.url,
    type: route.method,
    data : { name : 'test' },
    success : function(result) {
            console.log(result);
    }
});

Restful Routing will expose this JavaScript routes through a route (surprise!), and also make it possible to generate it and spit it out into a flat file in case you want to bundle it.

You'll be able to set it like you can with routedebug. We can also cache bust it for you if are still in development.

map.JsRoute("client_routes.js", bust: true);

So what do you guys think? Is it a thing you want, or is this a crazy thought?

GET /Delete

Hi I was wondering if it would be possible to add a route which allows you to go to a page like /posts/1/delete which is just a get so that you can have a "Are you sure you want to delete this?" then a form with an input and a <%= Html.DeleteOverrideTag() %> on it. I think that by default it doesn't add this as route.

Sample is broken?

In the sample solution the FormatResult returns XML as default format for the BlogsController#Index action.
Is this a bug in FormatResult or in the usage in the samples?

Extension based content negotiation

Hi, is there any functionality that allows extension based content negotiation?

e.g. If the URI is /foo.json, you can infer the accept content type application/json, /foo.xml -> application/xml, /foo.txt -> text/plain, etc

RestfulHttpMethodConstraint not working properly

When routing with the Resource method, the destroy action is never accessible, it instead routes to the Create action. This is because the previous routes that are mapped (and therefore matched before the route that should really match), for example the route to update, that has the same url but the PUT verb, if it cannot Match with the verb, it falls back to the base method, thus routing to a normal POST. This is why the Create method is called, even if the hidden input was included in the form.

What I suggest is falling back to the base method only if the verbs allowed contain either GET or POST, else just return false.

Perhaps you can find a better solution.

If I couldn't explain myself very well please tell me so!

Put override has no effect

When mapping a Resource and using the Html.PutOverrideTag() helper to override the POST to a PUT the request ends up in organizations#create and not #update as expected.

I think I have set up everything correctly.

Thanks, great work!

RouteDebug object null exception

In the index action it assumes that there will always be constraints, but using MvcMiniProfiler breaks RouteDebug.

var httpMethodConstraint = route.Constraints["httpMethod"] as HttpMethodConstraint;

The fix could be as easy as

var httpMethodConstraint = (route.Constraints ?? new RouteValueDictionary()) ["httpMethod"] as HttpMethodConstraint;

Strongly typed Additional action registration

I wanted to discuss some additions to routes registration API. In current version I can write an extension method like this:

    public static class RoutesExtensions
    {
        public static void Member<TController>(this IResourcesMapper<TController> mapper, Expression<Action<TController>> member, HttpVerbs verb) 
            where TController : Controller
        {
            var methodCall = member.Body as MethodCallExpression;
            if (methodCall == null) 
                throw new ArgumentException("member value should be a call to controller action method", "member");

            string methodName = methodCall.Method.Name;

            switch (verb)
            {
                case HttpVerbs.Get:
                    mapper.Member(x => x.Get(methodName));
                    break;
                case HttpVerbs.Put:
                    mapper.Member(x => x.Put(methodName));
                    break;
                case HttpVerbs.Post:
                    mapper.Member(x => x.Post(methodName));
                    break;
                case HttpVerbs.Delete:
                    mapper.Member(x => x.Delete(methodName));
                    break;
                case HttpVerbs.Head:
                    mapper.Member(x => x.Head(methodName));
                    break;
                default:
                    throw new NotSupportedException("Provided http verb is not supported");
            }
        }
    }

And it will allow to change registration of "Test" in sample site from

// old version
blogs.Member(x => x.Get("test"));
// new version:
blogs.Member(x => x.Test(0, null), HttpVerbs.Get);

Currently I don't like here two things:

  1. With lambda expression we need to pass parameters in method
  2. Switch statement in the method (it can be removed easily if move this extension method to core assembly and make Route method of AdditionalAction class internal)

But we removed a magic string - method name.
What do you think about it?

No route in the route table matches the supplied values

Error:
No route in the route table matches the supplied values.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: No route in the route table matches the supplied values.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: No route in the route table matches the supplied values.]
System.Web.Mvc.RedirectToRouteResult.ExecuteResult(ControllerContext context) +379311
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +10
System.Web.Mvc.<>c__DisplayClass14.b__11() +20
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) +251 System.Web.Mvc.<>c__DisplayClass16.<InvokeActionResultWithFilters>b__13() +19 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList1 filters, ActionResult actionResult) +178
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +314
System.Web.Mvc.Controller.ExecuteCore() +105
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +39
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
System.Web.Mvc.<>c__DisplayClass8.b__4() +34
System.Web.Mvc.Async.<>c__DisplayClass1.b__0() +21
System.Web.Mvc.Async.<>c__DisplayClass81.<BeginSynchronous>b__7(IAsyncResult _) +12 System.Web.Mvc.Async.WrappedAsyncResult1.End() +59
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +44
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8679150
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Globals.ascx:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RestfulRoutingViewEngine());

        RouteTable.Routes.MapRoutes<Routes>();
    }
}


public class Routes : RouteSet
{
    public Routes()
    {
        Map("").To<HomeController>(_ => _.Index());

        Map("routedebug").To<RouteDebugController>(_ => _.Index());

        Route(new Route("user/{action}", new RouteValueDictionary(new { controller = "user" }), new MvcRouteHandler()));


        Area<GroupsController>("", () =>
        {
            Resource<ProjectsController>(()=> { });
        });

    }
}

HomeController:
public class HomeController : Controller {
public ActionResult Index() {
Response.AppendHeader(
"X-XRDS-Location",
new Uri(Request.Url, Response.ApplyAppPathModifier("~/Home/xrds")).AbsoluteUri);
return RedirectToAction("Index", "Groups");
}

    public ActionResult Xrds() {
        return View("Xrds");
    }
}

Sample project don't working.

The controller name 'blogs' is ambiguous between the following types:
RestfulRouting.Sample.Controllers.Admin.BlogsController
RestfulRouting.Sample.Controllers.BlogsController

StandardMapper ignores PUT, DELETE overides

The ResourcesMapper uses RestfulHttpMethodConstraint which allows a POST to be treated as a PUT, if there's a hidden input (_method or X-HTTP-Method-Override) but the StandardMapper doesn't.

I can tap both on the end: '...Allow(HttpVerbs.Post).Allow(HttpVerbs.Put);' but it feels like it should behave the like the resources, as override is not limited to restful resources, it's just a way to allow PUT, DELETE in browsers that don't support the verbs.

Just wanted to get your opinion. If you think it should behave that way, I'll popover a patch.

ReRoute does not work for Resources (plural!) mapper

Here's a simple mapping:

map.Resources<ImagesController>(images =>
{
    images.ReRoute(p => p.New = "{resourcesPath}/{id}.png");
});

This does not work with Resources<T> mapping - it doesn't modify the mapped paths at all. However, it does work if using Resource<T> (singular).

Support Lambda Registration of Async Actions

Async Controllers are a valuable part of the ASP.Net MVC framework. Currently you can register the actions with the extension "Member" but cannot with Path unless you create a stub action.

These actions are two parts, for one action. For example:

  • Action: Test
  • Start: TestAsync
  • Completed : TestCompleted

More can be found here http://msdn.microsoft.com/en-us/library/ee728598.aspx

This is not a huge priority since there are work arounds using Member registration.

Documentation out of date

Hey,
I'm a long time rails developer but have been forced to work with ASP, so I went the MVC 3 way and found your package. However the docs on the site and on github seem to be out of date, github gets me closer to actually working but both cases I get issues.
Following Github instructions I get:
The type Routes doesn't have a static method named Start
Following the website, I get:
'Routes' does not implement inherited abstract member 'RestfulRouting.RouteSet.Map(RestfulRouting.IMapper)'
Hard to figure out what's happening when my .net knowladge is limited.

Could not load file or assembly RazorEngine

When I try to see the debug routes path, I get this error:

Could not load file or assembly 'RazorEngine, Version=2.1.4039.23635, Culture=neutral, PublicKeyToken=1f722ed313f51831' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

My route (for the debugger) is:
map.DebugRoute("routedebug");

Better exception when an unexpected verb is used

I typed: .Only("create", "show", "delete") and got a The given key was not present in the dictionary. (It should be 'destroy' not 'delete'.)

A better exception, perhaps listing the valid values, would be nice.

json deserialization empty string results in null

I have found when an object is received in a controller's action method the json has properties set to empty string "" but when the method gets the deserialized class the properties are set to null and not empty string.

I have checked serialization and deserialization of empty string with System.Web.Script.Serialization.JavaScriptSerializer and empty string makes it through serialization and deserialization. It is when restful-routing is handing the deserialization that I find null in the place of an empty string.

Naming of Routes borked when dealing with Areas

To recreate follow these steps:

  1. Create an area
  2. Have more than 2 resources in that area
  3. open up route debugger and you will notice somehow that the names are intermingled.

The routes are fine and since most people don't use the names this is a non breaking issue, just annoying to see a goofed up name.

Map() does not work as expected

When Map() is used more than one level deep, nesting does not work as expected - example:

        Resource<LocationController>(() => {
            Resource<ProfileController>(() => {
                Map("snafu")
                    .To<TestController>(x => x.Snafu());
            });
        });

Inspecting the generated routes, I would expect to see "location/profile/snafu" for the inner route - but instead the generated route is just "profile/snafu", with the parent "location" route getting discarded for some reason.

Am I doing something wrong, or should I expect this to work?

Make solution build in Mono

The solution doesn't currently work in Mono because we need to add the references to the assemblies missing from mono:

  • System.Web.Mvc.dll - ASP
  • System.WebPages
  • etc..

Basically all the assemblies necessary to to deploy and ASP.Net MVC 3 app.

Will probably have to do this for ASP.Net MVC 4 as well when it becomes RC.

Request validation triggering inside route matching?

I have a form that will have HTML tags in at least one of the text areas. Per the MVC 4 documentation I added the [AllowHtml] attribute to the view model properties, so that MVC's built in request validation doesn't complain. However, it's not working, and the stack trace seems to indicate that RestfulRouting is the culprit:

[HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (LocalInformation="**<a href="http://www....").]
System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8862740
System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) +122
System.Web.HttpRequest.get_Form() +150
System.Web.HttpRequestWrapper.get_Form() +11
RestfulRouting.RestfulHttpMethodConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +264
System.Web.Routing.HttpMethodConstraint.System.Web.Routing.IRouteConstraint.Match(HttpContextBase httpContext, Route route, String parameterName, RouteValueDictionary values, RouteDirection routeDirection) +22

I'm using MVC 4 on .Net 4.0.

My route is a standard REST "update" route.

can't use RestfulRouting with web api

hello, i'm trying to use restful routing with web api controllers (ApiController)
but ApiController doesn't inherit from Controller, so I can't use IMapper

is there a way to use it?

Delete route is missing

When running the Sample project I noticed the href attribute is empty for the delete link in all pages. After further review it appears any code regarding the Delete route is missing. Is this by design?

I have updated the following code files with appropriate code and all seems to work ok.
ResourcesMapper.cs (added method DeleteRoute())
ResourceMapper.cs (added method DeleteRoute())

Mapping.cs (included DeleteName in the IncludeActions list in the method EnsureIncludedActionsIsInitialized)

ResourceMapping.cs (ensure route is added to routeCollection in AddRoutesTo method)
ResourcesMapping.cs (ensure route is added to routeCollection in AddRoutesTo method)

RestfulRoutingRazorViewEngine

currently the view engine in restful-routing is webforms based, that works great with MVC 2 and MVC 3 if you stick with webforms. Sadly it does not work with Razor views. It is as simple as changing the extensions from aspx and ascx to cshtml.

You could combine them in one view engine, or create a separate viewengine for both formats.

Proposed new method on StandardMapping to allow HttpVerbs

The method is as follows:

public StandardMapping Allow(params HttpVerbs[] verbs)
{
var allowedMethods = verbs.Select(x => verbStrings[x]).ToArray();
Route.Constraints["httpMethod"] = new HttpMethodConstraint(allowedMethods);

        return this;
    }

verbStrings is a static dictionary declared as follows:

private static readonly Dictionary<HttpVerbs, string> verbStrings =
new Dictionary<HttpVerbs, string>
{
{HttpVerbs.Get, "GET"},
{HttpVerbs.Post, "POST"},
{HttpVerbs.Put, "PUT"},
{HttpVerbs.Delete, "DELETE"},
{HttpVerbs.Head, "HEAD"},
};

I think is worthy to have, to avoid creating HttpMethodConstraints with a string to indicate the verb.

Mono 2.10.5 compatibility issue with FormatResult

Breaks because the Mono implementation of IndexOf doesn't optimise searches for nulls.
Quick fix is required in AcceptType.Equals(object obj)

Fork + pull request to follow!

Object reference not set to an instance of an object

Description: HTTP 500. Error processing request.

Stack Trace:

System.NullReferenceException: Object reference not set to an instance of an object
at RestfulRouting.Format.AcceptType.Equals (System.Object obj) [0x00000] in :0
at System.Collections.Generic.EqualityComparer1+DefaultComparer[RestfulRouting.Format.AcceptType].Equals (RestfulRouting.Format.AcceptType x, RestfulRouting.Format.AcceptType y) [0x00000] in <filename unknown>:0 at System.Array.IndexOf[AcceptType] (RestfulRouting.Format.AcceptType[] array, RestfulRouting.Format.AcceptType value, Int32 startIndex, Int32 count) [0x00000] in <filename unknown>:0 at System.Collections.Generic.List1[RestfulRouting.Format.AcceptType].IndexOf (RestfulRouting.Format.AcceptType item) [0x00000] in :0
at RestfulRouting.Format.AcceptList.CustomSort () [0x00000] in :0
at RestfulRouting.Format.AcceptList..ctor (RestfulRouting.Format.MimeTypeList types, System.String[] acceptTypes) [0x00000] in :0
at RestfulRouting.Format.MimeTypeList.Parse (System.String[] acceptTypes) [0x00000] in :0
at RestfulRouting.Format.FormatResult.GetFormat (RestfulRouting.Format.FormatCollection formatCollection, System.String[] acceptTypes) [0x00000] in :0
at RestfulRouting.Format.FormatResult.GetResult (RestfulRouting.Format.FormatCollection formatCollection, System.Web.Routing.RouteValueDictionary routeValues, System.String[] acceptTypes) [0x00000] in :0
at RestfulRouting.Format.FormatResult.ExecuteResult (System.Web.Mvc.ControllerContext context) [0x00000] in :0
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult (System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ActionResult actionResult) [0x00000] in :0
at System.Web.Mvc.ControllerActionInvoker+<>c__DisplayClass1c.b__19 () [0x00000] in :0
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter (IResultFilter filter, System.Web.Mvc.ResultExecutingContext preContext, System.Func`1 continuation) [0x00000] in :0

Modelstate when redirecting across actions

I have found that when everything is perfect with your actions then Restful-Routing is great. But what happens when there are validation issues when posting/putting to actions like CREATE, UPDATE, and even DESTROY.

In ASP.NET MVC you should be using ModelState to check the validity of your models, but this can be lost when redirecting from CREATE,UPDATE, and DESTROY back to NEW and EDIT actions. I feel the solution is probably TempData.

So I was looking through MVCContrib and found the ModelStateToTempDataAttribute.

I was just wondering if RestfulRouting should have a similar filter, or should we just force people to use MVCContrib or write their own?

This is definitely and issue, just would like some input on how to approach this solution.

Mapper.Area does not use pathPrefix parameter

I figured that I could use the Area mapper for something like this:

map.Area("FooBar", "/foo/bar", fooBar =>
{
    // ...
});

And then get /foo/bar/* URLs generated. However, the second parameter, pathPrefix is ignored in both the generic and non-generic Area methods.

Is there a reason for this? The only way I've been able to work around this is to use:

map.Area("foo/bar", fooBar =>
{
    // ...
});

However, this requires that the area name have a slash in it.

Constraints do not inherit

When routing nested resources, their constraints are not properly inherited.

For example:

        Resources<LocationController>(() => {
            Constrain("id", @"\d+");
            Resource<ProfileController>(() => {
                Map("snafu")
                    .To<TestController>(x => x.Sample(""));
            });
        });

The id constraint is not inherited by the inner routes.

I've tried to fix it, but this appears to be non-trivial, since the name (id) actually may be different in nested routes (e.g. LocationId, ProfileId, etc.) ... I'm afraid I don't know how to fix this.

Mapping child collection actions/controller?

We have something similar to the following structure:

GET    /music
POST   /music
GET    /music/:id
GET    /music/starred
POST   /music/starred/:id
DELETE /music/starred/:id
etc...

We also have a "private" collection with very similar URLs:

GET    /music/private
POST   /music/private
GET    /music/private/:id
GET    /music/private/starred
POST   /music/private/starred/:id
DELETE /music/private/starred/:id
etc...

Right now, I can do it with something like this:

map.Resources<StarredMusicController>(flowsDraftStarred =>
{
    flowsDraftStarred.As("music/private/starred");
});

map.Resources<StarredMusicController>(flowsLiveStarred =>
{
    flowsLiveStarred.As("music/starred");
});

map.Resources<MusicController>(flowsDraft =>
{
    flowsDraft.As("music/private");
});

map.Resources<MusicController>(flowsLive =>
{
    flowsLive.As("music");
});

However, I was wondering if there is an easier way to map using the "nested" nature of the URL structure? There is a lot of repetition going on in these mappings (they've been simplified for this example).

What I'd like to be able to do is use IResourceMapper<T>.Collection() or a nested IMapper.Resources<T>(). The problem with using Collection() is that it does not allow you to map to a different controller. With Resources<T>, the child resources are mapped like /music/{musicId}/starred/{id} - when we actually want starred to be a collection of all of the music.

Routing registration problems

  1. Sample routes:
    public Routes()
    {
    Map("").To(x => x.Index());
        Map("routedebug").To<RouteDebugController>(x => x.Index());



        Area<BlogsController>("",
            () =>
            {
                Resources<BlogsController>(() => Resources<PostsController>());
            });
    }

It's routedebug:
HttpMethods Area Path Endpoint Namespaces
GET root#index
GET routedebug routedebug#index
GET blogs blogs#index RestfulRouting.Sample.Controllers
POST blogs blogs#create RestfulRouting.Sample.Controllers
GET blogs/new blogs#new RestfulRouting.Sample.Controllers
GET blogs/{id}/edit blogs#edit RestfulRouting.Sample.Controllers
GET blogs/{id} blogs#show RestfulRouting.Sample.Controllers
PUT blogs/{id} blogs#update RestfulRouting.Sample.Controllers
DELETE blogs/{id} blogs#destroy RestfulRouting.Sample.Controllers
GET blogs/{blogId}/posts posts#index RestfulRouting.Sample.Controllers
POST blogs/{blogId}/posts posts#create RestfulRouting.Sample.Controllers
GET blogs/{blogId}/posts/new posts#new RestfulRouting.Sample.Controllers
GET blogs/{blogId}/posts/{id}/edit posts#edit RestfulRouting.Sample.Controllers
GET blogs/{blogId}/posts/{id} posts#show RestfulRouting.Sample.Controllers
PUT blogs/{blogId}/posts/{id} posts#update RestfulRouting.Sample.Controllers

  1. My routes config:
    public Routes()
    {
    Map("").To(_ => _.Index());
        Map("routedebug").To<RouteDebugController>(_ => _.Index());

        Route(new Route("user/{action}", new RouteValueDictionary(new { controller = "user" }), new MvcRouteHandler()));


        Area<GroupsController>("", () =>
        {
            Resources<GroupsController>(() => Resource<ProjectsController>());
        });

    }

Routedebug:
HttpMethods Area Path Endpoint Namespaces
GET home#index
GET routedebug routedebug#index
user/{action} user#
GET groups groups#index DevGroups.Web.Controllers
POST groups groups#create DevGroups.Web.Controllers
GET groups/new groups#new DevGroups.Web.Controllers
GET groups/{id}/edit groups#edit DevGroups.Web.Controllers
GET groups/{id} groups#show DevGroups.Web.Controllers
PUT groups/{id} groups#update DevGroups.Web.Controllers
DELETE groups/{id} groups#destroy DevGroups.Web.Controllers
GET groups/project projects#show DevGroups.Web.Controllers
POST groups/project projects#create DevGroups.Web.Controllers
GET groups/project/new projects#new DevGroups.Web.Controllers
GET groups/project/edit projects#edit DevGroups.Web.Controllers
PUT groups/project projects#update DevGroups.Web.Controllers
DELETE groups/project projects#destroy DevGroups.Web.Controllers

I can't find where is defined what blogs area accept "blogId" to identify Blog.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.