1

I have a solution with an MVC project and also a separate Web Api project. I have been working on the the MVC portion and have had it hosted as a web role in a cloud service project.

Now I need to build on the Web Api. Running the solution as is in the azure emulator I'm unable to hit my Web Api controller, I get a 404 Not Found.

What steps do I need to take after creating the WebApi project in the solution in order to enable my MVC project alongside it to hit the Api controller using a jQuery ajax call (from the MVC project)?

Note: The portion of the application that will be consuming the Api is in a subdomain (ex "consumingapp.myapplication.com/api/Values". I don't know if that makes any difference.

j0k
  • 22,600
  • 28
  • 79
  • 90
parliament
  • 21,544
  • 38
  • 148
  • 238
  • Your question is very similar to another that I answered [here](http://stackoverflow.com/questions/12905566/web-api-in-mvc-solution-in-separate-project/12907799#12907799). I think my answer and perhaps others in that question should help you. – David Peden Mar 27 '13 at 06:35

1 Answers1

0

Ok here are the steps to run MVC and WebApi side by side in Azure under a single web role:

  1. Add only the MVC project as a Web Role in the Cloud Service project.
  2. Open ServiceDefinition.csdef an configure as follows:

    <Sites>
       <Site name="Web" physicalDirectory="..\..\..\Application.Web">
          <Bindings>
             <Binding name="Endpoint1" endpointName="Endpoint1" />
          </Bindings>
       </Site>
       <Site name="Web.Api" physicalDirectory="..\..\..\Application.Web.Api">
          <Bindings>
             <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="api.myapplication.com"/>
          </Bindings>
       </Site>      
    </Sites>
    

    Note: The physical directory is relative to the definition file that is deployed to CloudProject\bin\release so you need to back track 3 nodes to get to the solution folder. Also I had some trouble with this trying to run the project it would automatically switch the physicalDirectory back to a bad path. To fix that I right clicked the cloud project > Project Dependencies > make sure both projects are checked off. Also make sure to save and close all instances of the text editor for the definition file then Rebuild and finally Run. Seems like some kind of bug that was driving me nuts and eventually disappeared.

  3. Configure your host files to allow for local testing using the emulator:

    127.0.0.1 myapplication.com api.myapplication.com

  4. To use this .NET cors implementation run the following Nuget command on your WebApi project:

    Install-Package Thinktecture.IdentityModel

  5. Add the following class (taken from the post) to your WebApi project:

    public static class CorsConfig
    {
        public static void RegisterCors(HttpConfiguration httpConfiguration)
        {
            WebApiCorsConfiguration corsConfig = new WebApiCorsConfiguration();
            corsConfig.RegisterGlobal(httpConfiguration);
    
            corsConfig
                .ForResources("Values") //Controller nae
                .ForOrigins("http://myapplication.com", "myapplication.com:81")
                .AllowAll();
        }
    }
    
  6. Call RegisterCors() from Application_Start()

  7. Make sure you Web.config in the WebApi project has OPTIONS verb for the ExtensionlessUrlHandler:

      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    
  8. Make cross-origin request to hit your api controller:

    $.ajax({ url: "http://api.myapplication.com/api/Values", ... })
    

And Viola!

Hope that helps others

parliament
  • 21,544
  • 38
  • 148
  • 238
  • 1
    This is a good write-up and very similar to what I did. The big thing that you are missing is that you really should be building/publishing the secondary sites rather than relying on the default file copy. This gets you a proper package (only the files you need) and enables config transforms (critical). See http://kellyhpdx.wordpress.com/2012/04/11/deploying-multiple-web-applications-to-a-single-azure-instance-and-applying-web-config-transforms-correctly/ for reference. – David Peden Mar 27 '13 at 17:03
  • Yes you're right without those extra configurations I probably would have ran into problems during deployment. Thanks for getting back with that link. – parliament Mar 27 '13 at 20:01
  • The only thing I want to be sure of before I change my working configurations above: Does that setup still require CORS? Seems like both projects are deployed to the same domain and there is no hostHeader configurations being done so will this actually work to access my API using $.ajax({ url: "/api/Values", .. }) ? – parliament Mar 27 '13 at 20:07
  • 1
    CORS is required if you intend to make calls from myapplication.com to api.myapplication.com. Those are not the same domains. If the calls were to myapplication.com/api, then you would not need CORS. – David Peden Mar 27 '13 at 22:14
  • Right, so am I correct to assume that the setup you linked to deploys both projects to the same domain? Thanks again – parliament Mar 28 '13 at 04:51
  • 1
    No. Your route maps determine how your apps are exposed. – David Peden Mar 28 '13 at 06:05
  • Still doesn't fully make sense to me in this context. In my write up above I use the DefaultApi route (not shown) which does not register any subdomain routes, the host header in my ServicDefinition seems to take care of making sure the routes hit my api controller if they have "api" subdomain. In the linked article there is no host header and no subdomain routes. Seems like I would be able to use myapplication.com/SomePage for MVC controllers and myapplication.com/api/Values for Api Controllers. (assuming there's never any route conflicts), with both in the same domain – parliament Mar 28 '13 at 19:58
  • 1
    Correct, with the default routes, your API will be surfaced via /api and you do not need CORS. If you prefer to have your API exposed as api.*, you'll need CORS. Security/authentication requirements will likely drive that decision. – David Peden Mar 28 '13 at 22:13