web-dev-qa-db-fra.com

Toutes les demandes à l'API Web ASP.NET renvoient une erreur 404

J'ai un site Web ASP.NET MVC 4 qui inclut l'API Web. Le site est développé et testé avec Visual Studio 2012 et .NET 4.5 sur Windows 8 avec IIS Express comme serveur Web. Dans cet environnement de développement, tout fonctionne.

Il est maintenant déployé sur un serveur Windows 2008 R2 (SP1) avec IIS 7.5. .NET 4.0 et 4.5 sont installés. Le pool d'applications s'exécute avec .NET 4.0 en mode pipeline intégré.

Dans cet environnement de production, le site Web MVC fonctionne, l'API Web ne fonctionne pas. Pour chaque demande, peu importe si GET ou POST j'obtiens un Erreur 404. Si je saisis simplement une URL d'API Web dans le navigateur (IE 9 ouvert localement sur le serveur) pour exécuter une demande GET, j'obtiens une page 404. Si j'émets une demande POST à partir d'une application cliente API Web, j'obtiens également un 404 et le message:

Aucune ressource HTTP correspondant à l'URI de la demande n'a été trouvée.

J'ai également créé un site Web de test avec MVC 4 et API Web et je l'ai déployé sur le même serveur et l'API Web fonctionne. API Web et MVC les assemblys ont le même numéro de version dans les deux projets.

De plus, j'ai ajouté le Web API Route Debugger à l'application. Si j'utilise un itinéraire valide comme http://myserver/api/order/12 J'obtiens le résultat suivant:

Route Debugger

Pour moi, cela signifie que le modèle d'itinéraire correct Api/{Controller}/{Id} A été trouvé et correctement analysé dans un contrôleur Order et Id=12. Le contrôleur (dérivé de ApiController) existe dans l'assembly Web où se trouvent également tous les contrôleurs MVC.

Cependant, je ne sais pas ce que le statut 000 Pourrait signifier et pourquoi il n'y a pas de section "Sélection d'itinéraire" affichée (ce qui est normalement le cas même si l'assembly ne contient pas un seul ApiController, voir les captures d'écran sur la page liée ci-dessus). D'une manière ou d'une autre, il semble qu'aucun ApiController ne soit trouvé ou même non recherché ou la recherche échoue silencieusement.

Les fichiers journaux IIS ne montrent rien d'utile. La modification de divers paramètres du pool d'applications et l'utilisation du même pool d'applications pour le test et l'application réelle n'ont pas aidé.

Je suis actuellement en train de supprimer des "fonctionnalités", des paramètres de configuration, des assemblages tiers, etc. de l'application pour la ramener à la petite taille de l'application de test à la fin et en espérant qu'à un moment donné, cela commence à fonctionner.

Quelqu'un a-t-il une idée de ce que pourrait être le problème? De plus, toute idée de débogage ou de journalisation pour éventuellement trouver la raison est la bienvenue.

Modifier

Grâce à la pointe de Darrel Miller dans les commentaires ci-dessous, j'ai intégré Tracing for ASP.NET Web Api .

Pour l'URL de demande (GET) http://myserver/api/order/12, J'obtiens ce qui suit:

  • En environnement de développement, réussi (en abrégé):

Message: http://localhost:50020/api/order/12; Catégorie: System.Web.Http.Request

Sélection et instanciation du contrôleur ...

Opérateur: DefaultHttpControllerSelector; Opération: SelectController; Message: Route = "controller: order, id: 12"; Catégorie: System.Web.Http.Controllers

Opérateur: DefaultHttpControllerSelector; Opération: SelectController; Message: Commande; Catégorie: System.Web.Http.Controllers

Opérateur: HttpControllerDescriptor; Opération: CreateController; Message: ; Catégorie: System.Web.Http.Controllers

Opérateur: DefaultHttpControllerActivator; Opération: Créer; Message: ; Catégorie: System.Web.Http.Controllers

Opérateur: DefaultHttpControllerActivator; Opération: Créer; Message: MyApplication.ApiControllers.OrderController; Catégorie: System.Web.Http.Controllers

La sélection des actions, la liaison des paramètres et l'invocation des actions suivent ...

Négociation de contenu et formatage pour le résultat ...

Opérateur: DefaultContentNegotiator; Opération: Négocier; Message: Typ = "String" ... plus

Élimination du contrôleur ...

Opérateur: OrderController; Opération: Éliminer; Message: ; Catégorie: System.Web.Http.Controllers

  • En environnement de production, échec (en abrégé):

Message: http://myserver/api/order/12; Catégorie: System.Web.Http.Request

Opérateur: DefaultHttpControllerSelector; Opération: SelectController; Message: Route = "controller: order, id: 12"; Catégorie: System.Web.Http.Controllers

La partie entière de l'activation du contrôleur, de la sélection des actions, de la liaison des paramètres, de l'invocation des actions est manquante et il suit immédiatement la négociation du contenu et le formatage du message d'erreur :

Opérateur: DefaultContentNegotiator; Opération: Négocier; Message: Tapez = "HttpError" ... plus

29
Slauma

Grâce à Kiran Challa commentaire et code source de cette réponse j'ai pu comprendre qu'un assemblage (le ReportViewer 11 Assembly pour SQL Server Reporting Services) était manquant sur le serveur de production.

Bien qu'aucun ApiController ne se trouve dans cet assembly, il semble que les contrôleurs des assemblys - dans ce cas, l'assembly de mon projet Web - qui font référence à l'assembly manquant ne soient pas trouvés.

Apparemment, ce comportement est lié à ce morceau de code de la source DefaultHttpControllerTypeResolver de l'API Web:

List<Type> result = new List<Type>();

// Go through all assemblies referenced by the application
// and search for types matching a predicate
ICollection<Assembly> assemblies = assembliesResolver.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
    Type[] exportedTypes = null;
    if (Assembly == null || Assembly.IsDynamic)
    {
        // can't call GetExportedTypes on a dynamic Assembly
        continue;
    }

    try
    {
        exportedTypes = Assembly.GetExportedTypes();
    }
    catch (ReflectionTypeLoadException ex)
    {
        exportedTypes = ex.Types;
    }
    catch
    {
        // We deliberately ignore all exceptions when building the cache. If 
        // a controller type is not found then we will respond later with a 404.
        // However, until then we don't know whether an exception at all will
        // have an impact on finding a controller.
        continue;
    }

    if (exportedTypes != null)
    {
        result.AddRange(exportedTypes.Where(x => IsControllerTypePredicate(x)));
    }
}

Je ne sais pas si cela doit être ainsi et je ne suis pas tout à fait convaincu par le commentaire du code mais ce catch ... continue block est plutôt silencieux sur un problème possible et il m'a fallu énormément de temps et de frustration pour le trouver. Je savais même que le ReportViewer n'était pas encore installé. J'ai essayé de l'installer et des assemblys dépendants mais il a été bloqué par un autre processus en cours d'exécution sur le serveur, j'ai donc décidé de reporter l'installation jusqu'à ce que je puisse contacter l'administrateur et me concentrer sur les tests MVC et WebAPI en premier - grosse erreur! Sans l'extrait de code de débogage de Kiran, je n'avais jamais eu l'idée que l'existence d'un ReportViewer.dll pourrait avoir quelque chose à voir avec la résolution du type de contrôleur.

À mon avis, il y a place à amélioration pour le développeur moyen comme moi qui n'a pas une connaissance plus approfondie du fonctionnement interne de l'API Web.

Après avoir installé le ReportViewer.dll le problème a disparu.

Voici des questions sur le même symptôme qui pourrait avoir la même raison:

Modifier

J'ai émis une demande d'amélioration sur CodePlex:

http://aspnetwebstack.codeplex.com/workitem/1075

Édition 2 (11 août 13)

Le problème a été résolu pour WebAPI v5.0 RC. Voir le lien ci-dessus vers l'élément de travail et sa section de commentaires pour plus de détails.

23
Slauma

De grandes ressources dans cette réponse, cependant, j'obtenais un 404 pour ce qui s'est avéré être une raison assez stupide:

  1. J'ai créé un programme d'installation WiX pour mon projet d'API
  2. Installé sur un test VM (machine virtuelle)
  3. Demandé pour l'URI que l'API doit servir
  4. COUP! 404 :(

Il s'est avéré que j'avais manqué l'empaquetage et le déploiement de Global.asax à la racine du répertoire virtuel dans mon déploiement. Ajouter ceci ici au profit de goofies comme moi :)

5
Sudhanshu Mishra

J'ai eu le même problème dans un serveur distant, mais lorsque j'exécute sur un localhost fonctionne très bien.

Ma solution était:

<system.webServer>
    <modules>
        <remove name="UrlRoutingModule-4.0" />
        <add name="UrlRoutingModule-4.0" 
            type="System.Web.Routing.UrlRoutingModule" preCondition="" /> 
    </modules>
</system.webServer>

J'espère que cela fonctionne pour vous.

0
framled