HostConfig.DefaultRedirectPath not working v4.5.14

Upgraded to 4.5.14 (from 4.5.7) and the HostConfig().DefaultRedirectPath doesn’t seem to be working and now we’re getting “Page Not Found” on those pages.

On 4.5.7:
sub1.mywebsite.com/ would redirect to sub1.mywebsite.com/authenticated_page/ (which would redirect them to sign in if they aren’t signed in auth1.mywebsite.com).

However on 4.5.14
sub1.mywebsite.com/ goes to “page not found” error.

ServiceStack seems to possibly be ignoring the HostConfig().DefaultRedirectPath???

Is this a bug or is there a new way to set the DefaultRedirectPath?

public class AppHost : AppHostBase {
        public override void Configure(Container container)  {
            // removed unnecessary config lines...
 
            var endpointHostConfig = new HostConfig();
            endpointHostConfig.AllowFileExtensions.Add("map");
            endpointHostConfig.DefaultRedirectPath = "/authenticated_page";
            SetConfig(endpointHostConfig);
        }
}

DefaultRedirectPath is still working for me as expected, I’m assuming there must be some other config that’s interfering with the request, can you put together a small stand-alone project on GitHub that repro’s the issue.

I’ll try putting something together. The only change in our web app was the upgrade from 4.5.7 to 4.5.14 and the FIleSystemVirtualPathProvider. So something must have changed in the framework. (v4.5.14 FileSystemVirtualPathProvider)

While I’m putting together a project here is more of the AppHost. Maybe there is something in there that you’ll see right away.

public class AppHost : AppHostBase {
        public override void Configure(Container container)  {
            // removed unnecessary config lines...

            GlobalHtmlErrorHttpHandler = new RazorHandler("/500");
            CustomErrorHttpHandlers.Clear();
            CustomErrorHttpHandlers.Add(HttpStatusCode.InternalServerError, new RazorHandler("/500"));
            CustomErrorHttpHandlers.Add(HttpStatusCode.NotFound, new RazorHandler("/404"));
            CustomErrorHttpHandlers.Add(HttpStatusCode.Unauthorized, new RazorHandler("/401"));

            RawHttpHandlers.Add(httpReq =>
            {
                if (httpReq.PathInfo == "/")
                {
                    HttpContext.Current.RewritePath(Config.DefaultRedirectPath);
                }

                return null;
            });

            LoadPlugin(
                new RazorFormat
                {
                    LoadFromAssemblies = { typeof(AppHost).Assembly },
                    VirtualFileSources = new FileSystemVirtualFiles(Config.WebHostPhysicalPath)
                },
                new MyWebAppFeature());

            // ConfigureDatabase();

            var endpointHostConfig = new HostConfig();
            endpointHostConfig.AllowFileExtensions.Add("map");
            endpointHostConfig.DefaultRedirectPath = "/authenticated_page";
            SetConfig(endpointHostConfig);
        }

       public override string ResolveAbsoluteUrl(string virtualPath, IRequest httpReq)
        {
            if (virtualPath.SafeSubstring(0, 2) == "~/")
            {
                // MyDomain() = "https://{0}".Fmt(domain).WithTrailingSlash();
                return httpReq.MyDomain().CombineWith(virtualPath.Substring(2));
            }
            return virtualPath;
        }
}

It looks like from debugging that the RawHttpHandler is not executing before the LoadPlugin()? It looks like it is going directly into MyWebAppFeature() which loads a FallbackService which then HttpError.NotFound.

Did the sequence of execution change?

// AppHost.Configure(Container container) (full code in above reply)
RawHttpHandlers.Add(httpReq =>
            {
                if (httpReq.PathInfo == "/")
                {
                    HttpContext.Current.RewritePath(Config.DefaultRedirectPath);
                }

                return null;
            });

            LoadPlugin(
                new RazorFormat
                {
                    LoadFromAssemblies = { typeof(AppHost).Assembly },
                    VirtualFileSources = new FileSystemVirtualFiles(Config.WebHostPhysicalPath)
                },
                new MyWebAppFeature());

It looks like the sequence of execution changed.

In v4.5.7 the RawHttpHandlers executes before the LoadPlugin() (Which loads the FallbackService)

In v4.5.14 the LoadPlugin() which loads FallbackService executes before RawHttpHandlers which is why the redirect from root isn’t happening anymore.

Was this change of execution sequences planned? If so wish it would have waited until v5 unless there is an easy fix.

The RawHttpHandlers is still at #1 in the order of operations doc.

The App Configuration code in Configure() is executed once on Startup and is executed before any runtime requests but RawHttpHandlers are still executed first for requests at runtime.

Note the purpose of RawHttpHandler class is to return a IHttpHandler, e.g. if you want to use the RawHttpHandlers to redirect you should return a RedirectHttpHandler, e.g:

RawHttpHandlers.Add(req => req.PathInfo == "/"
 ? new RedirectHttpHandler { RelativeUrl = "/redirect/path" }
 : null);

But you shouldn’t need a RawHttpHandler in addition to setting Config.DefaultRedirectPath as ServiceStack will redirect to DefaultRedirectPath for unhandled default requests.

These ServiceStack websites that we’re having issues with have been around since version 2 or 2.5 (2012). We’ve been upgrading over the years so there is probably code that should be refactored. ServiceStack.NET is well built :slight_smile:

Original code that doesn’t work in v4.5.14:

// Code Example 1
// Note: inside AppHost.Configure(Container container)

RawHttpHandlers.Add(httpReq =>
 {
    if (httpReq.PathInfo == "/")
    {
        HttpContext.Current.RewritePath(Config.DefaultRedirectPath);
    }
    return null;
 });

mythz suggested code that does work similar Code Example 1 in v4.5.7 and v4.5.14 and executes before the FallbackService.
This is the solution we’re going with.

// Code Example 2
// Note: inside AppHost.Configure(Container container)
            
RawHttpHandlers.Add(req => req.PathInfo == "/"
     ? new RedirectHttpHandler { RelativeUrl = Config.DefaultRedirectPath } 
     : null);

It would seem then that a change was made so that code cannot use RewritePath or is ignored when used in RawHttpHandlers as Code Example 1 shows.
The following will no longer work when used in RawHttpHandlers at some point between v4.5.8 and v4.5.14.

HttpContext.Current.RewritePath(Config.DefaultRedirectPath);

However, code can still use HttpContext.Current.Response.Redirect() in RawHttpHandler, example:

// Code Example 3
// Note: inside AppHost.Configure(Container container)
            
RawHttpHandlers.Add(req =>
  {
    if (req.PathInfo == "/")
    {      
        HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.Redirect;
        HttpContext.Current.Response.Redirect(Config.DefaultRedirectPath);
    }
    return null;
  });

Thanks again Mythz for all your work and support!

Note: In v4.5.7 and v4.5.14 the DefaultRedirectPath does not work when I remove the RawHttpHandler from the AppHost.Configure(). The FallbackService still executes. But that is probably because FallbackService uses the [FallbackRoute] attribute?

1 Like

Right if the Request matches the FallbackRoute it takes precedence.