Allow customizing what constitutes a controller for POCO controllers #1274
Comments
Some ideas we discussed:
|
Just researching support for POCO controllers. Will this enhancement mean I wouldn't have to use the suffix "Controller" on my controllers? |
This could absolutely mean that, but of course you will have to do something to let us know your class is a controller. See the list above for details, but some short examples.
options.ControllersBaseTypes.Add(typeof(MyCustomBaseClass));
// or
[Controller]
class MyCustomBaseClass
// or
class MyCustomBaseController // <-- Controller suffix indicates controller
options.IsController = (Type t) => return t.Name.StartsWith("Foo"); You can of course customize the existing service that picks up controllers, but we prefer to make it a bit easier, and we advocate that replacing services in MVC6 will most of the times mean we got something wrong. We'd rather get it right from the get go, or provide an option for the 99% case. It would be nice if you can share you plans and reasoning for using POCO controllers, we might just be able to accomodate it when we lock the design for this feature. |
I'm interested in the technical reasoning for requiring the controller to be tagged somehow for the runtime. Mainly because I suspect there might be a much more deliberate way to go about this (or have both options if some prefer convention). What would be nice is if the POCO controller didn't require annotations. I'm coming from a PHP background, specifically Laravel. In that system, they allow for you to author routes as follows:
Out of all the routing conventions, this shorthand (something I think you guys are already very close to matching), has been very nice to use. The simplicity is in the DSL. It allows the framework authors to not have to rely on tagging/reflection mechanisms to route. The framework also reflects on both the class and the action method to see if dependencies need to be injected. It's worth repeating that the framework also supports convention based routing, so if desired, the developer can write less specific routes. So, in MVC 6, my hope would be to see something like the following:
You'll note the distinction about static controllers which is a concept similar to Scala's |
Technical reason? Because sometimes discovery is nice. When you don't want discovery and want to be explicit about everything, you can be but discovery makes the getting started much simpler. |
So that's saying it's required out of wanting to offer the convenience. I was asking if there was a technical limitation mandating that the tagging had to happen. But judging by your answer, there isn't - which is good! Right now writing routes in ASP.NET MVC 5/6 isn't the prettiest. This more explicit scenario allows for a much cleaner routing config. I can express 90% of routes, whether convention or custom using a single line instead of having to pollute wherever I define my routes with multiple lines and anonymous objects. |
I'm guessing that the majority would prefer to write it that way. The rest that don't can use whatever mechanism this bug gets resolved with. |
If you're doing the right thing, I think you'll find that over time, the opposite is true. To date, ASP.NET MVC users have only had one option - so you might be right for existing users today - but even that changes when a better option becomes available. Don't forget the attrition of documentation too. If your only documented method is one way, the community takes it as prescriptive and will not question. That could even be in spite of whether it's a best practice or the most convenient out of two options. All it proves is that that most people are - rightfully - there to get the job done and won't be bothered to dig into internals because they expect you to lead them to safety. That means that if my suggestions here are implemented they must be clearly documented & featured. Otherwise you'd definitely be right because nobody would know about the more user-friendly syntax! ;)
(I should note, I continuously reference Laravel because it's a very well designed framework. As of today, I consider its routing the gold standard.) Taking all these examples into account, ASP.NET MVC is clearly an outlier and route mapping is one area I think you can have a really positive impact. |
Thanks for the lesson. I think only a few of these apply since we have to look past route definitions and discovery and do what is idiomatic given that c# is the language. If we did inline routes (and we'll probably have a low level way of doing that directly in routing as isn't mvc specific at all) that would be cool for simple stuff. Now the mvc pipeline includes, action selection, model binding filter execution, conneg etc . Some of these features completely would need to be handled differently when you change the pattern and I think it'll take alot more effort to design a system around those patterns (and some are worse imo, at least for c#). That said, if you want an explicit way to map controller classes, there will probably be one. Other than that, you can extend the framework or use one of the many others that exist on .net. For comparison though, you should look around at some existing .net web frameworks as well to compare and contrast the approaches. Nancy is one that stands out pattern wise. |
Nice as it may seem, that approach sounds like it could get pretty out of hand (see my notes on nancy below). Routing is something you want to try and keep as simple as possible, and encourage people to move on. I'm familiar with Nancy and didn't reference it for a few reasons. Overall for routing, I don't think it's user friendly. It also imposes some compromises that don't make sense - the most ugly of which is that it requires that all dependencies be resolved up front when routes are defined (ouch!). |
So in MVC6 we don't recommend going with the pattern of defining routes with default objects, this was a very cumbersome syntax. When it comes to "documentation", the new templates are going to show the new pattern right from the get go. So you would just: Now just like David suggests it is rather easy to implement something like you are looking for, but we are still debating what would an approach closer to your suggestion looks like. #1877 discuss a potential way to apply attribute routes in a centralized way, it can completely be written on top of current MVC without changing any of the MVC services implementing an #1877 It does not resolve the issue of having to have a controller suffix or derive from controller. But honestly I don't quite get why you won't do that. Following framework conventions makes new developers on your team having to learn less and be more effective. So in short this issue is really about the following scenario:
|
Yeah - the syntax for options is not nice at all. But that doesn't mean specifying controllers explicitly is a bad practice. It means MVC misjudged the importance of getting this right. Catch-all mappings like
In fact, the first thing I do in a framework project is remove any generic class-name-maps-to-route defaults. They simply aren't helpful. What if I want two controllers named the same? I obviously namespace the classes at that point. But how does the router differentiate when all the action methods have been flattened into one namespace? Now you're having to kludge your app's external signature to satisfy a hard-baked convention. Attribute mapping for the paths of controllers is also an issue. Especially if your controllers are supplied by external libraries (and the mapping is left to you). It comes up when you want to add a prefix to groups of controllers There is really no one-shot solution for routing that you can call a "convention". It's better to have a minimal and flexible syntax instead of creating a rigid system and then having to code in confusing ways for the implementer to pre-empt it. At first read, #1877 seems to reflect what I'm suggesting so far. But these two issues are definitely connected. |
Design - We will walk up and look for a base class that is named according to the "standard" |
determine if any ancestor has the "Controller" suffix. * Introduce NonControllerAttribute to opt out of Controller detection. Fixes #1274
determine if any ancestor has the "Controller" suffix. * Introduce NonControllerAttribute to opt out of Controller detection. Fixes #1274
determine if any ancestor has the "Controller" suffix. * Introduce NonControllerAttribute to opt out of Controller detection. Fixes #1274
determine if any ancestor has the "Controller" suffix. * Introduce NonControllerAttribute to opt out of Controller detection. Fixes #1274
Right now, when a user writes a POCO controller it has to end with the controller suffix.
After writing the ApiController (which is basically a POCO controller) it behaves slightly differently than the non POCO controller.
We can make an MVC Option that is either a predicate indicate what controller is, or a list of base types that behave similarly to controller along the lines of
IsAssignableFrom(baseType)
The text was updated successfully, but these errors were encountered: