2013-01-14 11 views
25

Nel mio progetto API Web, non è possibile eseguire uno HTTP PUT alle risorse. Ho letto il numero somesimilarquestionsonthisproblem e ho seguito il consiglio consigliato.HTTP PUT non consentito nell'API Web ASP.NET

Prima di tutto, ho disinstallato WebDAV completamente sulla mia macchina (Windows 7 64-bit) e successivamente ho riavviato la mia macchina.

In secondo luogo, i gestori WebDAV sono stati specificati come rimossi nel mio web.config e il verbo HTTP PUT è stato specificato come consentito per il gestore di URL senza estensioni.

<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> 

Ho anche provato ad aggiungere l'ISAPI senza estensione URL Handler (32-bit e 64-bit) e cambiare la mia applicazione dalla pipeline integrata App Pool al classico App Pool.

<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" /> 

Attualmente sto usando Thinktecture IdentityModel per abilitare il supporto Croce Origin Resource Sharing (CORS). Per la mia sanità mentale, sono andato con l'opzione nucleare di abilitare tutto per assicurarmi che il HTTP PUT sia effettivamente permesso.

config.RegisterGlobal(httpConfig); 

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

Il Attribute Routing pacchetto NuGet è configurato per raccogliere tutte le rotte per il gruppo corrente ed eventuali sottotipi di ApiController.

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

La mia risorsa ha anche l'attributo PUT specificato correttamente.

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

Ogni risorsa Guardo in materia raccomanda la stessa cosa esatta: disinstallazione WebDAV, disabilitando i gestori WebDAV e fare in modo che il gestore senza estensione URL sia configurato correttamente. Ho fatto tutto questo ed è ancora non funziona.

In violinista, sto ottenendo il seguente:

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

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

Che cosa sto facendo di sbagliato?

+0

Questo attributo deve essere '[HttpPut]'? –

+0

@dtryon: No. È da "AttributeRouting". Dovrebbe essere '[PUT (...)]'. –

+0

Ho avuto questo problema - è stato perché l'azione del mio controller non è stata configurata correttamente - si aspettava un parametro che non includevo. – niico

risposta

19

Apparentemente, c'è un problema noto all'interno AttributeRouting cui i metodi HttpPut sono attualmente non funzionali in ASP.NET Web API.

Il currently accepted workaround è aggiungere il verbo appropriato sul percorso fino ad una correzione adeguata arriva:

Web API RC sigillato un'interfaccia vitale per il rilevamento percorso dal quadro sottostante . Sebbene l'interfaccia sia ora pubblica, la modifica non verrà rilasciata fino a vNext. Così qui sono alcune soluzioni: attributi

  • Usa AR in combinazione con HttpGet, HttpPost, HttpPut o HttpDelete attributi da 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() {} 
+0

stavo proprio scrivendo questo, +1 –

+0

@FilipW: Mi ci è voluto un po 'per trovarlo. Ho inserito un commento sul collegamento nella mia risposta chiedendo se sarebbe possibile documentarlo meglio nel codice (ad esempio "ObsoleteException"). Questo è un bug piuttosto confuso considerando che ci sono già due problemi noti che non hanno alcun rapporto con lo stesso problema. –

4

Ho avuto lo stesso errore e risalire a un percorso personalizzato che avevo definito in questo modo:

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

Il problema qui è la action = "Get" che impedito l'azione PUT dello stesso URI per rispondere. La rimozione dell'azione predefinita ha risolto il problema.

+0

Grazie a @MikeBantegui. Nella ricerca del problema, la tua domanda è stata la corrispondenza più completa e più vicina alla mia configurazione, tranne l'attributo di instradamento, quindi ho pensato di mettere la mia soluzione nel caso in cui aiuti qualcun altro – Andrew

+0

abbastanza giusto. Hai idea del motivo per cui l'azione predefinita stava impedendo l'azione "PUT"? Sembra che potrebbe essere un bug. –

+0

Mi chiedevo se potesse essere un bug anche - non si può davvero chiamarlo 'default' se il metodo di richiesta reale non può superarlo! Anche se ammetto che non ho esaminato il motivo per cui – Andrew

11

Doppio controllo che si sta utilizzando [HttpPut] da System.Web.Http.

In alcune circostanze è possibile utilizzare l'attributo di System.Web.Mvc.

Il risultato sono stati 405 per noi.

+1

ha fatto il trucco, grazie! – Rob

+1

Resharper cattivo, cattivo. – DontVoteMeDown

+0

potresti darmi qualche altro dettaglio? –

3

Quello che ha funzionato per me è stato quello di aggiungere un attributo percorso, come ho già avuto uno definita per una richiesta GET che è stato sovraccaricato, come di seguito:

// 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; 
    } 

Così ho aggiunto per il 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); 
    } 
+1

Aggiunta di/{id: int} l'ha fatto. grazie – Sameer

+0

Sei il benvenuto –

0

Penso che questo non sia più il caso, forse questo problema è stato risolto ora. L'API Web MVC di ASP.NET ora consente $ http.put e qui è il codice da testare. Codice

AngularJS 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); 
     }); 
    }; 

codice 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> 

ASP.NET MVC metodo di azione di controllo Web API

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); 
    } 
} 

(Cambia l'url per inviare la richiesta a) Quando clicchiamo sul pulsante Invia, invia la richiesta HttpPut a '/ api/default' (DefaultController) dove viene dichiarato il metodo di azione PutDataResponse. Questo metodo verrà chiamato e l'utente riceverà la sua risposta.

Questa soluzione è stato originariamente scritto here

0

Per me è stato perché non avevo impostare il tipo di supporto nella stringa di contenuto JSON per la mia richiesta di un client http:

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

Tutti i tipi di comportamento strano se questo non è impostato.

Problemi correlati