Search code examples
asp.net-mvciisreverse-proxyiis-8spotfire

IIS reverse proxy configuration issues with MVC 5 app


I cannot properly configure reverse proxy in IIS 8.5 for my MVC5 application. We use 3rd party application Tibco Spotfire WebPlayer 7.0.1 to integrate into our MVC webapp. To do so we use Javascript API to open report from WebPlayer and insert it into iframe.

We have to configure reverse proxy to allow requests go to backend server with WebPlayer installed. Our main webapp located at http://mywebapp.com/ and all requests that should be rewrite looks like http://mywebapp.com/SpotfireWeb/..., backend server located at private ip http://172.29.1.7/SpotfireWeb/...

The main issue that I configured reverse proxy using ARR 3.0 and URL Rewrite Module 2.0, but it doesn't work for *.ashx, *.aspx, *.axd, *.asmx files. It looks like some handler conflicts with ARR/RewriteModule and doesn't allow to pass requests to different server

Details:

When I try to load static html file like http://mywebapp.com/SpotfireWeb/secret.html the request is been rewrote to 172.29.1.7 server and I got content of this file. But once I request something like http://mywebapp.com/SpotfireWeb/GetJavaScriptApi.ashx?Version=6.0 I got 404 error from mywebapp.com. I run Wireshark and discovered that requests to back-end server 172.29.1.7 don't go at all if requests contains *.ashx file. I installed Failed Requests Trace and found that event HANDLER_CHANGED occurred which changed ApplicationRequestRoutingHandler to System.Web.Mvc.MvcHandler Failed Requests Trace

Playing with this I removed some handlers and now Wireshark catches requests to the back-end server. I believe this approach of removing handlers is not correct. May be I configured something in wrong way? enter image description here web.config

Anyway, removing one module by one I faced issue when POST request to http://mywebapp.com/SpotfireWeb/AjaxService.asmx/InitiateOpen didn't processed and I got 404 error from my initial app. When I removed *.asmx handler I still got the same error. This is point where I get stuck right now.

Trace from IE

My rewrite rules from web.config of mywebapp.com. I configured it at website level:

        <rewrite>
        <rules>
            <rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
                <match url="SpotfireWeb/?(.*)$" />
                <action type="Rewrite" url="http://172.29.1.7/SpotfireWeb/{R:1}" logRewrittenUrl="true" />
                <serverVariables>
                    <set name="ORIGINAL_HOST" value="{HTTP_HOST}" />
                </serverVariables>
            </rule>
        </rules>
        <outboundRules>
            <clear />
            <rule name="ReverseProxyOutboundRule1" preCondition="" enabled="true">
                <match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" pattern="SpotfireWeb/?(.*)" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
                <action type="Rewrite" value="http://mywebapp.com/SpotfireWeb/{R:1}" />
            </rule>
            <rule name="ReverseProxy_Redirection" preCondition="IsRedirection" enabled="true">
                <match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" serverVariable="RESPONSE_Location" pattern="^http://[^/]+/(.*)" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                    <add input="{ORIGINAL_HOST}" pattern=".+" />
                    <add input="{URL}" pattern="^/(SpotfireWeb)/?.*" />
                </conditions>
                <action type="Rewrite" value="http://{ORIGINAL_HOST}/{C:1}/{R:1}" />
            </rule>
            <preConditions>
                <preCondition name="IsRedirection">
                    <add input="{RESPONSE_STATUS}" pattern="3\d\d" />
                </preCondition>
            </preConditions>
        </outboundRules>
    </rewrite>

Have anyone saw something similar ? I assume that root cause in MVC handler, but can't understand where.


Solution

  • I fixed this. Obviously we don't need to remove modules. The answer basically into logs of failed requests. During MAP_REQUEST_HANDLER event ASP.NET infrastructure determines the request handler for the current request. In my case MVC handler selected every time I requested URL like /SpotfireWeb/... regardless of ARR was current handler. Here I found that:

    ..the handler mapping can be changed during request execution in the MAP_REQUEST_HANDLER event. This allows scenarios such as URL rewriting to work.

    My fix was removing SpotfireWeb from MVC routes completely. Thus I added following code into RouteConfig.cs

    routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");
    

    And the whole class looks like:

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            // ignore everything under 'SpotfireWeb' because this request will be routed 
            // to separate server via reverse proxy ARR/Rewrite module
            routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { area = string.Empty, controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces: new[] { "GKSPortal.Controllers" });
        }
    }