ServiceStack DefaultRedirectPath not triggering - asp.net-mvc

I'm using ServiceStack in an MVC4, VS2012 project running on windows7. I'm attempting to call a default "/search" route when the application loads. To do this I have the following code in my AppHost Configure method
Plugins.Add(new RazorFormat());
SetConfig(new EndpointHostConfig
{
ServiceStackHandlerFactoryPath = "api",
DefaultRedirectPath = "/search"
});
If I call this route directly (via /api/search) it works correctly. However when I run my project I simply get a HTTP Error 403.14 - Forbidden error. It's appears to be attempting to locate a static source document from the website root (I've removed all of these) rather than the dynamic route specified in DefaultRedirectPath
I've also added a HttpHandler via the CatchAllHandlers method to see if the route is being attempted but it appears the DefaultRedirect is simply not happening.
Any suggestions would be greatly appreciated. From everything I've read this should just work.

I'm assuming that you've set up your /api path correctly in web.config too.
DefaultRedirectPath is just a simple redirect used when you request the root of your API (i.e. "/api"). It literally returns a 302 with your DefaultRedirectPath as the Location header (combined with the application root URL, if your ASP.NET application isn't at the root of the server). In other words, it's not a "route", just a relative URL. And in your case, it will redirect to /search in the root of your application, not to /api/search.
It should work, if you use DefaultRedirectPath = "/api/search".
However, when ServiceStack isn't at the root of the website, it will use MetadataRedirectPath first, and only if that is null or empty, DefaultRedirectPath. So you'll need to set MetadataRedirectPath to null, if this is what you want.
As for your test with CatchAllHandlers, as far as I can tell, CatchAllHandlers will actually cause your DefaultRedirect to not be used - the CatchAllHandler will be used as a handler, and the DefaultRedirectHandler that does the DefaultRedirectPath redirect won't ever come into play.
That will take care of redirecting from "/api" to "/api/search".
MVC is in control of your root url - the "api" addition to web.config and AppHost.Config does exactly that - keep ServiceStack only in control of "/api", while letting MVC take care of the rest. So, with that setup, if you want a redirect from "/" to "/api/search", you'd need to do it in the MVC home controller.

Related

URLs with several path components get sent directly to static file handler

I have the following problem with an Asp.net MVC application when running on IIS (tested with version 7.0 and 8.5) : if the path in the URL has no more than 3 components (for example http://myhost.com/a/b/c, it gets correctly handled by the application code. But when an additional component is added in the path (http://myhost.com/a/b/c/d), it will be sent directly to the static file handler. As the path is not used for a physical file, I get a 404 (with the error page coming from the static file handler, not the custon 404 page configured in web.config)
I don't have this problem on my dev station running IIS Express.
I use runAllManagedModulesForAllRequests="true" in web.config, disabling it doesn't solve the issue.
Disabling the static file handler doesn't help, I still get a 404 but this time the error message says "Handler Not yet determined".
I really looks this is something happening very early in IIS processing, because if I recycle the application pool and try to access to this URL, the response comes immediately, without the usual delay that I get when the application needs to start.
What am I missing? Why is IIS not forwarding such requests to my application?
It's your routes!!
The default route in MVC only takes over controller, action & ID. You're trying to use a fourth which you haven't defined. Just add another url parameter to your route collection.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}/{another}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, another= UrlParameter.Optional }
);
Hope this helps.
I think I found something: the long url was not handled by an MVC route, but by an OWIN middleware. Somehow, it seems that for IIS, if no route is configured for an URL, then the request pipeline is completely ignored, including any OWIN middlewares (and also custom page for 404).
By adding another parameter in a route like suggested by heymega, I was able to work around the problem, the OWIN middlewares were executed. I added the following route:
routes.MapRoute("CatchLongUrls", "{a}/{b}/{c}/{*d}",
new {controller = "Invalid", action = "Nothing"});

Prevent static file handler from intercepting filename-like URL

In my web application I have a route which looks like this:
routeCollection.MapRoute(
"AdfsMetadata", // name
"FederationMetadata/2007-06/FederationMetadata.xml", // url
new { controller = "AdfsController", action = "MetaData" }); // defaults
The idea behind this route was to work better with Microsoft AD FS server (2.0+) which looks for AD FS metadata at this point when you just specify a host name. With MVC3 all worked fine. But we upgraded the project to MVC4 recently and now the call for this URL results in a 404, the handler mentioned on the error page is StaticFile and the physical path is D:\path\to\my\project\FederationMetadata\2007-06\FederationMetadata.xml. I assume that MVC or ASP.NET "thinks" it must be a request for a static file and looks for the file, but it isn't a file. The data is generated dynamically - that's why I routed the URL to a controller action. The problem is that even the Route Debugger by Phil Haack doesn't work. It's just a 404 with no further information besides that IIS tried to access a physical file which isn't there.
Does anyone have a solution for this? I just want this URL to be routed to a controller action.
P.S.: I'm not 100% sure that the cause was the upgrade to MVC4, it was just a guess because the error occurred at about the same time as the upgrade, and the same route works in another project which is still using MVC3.
Edit:
I have a custom ControllerFactory which needs the full class name (AdfsController instead of Adfs), so the suffix Controller is correct in this case.
Add the following to the <handlers> section of the <system.webServer> node:
<add
name="AdfsMetadata"
path="/FederationMetadata/2007-06/FederationMetadata.xml"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
This instructs IIS that GET requests to the specified url should be handled by the managed pipeline and not considered as static files and served by IIS directly.
I have a custom ControllerFactory which needs the full class name
(AdfsController instead of Adfs), so the suffix Controller is correct
in this case.
Double check this please. Try with and without the Controller suffix in the route definition.
IIS by default is serving that file as static withouth going into ASP pipeline, can you change the route to not have a .xml extension (which is not necessary at least you have a specific requirement about that)
You can specifiy the route like this:
routeCollection.MapRoute(
"AdfsMetadata", // name
"FederationMetadata/2007-06/FederationMetadata", // url
new { controller = "AdfsController", action = "MetaData" }); // defaults
Other solution would be to add to your web.config
<modules runAllManagedModulesForAllRequests="true">
but I recommend you to avoid this as possible since what it does is to stop IIS from serving all static files
EDIT Last try... a custom http handler for that specific path would work. This post is similar to your problem only that with images (look for "Better: Custom HttpHandlers" section)

Can I redirect www.abc.com/a b c/test.html to www.abc.com/a-b-c/test.html with MVC3

I am changing the way links show on my web site. I changed from allowing space in the URL to a new format where the URL has dashes where spaces used to be.
This effects only ONE string in the middle of the URL.
Google has indexed many of my pages with the old spaces in the URL but now they show up as 404s. Is it possible for me to put some code in place (temporary) that can redirect those URLs with spaces to the ones with dashes. I think it's a 403 redirect. A permanent redirect.
Thanks,
We wen't through the same thing recently. We ended up creating a LegacyController, which basically called into RedirectToActionPermanent or RedirectToRoutePermanent. (HTTP 301 - Moved Permanently).
Ideally, you should let IIS7 do the redirects, but we couldn't, because we needed to call our DB in order to figure out where to go.
If your redirect is as simple as you say it is (e.g no "dynamic" info in the URL), then you should use IIS.
Why don't you try to configure you routing to support both: legacy and new routes?
Basically /a b c/page and /a-b-c/page should be mapped to the same action of controller.

Rails 404 handler for non-Rails URLs

I've inherited a site with hundreds of scattered HTML and non-framework PHP files, which I am porting to Ruby on Rails 3.0.
As functionality is added in the Rails app, the corresponding pages are deleted from the document root; but, because there are often links to these in Google or from external sites, simply returning a 404 is not acceptable.
A URL like '/contact.php' should redirect to '/app/contact/', for example.
For the first few cases of this, I created simple stub html files at the old locations, with Meta tags within to perform the redirect. This doesn't scale well, particularly once I start replacing product pages, of which there are thousands.
My preference is to delete the old pages, then have the 404 handler dispatch these to the new Rails app, which will examine the URL using regexes and database lookup to try to figure out what the replacement page is, then issue a 301 redirect to that new page.
In httpd.conf, I placed the directive:
ErrorDocument 404 /app/error/handle404
# /app/error is a rails url.
When I hit "http://localhost/does-not-exist", this causes my ErrorController to be invoked, as expected.
However, within the controller, I cannot find the original path ("/does-not-exist") anywhere in request, request.headers, or ENV - I've been calling likely methods like request.request_uri (which contains /app/error/handle404), and examining request.headers and ENV without finding the expected original path.
The Apache access_log shows only the request for /does-not-exist, indicating that it transparently invoked /app/error/handle404 (without doing a redirect or causing a second request to be made).
How can I get access to the original URL?
Edit: to clarify, here is the sequence of events:
User hits legacy path like http://mysite/foo.php, probably coming from some ancient link from a blog.
...but foo.php no longer exists!
this is a 404, thus Apache invokes ErrorDocument
directive is "ErrorDocument 404 /railsapp/error/handle404"
Rails routes this to ErrorController action "handle404" - this is working correctly
problem: in ErrorController, request.request.uri, request.headers do not provide any clue as to which URL the user was actually trying to get to, like "/foo.php"; I need to know the original URL to serve up an appropriate replacement page.
As I couldn't find the original, non-rewritten URL in the Rails request, I ended up doing it in PHP - plain, old-fashioned, non-framework PHP with explicit mysqli_*() calls.
The PHP error handler receives the necessary information in the $_SERVER hash; $_SERVER['REQUEST_URI'] contains the original URI that I needed.
I look this up in a database, and if I find a corresponding entry, issue a 301 redirect to the new location; if there's no entry, I simply display a 404 page to the user.
Simplified (PHP):
$url = $_SERVER['REQUEST_URI'];
$redir = lookupRedirect($url); # database stuff here
if (! $redir) {
include ('404.phtml');
} else {
header("Status: 301");
header("Location: " . $redir['new_url']);
}
It's an ugly kluge, but I just couldn't find a way to make the Rails app aware of the error URL.

HttpContext returning only "/"

I have the following two lines of codes in my model, however, both virtual and path have values "\". Where have I gone wrong?
var virtual = VirtualPathUtility.ToAbsolute(HttpContext.Current.Request.ApplicationPath);
var path =HttpContext.Current.Request.ApplicationPath;
From MSDN:
Gets the ASP.NET application's virtual application root path on the server.
So this is the part of the URL's path that is the root of the IIS Web Application the code is running in. The root URL ("http://domain/") is always an IIS Application, so will give "/" as its ApplicationPath.
You perhaps need to convert some child (virtual) folder into an IIS Application to see a longer path result.
Updated from comment:
I want to have the part ":/..."
This information is all available within the properties of Request.Uri. In particular "http" is Uri.Scheme, severname is Uri.Host and the port is Uri.Port (but check Uri.IsDefaultPort to check if you need to specify it).
http://weblogs.asp.net/srkirkland/archive/2009/09/17/a-urlhelper-extension-for-creating-absolute-action-paths-in-asp-net-mvc.aspx

Resources