141 votes

La requête Put de l'API Web génère une erreur Http 405 Method Not Allowed (méthode non autorisée)

Voici l'appel au PUT sur mon API Web - la troisième ligne de la méthode (j'appelle l'API Web depuis un frontal ASP.NET MVC) :

enter image description here

client.BaseAddress es http://localhost/CallCOPAPI/ .

Voici contactUri :

enter image description here

Voici contactUri.PathAndQuery :

enter image description here

Et enfin, voici ma réponse sur les 405 :

enter image description here

Voici le WebApi.config de mon projet d'API Web :

        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Routes.MapHttpRoute(
                name: "DefaultApiGet",
                routeTemplate: "api/{controller}/{action}/{regionId}",
                defaults: new { action = "Get" },
                constraints: new { httpMethod = new HttpMethodConstraint("GET") });

            var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            config.Formatters.Remove(config.Formatters.XmlFormatter);

J'ai essayé de supprimer le chemin d'accès qui est passé dans le fichier PutAsJsonAsync a string.Format("/api/department/{0}", department.Id) y string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id) sans succès.

Quelqu'un a-t-il une idée de la raison pour laquelle j'obtiens l'erreur 405 ?

UPDATE

Comme demandé, voici mon code de contrôleur de département (je posterai à la fois le code du contrôleur de département pour mon projet frontal, ainsi que le code de l'ApiController de département pour la WebAPI) :

Contrôleur du département Front End

namespace CallCOP.Controllers
{
    public class DepartmentController : Controller
    {
        HttpClient client = new HttpClient();
        HttpResponseMessage response = new HttpResponseMessage();
        Uri contactUri = null;

        public DepartmentController()
        {
            // set base address of WebAPI depending on your current environment
            client.BaseAddress = new Uri(ConfigurationManager.AppSettings[string.Format("APIEnvBaseAddress-{0}", CallCOP.Helpers.ConfigHelper.COPApplEnv)]);

            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
        }

        // need to only get departments that correspond to a Contact ID.
        // GET: /Department/?regionId={0}
        public ActionResult Index(int regionId)
        {
            response = client.GetAsync(string.Format("api/department/GetDeptsByRegionId/{0}", regionId)).Result;
            if (response.IsSuccessStatusCode)
            {
                var departments = response.Content.ReadAsAsync<IEnumerable<Department>>().Result;
                return View(departments);
            }
            else
            {
                LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
                    "Cannot retrieve the list of department records due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
                return RedirectToAction("Index");
            }

        }

        //
        // GET: /Department/Create

        public ActionResult Create(int regionId)
        {
            return View();
        }

        //
        // POST: /Department/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(int regionId, Department department)
        {
            department.RegionId = regionId;
            response = client.PostAsJsonAsync("api/department", department).Result;
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Edit", "Region", new { id = regionId });
            }
            else
            {
                LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
                    "Cannot create a new department due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
                return RedirectToAction("Edit", "Region", new { id = regionId });
            }
        }

        //
        // GET: /Department/Edit/5

        public ActionResult Edit(int id = 0)
        {
            response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
            Department department = response.Content.ReadAsAsync<Department>().Result;
            if (department == null)
            {
                return HttpNotFound();
            }
            return View(department);
        }

        //
        // POST: /Department/Edit/5

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(int regionId, Department department)
        {
            response = client.GetAsync(string.Format("api/department/{0}", department.Id)).Result;
            contactUri = response.RequestMessage.RequestUri;
            response = client.PutAsJsonAsync(string.Format(contactUri.PathAndQuery), department).Result;
            if (response.IsSuccessStatusCode)
            {
                return RedirectToAction("Index", new { regionId = regionId });
            }
            else
            {
                LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
                    "Cannot edit the department record due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
                return RedirectToAction("Index", new { regionId = regionId });
            }
        }

        //
        // GET: /Department/Delete/5

        public ActionResult Delete(int id = 0)
        {
            response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
            Department department = response.Content.ReadAsAsync<Department>().Result;

            if (department == null)
            {
                return HttpNotFound();
            }
            return View(department);
        }

        //
        // POST: /Department/Delete/5

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int regionId, int id)
        {
            response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
            contactUri = response.RequestMessage.RequestUri;
            response = client.DeleteAsync(contactUri).Result;
            return RedirectToAction("Index", new { regionId = regionId });
        }
    }
}

Département API Web ApiController

namespace CallCOPAPI.Controllers
{
    public class DepartmentController : ApiController
    {
        private CallCOPEntities db = new CallCOPEntities(HelperClasses.DBHelper.GetConnectionString());

        // GET api/department
        public IEnumerable<Department> Get()
        {
            return db.Departments.AsEnumerable();
        }

        // GET api/department/5
        public Department Get(int id)
        {
            Department dept = db.Departments.Find(id);
            if (dept == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            return dept;
        }

        // this should accept a contact id and return departments related to the particular contact record
        // GET api/department/5
        public IEnumerable<Department> GetDeptsByRegionId(int regionId)
        {
            IEnumerable<Department> depts = (from i in db.Departments
                                             where i.RegionId == regionId 
                                             select i);
            return depts;
        }

        // POST api/department
        public HttpResponseMessage Post(Department department)
        {
            if (ModelState.IsValid)
            {
                db.Departments.Add(department);
                db.SaveChanges();

                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, department);
                return response;
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

        // PUT api/department/5
        public HttpResponseMessage Put(int id, Department department)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }

            if (id != department.Id)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            db.Entry(department).State = EntityState.Modified;

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }

            return Request.CreateResponse(HttpStatusCode.OK);
        }

        // DELETE api/department/5
        public HttpResponseMessage Delete(int id)
        {
            Department department = db.Departments.Find(id);
            if (department == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            db.Departments.Remove(department);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }

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

0 votes

Ne devriez-vous pas utiliser [HttpPut] avant la définition de la méthode d'action ? ( [HttpPost] y [HttpDelete] le cas échéant également)

0 votes

@ChrisPratt Juste pour être clair, vous voulez dire mettre [HttpPut] sur le contrôleur WebAPI (ApiController), n'est-ce pas ? Parce que le contrôleur frontal du département (méthode d'édition) possède une méthode [HttpPost] attribut.

1 votes

@ChrisPratt Le ValuesController (celui qui est fourni avec le modèle WebAPI) n'a pas de [HttpPut] etc. sur les méthodes Put/Post/Delete .

322voto

Mike Marks Points 2244

J'ai donc vérifié les fonctionnalités de Windows pour m'assurer que je n'avais pas installé ce truc appelé WebDAV, et il m'a dit que ce n'était pas le cas. Quoi qu'il en soit, je suis allé de l'avant et placé ce qui suit dans mon web.config (à la fois front-end et WebAPI, juste pour être sûr), et il fonctionne maintenant. J'ai placé ceci à l'intérieur <system.webServer> .

<modules runAllManagedModulesForAllRequests="true">
    <remove name="WebDAVModule"/> <!-- add this -->
</modules>

En outre, il est souvent nécessaire d'ajouter les éléments suivants à la liste de l'UE web.config dans les manipulateurs. Merci à Babak

<handlers>
    <remove name="WebDAV" />
    ...
</handlers>

2 votes

Haha... ouais... j'étais sur le point d'abandonner. Alors oui. WebDAV doit avoir été activé dans votre applicationhost.config . Content que vous l'ayez réparé.

9 votes

Il se peut que vous deviez également ajouter ceci : <handlers><remove name="WebDAV" />...

14 votes

Ajouté ce uniquement à mon web.config WebApi et cela a fonctionné.

24voto

WebDav-SchmebDav. assurez-vous que vous créez l'url avec l'ID correctement. Ne l'envoyez pas comme http://www.fluff.com/api/Fluff?id=MyID et l'envoyer comme http://www.fluff.com/api/Fluff/MyID .

Eg.

PUT http://www.fluff.com/api/Fluff/123 HTTP/1.1
Host: www.fluff.com
Content-Length: 11

{"Data":"1"}

C'était me casser les couilles pour une petite éternité, un embarras total.

3 votes

Un casse-tête supplémentaire pour moi : Les actions PUT ne peuvent pas lier les données aux paramètres de type primitif. J'ai dû modifier public int PutFluffColor(int Id, int colorCode) a public int PutFluffColor(int Id, UpdateFluffColorModel model)

4 votes

J'aimerais pouvoir voter deux fois pour le WebDav-SchmebDav.

1 votes

Après plus de 8 heures de travail pour arriver à la solution, tout le monde recommande des changements de web.config, c'est tellement étonnant que personne n'a même pas parlé de cette possibilité.

23voto

Aron Points 5989

Ajoutez ceci à votre web.config . Vous devez indiquer à IIS ce que PUT PATCH DELETE y OPTIONS moyens. Et qui IHttpHandler à invoquer.

<configuation>
    <system.webServer>
    <handlers>
    <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
    <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <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" />
    <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" />
    </handlers>
    </system.webServer>
</configuration>

Vérifiez également que vous n'avez pas activé WebDAV.

0 votes

Je l'ai déjà. Je suppose que cela doit être placé dans le projet API Web, et non dans mon projet MVC frontal, n'est-ce pas ?

0 votes

Je n'ai pas installé WebDAV. De plus, dites-vous que le code web.config ci-dessus doit être placé dans le web.config du projet qui fait l'appel à l'API Web ?

0 votes

C'est en fait dans les deux web.configs... :(

16voto

jpgrassi Points 1223

J'exécute une application ASP.NET MVC 5 sur IIS 8.5. J'ai essayé toutes les variantes proposées ici, et voici ce que j'ai obtenu. web.config ressemble :

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <remove name="WebDAVModule"/> <!-- add this -->
    </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-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" />
      <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" />
    </handlers> 
</system.webServer>

Je n'ai pas pu désinstaller WebDav de mon serveur car je n'avais pas les privilèges d'administrateur. De plus, j'obtenais parfois le message method not allowed sur les fichiers .css et .js. Finalement, avec la configuration ci-dessus mise en place, tout a recommencé à fonctionner.

5voto

L'ajout de [FromBody] à l'un des paramètres de l'action a permis de résoudre le problème :

public async Task<IHttpActionResult> SetAmountOnEntry(string id, [FromBody]int amount)

Cependant, ASP.NET le déduirait correctement si l'objet complexe était utilisé dans le paramètre de la méthode :

public async Task<IHttpActionResult> UpdateEntry(string id, MyEntry entry)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X