This question has been asked in a similar but not identical fashion (and not resolved to my satisfaction) previously on Stack Overflow and elsewhere.
Coming from a linux-world, I want to use ASP.NET MVC but avoid identical but differently-cased routes from resolving to the same page. I do not want to force all routes to be 100% lowercase.
e.g. I want /Home/Something to be a valid route and /Home/somethingElse to also be a valid route, but not /Home/something or /home/somethingelse, given two functions called Something and somethingElse in the HomeController.
I can't find any way of doing this from within the RegisterRoutes function, but maybe I'm missing something obvious? I can answer this easily enough by adding code to each Controller function, but I'm obviously trying to avoid doing that.
Optimally, the solution would involve catching all permutations of a particular route, then 301 redirecting any that do not exactly match the case of the controller's function.
I was unable to find any way of doing this after extensive searching. Basically, case-sensitivity and IIS/ASP.NET apparently do not go together.
We're now using a bit of a kludge to solve this. The code has been opensourced (MIT license) on github: NeoSmart Web Toolkit, in particular, this file containing the SEO redirect code.
Using it is easy enough: each GET method in the controller classes needs to add just this one line at the start:
Seo.SeoRedirect(this);
The SEO rewrite class automatically uses C# 5.0's Caller Info attributes to do the heavy lifting, making the code above strictly copy-and-paste.
Ideally, I would love to find a way to turn that line of code into an attribute. For instance, prefixing the controller methods with [CaseSensitive] would automatically have the same effect as writing in that line, but alas, I do not (yet) know how to do this.
I also can't find any way of figuring this out with the Routing class/structures. That's some opaque code!
Related
I have solved a problem with a solution I found here on SO, but I am curious about if another idea I had is as bad as I think it might be.
I am debugging a custom security Attribute we have on/in several of our controllers. The Attribute currently redirects unauthorized users using a RedirectResult. This works fine except when calling the methods with Ajax. In those cases, the error returned to our JS consists of a text string of all the HTML of our error page (the one we redirect to) as well as the HTTP code and text 200/OK. I have solved this issue using the "IsAjaxRequest" method described in the answer to this question. Now I am perfectly able to respond differently to Ajax calls.
Out of curiosity, however, I would like to know what pitfalls might exist if I were to instead have solved the issue by doing the following. To me it seems like a bad idea, but I can't quite figure out why...
The ActionExecutingContext ("filterContext") has an HttpContext, which has a Request, which in turn has an AcceptTypes string collection. I notice that on my Ajax calls, which expect JSON, the value of filterContext.HttpContext.Request.AcceptTypes[0] is "application/json." I am wondering what might go wrong if I were to check this string against one or more expected content types and respond to them accordingly. Would this work, or is it asking for disaster?
I would say it works perfect, and I have been using that for years.
The whole point use request headers is to be able to tell the server what the client accept and expect.
I suggest you read more here about Web API and how it uses exactly that technique.
I'm trying to add some functionality to the default MvcHandler. What's happening is: I wanted to have dashed url's instead of Pascal Case url's. In other words if my controller is SomeController I wanted the URL to be /some-controller instead of /SomeController.
My best workaround was: I've created one mapping file URLMappings.xml which maps each controller to each desired URL. Then I've extended the default Route class to generate outgoing url's based on this and the default RouteHandler to understand the url's based on this. Well, this works fine because even if some mapping wasn't created then the framework will use the default behavior.
My point is: with this the routing system was understanding both kinds of Url's and this leads to duplicate content SEO problem. I wanted then to implement the following:
Get the controller value
See if on some mapping the controller name matches the value
If it matches, then there's some preferable URL than the one that was typed, should return 404.
I've searched on the web and the only way I've found to do this was to create a new IHttpHandler. However I don't want one from scratch, since I need all MVC functionality. I just want to put this logic on the ProcessRequest, however my overidden version of the method is not being executed.
Can someone give me some idea on how to deal with this ? Sorry if the question is silly or if it's not well detailed. If there's need for more information, just tell me.
You don't need a custom MvcHandler but a custom Route. There's a already NuGet package for this functionality called LowercaseRoutesMVC. Feel free to download it, explore the source code and adapt if necessary (to put the dash wherever you want to put it).
I'm a newbie to Symfony and I'm trying to switch my current project over to it.
For most of my controllers I need to do some multiple checks BEFORE executing the controller. Then if certain conditions are met for the check, forward them and show a different view, otherwise continue on to what they requested.
For example I have a group of controllers which should only be executed if the user is in a crew otherwise it loads a view saying "you're not in a crew".
This is very straight forward in procedural code, yet in OOP seems to get more complex, and now within a framework I seem to find myself even more limited.
How does one add logic before the controller is executed?
You want to set up before-filter logic. It's not something simple enough to write into a post here, but here's a good tutorial on doing so. If you have a specific issue with it, post here and I'll try to update with help: http://symfony.com/doc/2.0/cookbook/event_dispatcher/before_after_filters.html
This is more a cosmetic issue, rather than an actual "problem".
I've got a solution in which I am converting a lot of PageMethods into WebService calls instead. Some of the PageMethods created a page overhead of several hundred kilobytes, so I thought I'd extract them into their own WebServices, thus reducing the page overhead and enabling client side caching of the JavaScript proxies.
However, the project is structured with a lot of namespaces eg. CompanyName.Website.Services.MyService.ServiceMethod
This translates literally into JavaScript in the same namespaces.
In most cases I find this quite nice, but when I have around 20 methods in a service, it becomes quite tedious, always writing the same namespaces.
I did a bit of research, and found that I could write my own alias like so
var MyAlias = function() { CompanyName.Website.Service.MyService; }
Doing that, however, makes Visual Studio 2010 unable to provide intellisense. It works as expected, but I don't get to use the sweet, sweet intellisense I've come to love so much :)
So, my question is this: Are there any ways I can provide an alias for the generated proxy (like I can with custom types)?
I've tried using the attribute [System.Web.Script.Services.GenerateScriptType(typeof(MyService), ScriptTypeId = "MyServiceAlias")]
It does create some sort of alias, but I couldn't really figure out what impact it would have. Furthermore I don't think that's supposed to be used for static types like the WebService class is.
My requirements are, that I can shorten the generated proxy namespaces while keeping the original in the WebServices, but still get to use intellisense.
Thanks in advance...
How is it that I can create a method in the controller and just put some arguments and it figures it out after I click on a form submit? Under the hood, how does it find the right method and how does it figure out that I just want those arguments?
In a nutshell:
The routing engine handles the HttpRequest, and checks the requested URL. When it finds the first route match, it creates a new instance of MvcRouteHandler and passes it the broken-up tokens of the URL in a RouteValueDictionary.
The route's MvcRouteHandler takes the request, and tries to instantiate a controller class instance. By convention, it looks for a class called "XXXXXXController", where the X's are replaced by the {controller} parameter in the route.
Once it finds the controller, it invokes the appropriate method on it, given by the {action} parameter of the route. Any named arguments, such as {id}, that exist in the route, are passed as parameters to the method.
Basically, everything that ASP.Net MVC "knows" comes from the route information. It can't divine the parameters from thin air - they have to come from the route parsing. If the information isn't present in the requested URL, it can't be passed into the method.
It should also be noted that you can override the behaviour of the framework by making your routes use alternate handlers instead of MvcRouteHandler. The framework is quite extensible, so you can plug in custom functionality at many points.
There's quite a bit of code in play for controller, action and view resolution, as well as the ModelBinders. So much that it'd probably be best for you to look into specific portions of the framework and ask a more detailed question to get much of an answer.
Luckily, the ASP.NET MVC framework has been open-sourced, so if you're curious as to how it all works, you can get the code and look through it yourself. Its excellent code to read through and you're sure to learn something.
More to the point of your question, however, you should look at the System.Web.Mvc.MvcHandler and System.Web.Mvc.ControllerActionInvoker classes, which should lead you down the right path for answering your questions.