Ethan Schofer
Ethan Schofer

Reputation: 1848

WebAPI giving 404 on server

This has been asked a million times but....

I have a WebAPI. It works on my local machine running IIS. But after deploying to server, it fails.

Things I have tried:

Added

<modules runAllManagedModulesForAllRequests="true">

Set handlers to

<remove name="WebDAV" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Add json as MIME type

<staticContent>
  <mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>

Routing is mapped as

// Web API routes
        config.MapHttpAttributeRoutes();

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

Startup file:

public static void ConfigureContainer(IAppBuilder app)
    {
        var builder = new ContainerBuilder();

        var options = CreateCorsOptions();
        app.UseCors(options);

        // Get your HttpConfiguration.
        config = new HttpConfiguration();

        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        WebApiConfig.Register(config);

        RegistererWebApi(builder, config);

        // Register dependencies, then...
        var container = builder.Build();
        var webApiResolver = new AutofacWebApiDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;

        // Register the Autofac middleware FIRST. This also adds
        // Autofac-injected middleware registered with the container.
        app.UseAutofacMiddleware(container);
        app.UseAutofacWebApi(config);
        app.UseWebApi(config);

    }

private static void RegistererWebApi(ContainerBuilder builder, HttpConfiguration config)
    {
        // Register your Web API controllers.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // OPTIONAL: Register the Autofac filter provider.
        //builder.RegisterWebApiFilterProvider(config);
    }

UPDATE

Here is my full WebApiConfig:

public static class WebApiConfig
{
    /// <summary>
    /// Register the WebAPI. Remove Xml formatter (OPnly using JSON). Add filters. Set Routing
    /// </summary>
    /// <param name="config"></param>
    public static void Register(HttpConfiguration config)
    {
        //Enable cross origin requests
        var cors = new EnableCorsAttribute("http://local.isos.com,htt://dev.isos.mydelphic.com,http://qa.isos.mydelphic.com,http://localhost/", headers: "*", methods: "*");
        config.EnableCors(cors);

        // Web API configuration and services
        // Remove the XML formatter
        config.Formatters.Remove(config.Formatters.XmlFormatter);

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;

        config.Filters.Add(new UnhandledExceptionFilter());

        config.MessageHandlers.Add(new CacheCow.Server.CachingHandler(config));

        // Web API routes
        config.MapHttpAttributeRoutes();

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


    }

UPDATE2

Here is how I register my controllers with Autofac

private static void RegistererWebApi(ContainerBuilder builder, HttpConfiguration config)
    {
        // Register your Web API controllers.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());            
    }

And here is my controller:

[RoutePrefix("providers")]
public class ProviderController : BaseApiController
{
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="requestDispatcher">Dispatcher gets injected by Ioc</param>
    public ProviderController(IRequestDispatcher requestDispatcher)
        : base(requestDispatcher)
    { }

    /// <summary>
    /// Get a list of all providers outside the Philipines
    /// </summary>
    /// <returns>Returns an action result regarding the state of the request. Returns a 200 containing the list of providers. Returns a 404 is no results are found.</returns>
    [Route("",Name="Providers")]
    public async Task<IHttpActionResult> Get(string sort = "ProviderName", int page = 1, int pageSize = 10)
    {
        var query = new GetProviders();
        // Populate the view model by calling the appropriate handler
        var providers = await RequestDispatcher.DispatchAsync<GetProviders, ProvidersResponse>(query);
        if (providers == null)
        {
            return NotFound();
        }

        var totalCount = providers.Count;
        var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

        var urlHelper = new UrlHelper(Request);

        //Route name
        var prevLink = page > 1 ? urlHelper.Link("Providers",
        new
        {
            page = page - 1,
            pageSize = pageSize,
            sort = sort
        }) : "";

        var nextLink = page < totalPages ? urlHelper.Link("Providers",
        new
        {
            page = page + 1,
            pageSize = pageSize,
            sort = sort
        }) : "";


        var paginationHeader = new
        {
            currentPage = page,
            pageSize = pageSize,
            totalCount = totalCount,
            totalPages = totalPages,
            previousPageLink = prevLink,
            nextPageLink = nextLink
        };

        HttpContext.Current.Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));

        return Ok(providers);
    }
}

Upvotes: 1

Views: 871

Answers (2)

Ethan Schofer
Ethan Schofer

Reputation: 1848

It was a configuration setting. On the server, which is an older server, although still running IIS7, you need to explicitly tell IIS to look for an OWIN start up class:

<appSettings>  
  <add key="owin:appStartup"          vaue="yourproject.startup" />       
</appSettings>

Upvotes: 0

Travis Illig
Travis Illig

Reputation: 23934

It appears you're using OWIN, not the older-style singleton GlobalConfiguration... yet you're setting the dependency resolver on GlobalConfiguration.

One of the common errors when using OWIN is to try to set the GlobalConfiguration dependency resolver.

Try setting config.DependencyResolver instead. Check the docs for example/explanation.

Upvotes: 1

Related Questions