Configure ASP.NET Web API application as a Virtual

2020-07-10 05:41发布

问题:

Due to various engineering requirements, I need to develop a new ASP.NET Web API application (named as BarApp) within the same Application domain of an existing application (named as FooApp).

I would like to configure an ASP.NET Web API application (BarApp) as a virtual directory under an existing ASP.NET MVC application (FooApp) on IIS 8.5. Though many many posts talked about how to configure a virtual directory, none of them work.

Here is the configuration snippet

        <site name="FooApp" id="3" serverAutoStart="true">
            <application path="/" applicationPool="FooApp">
                <virtualDirectory path="/" physicalPath="E:\FooApp" />
                <virtualDirectory path="/Bar" physicalPath="E:\BarApp" />
            </application>
            <bindings>
                <binding protocol="https" bindingInformation="*:34566:" sslFlags="0" />
            </bindings>
        </site>

Here is the website structure:

-FooApp
|
|--Bin
|--View
|--Bar (as a virtual directory)
    |
    |--Bin
    |--View   

In the Foo App, I configured the routing: add an ingore route for all path with Bar

--RouteConfig.cs
  namespace FooApp
  {
       public class RouteConfig
       {
          public static void RegisterRoutes(RouteCollection routes)
         {
             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
             routes.IgnoreRoute("{*path}", new { path = @"Bar\/(.*)" });

             routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
             );
         }
   }
}

--WebApiConfig, keep the automatically generated one.

 namespace FooApp
 {
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
          }
     }
}

In the BarApp, the routing configure is modified as:

--RouteConfig.cs
namespace BarApp
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
               name: "Default",
               url: "Bar/{controller}/{action}/{id}",
               defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
         }
     }
}

--WebApiConfig
namespace BarApp
{
   public static class WebApiConfig
   {
       public static void Register(HttpConfiguration config)
      {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "Bar/api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
      }
   }
}

However, the above configuration does not work, and the ignore route seems not taken into effect.
Failed to access page of Bar: https://mywebsite.test.com:4433/Bar/ HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.

Failed to access Web API of Bar: https://mywebsite.test.com:4433/Bar/api/values HTTP Error 404.0 - Not Found The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

the Web API library is 2.2.1

回答1:

I think the problem with your approach is trying to host an Asp.Net application inside a Virtual Directory. Rather, you must add a child Application:

Then modify the web.config of the root application to avoid configuration collisions:

Reference: Disable inheritance in child applications and validateIntegratedModeConfiguration and inheritInChildApplications clash.

This way, you will be able to access your child web api without modifying any c# code:



回答2:

I haven't setup virtual application using configuration files (only through IIS and publish) but I believe the issue you are having is the understanding of how the route URL is mapped in a virtual application. For the following, let's assume your FooApp has a DNS set to fooapp (http://fooapp/).

If you have a Bar virtual application under fooapp, the root of the Bar website will be http://fooapp/Bar. If we look at your route definitions (MVC and WebApi):

// MVC Route
routes.MapRoute(
    name: "Default",
    url: "Bar/{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

// WebApi Route
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "Bar/api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Both your routes are set to listen to a Bar "directory" under the running application. If your WebApi application we published on its own (let's say on localhost), this would be http://localhost/Bar. But you are actually under http://fooapp/Bar and it will be capturing the request based on that root path which would be http://fooapp/Bar/Bar (so http://fooapp/Bar/Bar/api/values, etc..).

As far as ignore routes goes, if there is no controller handling a route on /Bar in the FooApp, the application will tell IIS that it doesn't know how to treat the request and IIS will then move to other Handlers (static file handlers, and so on). Let's take your request as an example (https://mywebsite.test.com:4433/Bar/). Since it's under a virtual application, it will ask the Bar application if it can handle a / route. Since your route definitions in the Bar application only handles /Bar/{tokens}, it will default to the static file handler (which in this case would be the directory browsing) and return a 403 due to configuration.

If you take your second example (https://mywebsite.test.com:4433/Bar/api/values), it will ask the Bar application if it can handle /api/values which it can't (remember, it can handle /Bar/api/values, not /api/values). Since your application can't, it will go back to the other handlers and nobody will be able to fulfill the request and return a 404.



回答3:

I had the same problem. solution is simple: in both MVC RouteConfiguration you need the routes to the child virtual application (here if you have bar under foo, foo needs to know the bar-routes).

For bar app you need the routes documented by Simon!

Kind regards

Tara