web-dev-qa-db-fra.com

HTTP PUT non autorisé dans l'API Web ASP.NET

Sur mon projet d'API Web, je ne peux pas effectuer de HTTP PUT sur mes ressources. J'ai lu certainssimilairesquestionssurceciproblème et j'ai suivi les conseils recommandés.

Tout d'abord, j'ai complètement désinstallé WebDAV sur mon ordinateur (Windows 7 64 bits), puis j'ai redémarré mon ordinateur.

Deuxièmement, les gestionnaires WebDAV ont été spécifiés comme étant supprimés dans mon web.config et le verbe HTTP PUT a été spécifié comme étant autorisé pour le gestionnaire d'URL sans extension.

<modules runAllManagedModulesForAllRequests="false">
  <remove name="WebDAVModule"/>
</modules>

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="WebDAV"/>
  <add name="ExtensionlessUrlHandler-Integrated-4.0"
       path="*."
       verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
       type="System.Web.Handlers.TransferRequestHandler"
       resourceType="Unspecified"
       requireAccess="Script"
       preCondition="integratedMode,runtimeVersionv4.0" />
  <add name="AttributeRouting" path="routes.axd" verb="*" type="AttributeRouting.Web.Logging.LogRoutesHandler, AttributeRouting.Web" />
</handlers>

J'ai même essayé d'ajouter le gestionnaire d'URL ISAPI Extensionless (32 bits et 64 bits) et de changer mon application du pool d'applications de pipeline intégré au pool d'applications classique.

<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"
      path="*."
      verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
      modules="IsapiModule"
      scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
      preCondition="classicMode,runtimeVersionv4.0,bitness32"
      responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
      path="*."
      verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
      modules="IsapiModule"
      scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
      preCondition="classicMode,runtimeVersionv4.0,bitness64"
      responseBufferLimit="0" />

J'utilise actuellement Thinktecture IdentityModel pour activer la prise en charge du partage de ressources d'origine croisée (CORS). Pour ma santé mentale, je suis allé avec l'option nucléaire de tout permettre pour s'assurer que le HTTP PUT est réellement autorisé.

config.RegisterGlobal(httpConfig);

config.ForAllResources()
      .ForAllOrigins()
      .AllowAllMethods()
      .AllowAllRequestHeaders();

Le package Attribute Routing NuGet est configuré pour récupérer toutes les routes de l'assembly actuel et tous les sous-types de ApiController.

config.AddRoutesFromAssembly(Assembly.GetExecutingAssembly());
config.AddRoutesFromControllersOfType<ApiController>();

Ma ressource a également l'attribut PUT correctement spécifié.

[PUT("/API/Authenticate/Link/{key}/{identifier}")]
public Boolean LinkUser(Guid key, String identifier) { ... }

Toutes les ressources consultées à ce sujet recommandent exactement la même chose: désinstaller WebDAV, désactiver les gestionnaires WebDAV et s’assurer que le gestionnaire d’URL Extensionless est correctement configuré. J'ai fait tout ça et ça encore ne fonctionne pas. 

En tant que violoniste, je reçois ce qui suit:

PUT https://localhost/Test/API/Authenticate/Link/Foo/Bar

{"Message":"The requested resource does not support http method 'PUT'."}

Qu'est-ce que je fais mal?

25
Mike Bailey

Apparemment, il existe un problème connu dans AttributeRouting dans lequel les méthodes HttpPut sont actuellement non fonctionnelles dans l’API Web ASP.NET.

La solution de contournement actuellement acceptée consiste à ajouter le verbe approprié sur l'itinéraire jusqu'à ce qu'un correctif correct apparaisse:

La Web API RC scellait une interface vitale pour la détection de route par le cadre sous-jacent. Bien que l'interface soit maintenant publique, le changement ne sera pas publié avant vNext. Alors voici quelques solutions de contournement:

  • Utilisez les attributs AR en combinaison avec les attributs HttpGet, HttpPost, HttpPut ou HttpDelete de System.Web.Http:
[GET("some/url"), HttpGet]
public string Method1() {}

[PUT("some/url"), HttpPut]
public string Method2() {}

[POST("some/url"), HttpPost]
public string Method3() {}

[DELETE("some/url"), HttpDelete]
public string Method4() {}
19
Mike Bailey

Vérifiez que vous utilisez [HttpPut] from System.Web.Http .

Dans certaines circonstances, vous pouvez utiliser l'attribut de System.Web.Mvc.

Cela a abouti à 405s pour nous.

12
Nick Josevski

J'ai eu la même erreur, et l'a tracé vers un itinéraire personnalisé que j'avais défini comme suit:

config.Routes.MapHttpRoute(
    name: "SomeCall",
    routeTemplate: "api/somecall/{id}",
    defaults: new { controller = "SomeCall", action = "Get" }
);

Le problème ici est leaction = "Get"qui a empêché l'action PUT du même URI de répondre. Supprimer l'action par défaut a résolu le problème.

4
Andrew

Ce qui a fonctionné pour moi a été d'ajouter un attribut de route, car j'en avais déjà un défini pour une demande GET surchargée comme ci-dessous:

    // GET api/Transactions/5
    [Route("api/Transactions/{id:int}")]
    public Transaction Get(int id)
    {
        return _transactionRepository.GetById(id);
    }

    [Route("api/Transactions/{code}")]
    public Transaction Get(string code)
    {
        try
        {
            return _transactionRepository.Search(p => p.Code == code).Single();
        }
        catch (Exception Ex)
        {
            System.IO.File.WriteAllText(@"C:\Users\Public\ErrorLog\Log.txt",
                Ex.Message + Ex.StackTrace + Ex.Source + Ex.InnerException.InnerException.Message);
        }

        return null;
    }

J'ai donc ajouté pour le PUT:

    // PUT api/Transactions/5
    [Route("api/Transactions/{id:int}")]
    public HttpResponseMessage Put(int id, Transaction transaction)
    {
        try
        {
            if (_transactionRepository.Save(transaction))
            {
                return Request.CreateResponse<Transaction>(HttpStatusCode.Created, transaction);
            }
        }
        catch (Exception Ex)
        {
            System.IO.File.WriteAllText(@"C:\Users\Public\ErrorLog\Log.txt",
                Ex.Message + Ex.StackTrace + Ex.Source + Ex.InnerException.InnerException.Message);
        }

        return Request.CreateResponse<Transaction>(HttpStatusCode.InternalServerError, transaction);
    }
3
Oladipo Olasemo

Pour moi, c'était parce que je n'avais pas défini le type de média dans la chaîne de contenu json pour ma demande de client http:

new StringContent (json, Encoding.UTF32, "application/json" );

Toutes sortes de comportements étranges si ce n'est pas défini.

0
ComeIn

Je pense que ce n'est plus le cas, peut-être que ce problème a été résolu maintenant. L'API Web ASP.NET MVC autorise désormais $ http.put et voici le code à tester.

AngularJS Code de script 

$scope.UpdateData = function () {
        var data = $.param({
            firstName: $scope.firstName,
            lastName: $scope.lastName,
            age: $scope.age
        });

        $http.put('/api/Default?'+ data)
        .success(function (data, status, headers) {
            $scope.ServerResponse = data;
        })
        .error(function (data, status, header, config) {
            $scope.ServerResponse =  htmlDecode("Data: " + data +
                "\n\n\n\nstatus: " + status +
                "\n\n\n\nheaders: " + header +
                "\n\n\n\nconfig: " + config);
        });
    };

Code HTML

<div ng-app="myApp" ng-controller="HttpPutController">
<h2>AngularJS Put request </h2>
<form ng-submit="UpdateData()">
    <p>First Name: <input type="text" name="firstName" ng-model="firstName" required /></p>
    <p>Last Name: <input type="text" name="lastName" ng-model="lastName" required /></p>
    <p>Age : <input type="number" name="age" ng-model="age" required /></p>
    <input type="submit" value="Submit" />
    <hr />
    {{ ServerResponse }}
</form></div>

Méthode d'action du contrôleur API Web MVC ASP.NET

 public class DefaultController : ApiController
{

    public HttpResponseMessage PutDataResponse(string firstName, string lastName, int age)
    {
        string msg =  "Updated: First name: " + firstName +
            " | Last name: " + lastName +
            " | Age: " + age;

        return Request.CreateResponse(HttpStatusCode.OK, msg);
    }
}

(Modifiez l'URL à laquelle envoyer la demande) Lorsque nous cliquons sur le bouton Soumettre, il envoie la demande HttpPut à '/ api/default' (DefaultController) où la méthode d'action PutDataResponse est déclarée. Cette méthode sera appelée et l'utilisateur obtiendra sa réponse.

Cette solution a été écrite à l'origine ici

0
Sheo Narayan