none
Problema multiples GET en Controlador RRS feed

  • Pregunta

  • Hola,

    Tengo un problema que me muestra el siguiente error:

    

    Tengo configurada de la siguiente manera mis rutas

    public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute(
                    name: "Default",
                    url: "{controller}/{action}/{id}",
                    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
      
            }
        }

    para el WebApi

    public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApiAction",
                    routeTemplate: "api/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                var json = config.Formatters.JsonFormatter;
                json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
                config.Formatters.Remove(config.Formatters.XmlFormatter);
    
    
              
    
            }
        }


    Y mi controlador esta de la siguiente manera:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    
    namespace Intranet2.Areas.Blog.Controllers
    {
        public class Default1Controller : ApiController
        {
            [HttpGet]
            [ActionName("Postlik")]
            public IHttpActionResult PostLikeMap()
            {
                return Ok("PostLikeMap");
            }
    
            [HttpGet]
            [ActionName("testa")]
            public IHttpActionResult TestA()
            {
                return Ok("textA");
            }
    
            [HttpGet]
            [ActionName("testb")]
            public IHttpActionResult TestB()
            {
                return Ok("textB");
            }
        }
    }
    

    Instale lo siguientes packs de Nuget


    Install-Package angularjs -Pre
    Install-Package EntityFramework
     Install-Package Microsoft.AspNet.WebApi
    Install-Package toastr
    Install-Package elmah

    Realmente no se que pasa, he revisado todo internet y no he logrado dar con el problema, alguien me podria ayudar..

    Porque no funcionan los ActionName?

    gracias.


    Gracias Carlos Bolivar

    jueves, 28 de agosto de 2014 4:47

Respuestas

  • Buenas!

    Diria, a bote pronto, que es por el orden de la tabla de rutas. La tienes definida así:

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

    Por lo tanto la URL /Blog/api/Default1/postlik se intenta mapear usando dicha tabla de rutas. Eliminamos la parte /Blog (que es el area) y nos queda la URL a mapear que es api/Default1/postlik.

    Entonces empieza por la primera ruta:

    routeTemplate: "api/{controller}/{id}". Se puede mapear tu URL a esa ruta? Pues sí:

    1. controller = Default1
    2. id = postlik

    Como hay un matching ya no se evalúan las ruatas siguientes.

    Por lo tanto webapi invoca el controlador Default1 con id "postlik". Como NO hay action definida usará el verbo HTTP (que es GET). Y resulta que se encuentra TRES métodos que pueden responder a GET. Como no tiene action no puede discriminar. Y de ahí el error.

    Lo que tu seguramente querías era mapear la segunda ruta, de forma que controller fuese Default1 y action=postlik (y sin id). De hecho estoy seguro que una URL tipo /Blog/api/Default1/postlik/x te funciona y te invoca el método deseado.

    Lo que debes hacer es modificar el orden de la tabla de rutas. Cambia las entradas de orden.

    Ya me dirás!

    Saludos!


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis

    • Marcado como respuesta cbolivar82 jueves, 28 de agosto de 2014 13:23
    jueves, 28 de agosto de 2014 7:01

Todas las respuestas

  • Buenas!

    Diria, a bote pronto, que es por el orden de la tabla de rutas. La tienes definida así:

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

    Por lo tanto la URL /Blog/api/Default1/postlik se intenta mapear usando dicha tabla de rutas. Eliminamos la parte /Blog (que es el area) y nos queda la URL a mapear que es api/Default1/postlik.

    Entonces empieza por la primera ruta:

    routeTemplate: "api/{controller}/{id}". Se puede mapear tu URL a esa ruta? Pues sí:

    1. controller = Default1
    2. id = postlik

    Como hay un matching ya no se evalúan las ruatas siguientes.

    Por lo tanto webapi invoca el controlador Default1 con id "postlik". Como NO hay action definida usará el verbo HTTP (que es GET). Y resulta que se encuentra TRES métodos que pueden responder a GET. Como no tiene action no puede discriminar. Y de ahí el error.

    Lo que tu seguramente querías era mapear la segunda ruta, de forma que controller fuese Default1 y action=postlik (y sin id). De hecho estoy seguro que una URL tipo /Blog/api/Default1/postlik/x te funciona y te invoca el método deseado.

    Lo que debes hacer es modificar el orden de la tabla de rutas. Cambia las entradas de orden.

    Ya me dirás!

    Saludos!


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis

    • Marcado como respuesta cbolivar82 jueves, 28 de agosto de 2014 13:23
    jueves, 28 de agosto de 2014 7:01
  • Gracias Eduard,

    segun indicas "Lo que debes hacer es modificar el orden de la tabla de rutas. Cambia las entradas de orden.",

    Conozco lo del MATCH sobre las rutas, incluso hice este cambio en el ordenen el archivo WebApiConfig.cs, quedando de la siguiente manera:

    config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApiAction2",
                    routeTemplate: "api/{controller}/{action}"
                );
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApiAction",
                    routeTemplate: "api/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
                
                var json = config.Formatters.JsonFormatter;
                json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
                config.Formatters.Remove(config.Formatters.XmlFormatter);

    El controlador lo tengo asi:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    
    namespace Intranet2.Areas.Blog.Controllers
    {
        public class Default1Controller : ApiController
        {
            [HttpGet]
            [ActionName("postlike")]
            public IHttpActionResult PostLikeMap()
            {
                //if (id.HasValue)
                //{
                //    //return collection of one item here
                //}
                return Ok("PostLikeMap");
            }
    
            [HttpGet]
            [ActionName("testa")]
            public IHttpActionResult TestA()
            {
                return Ok("textA");
            }
    
            [HttpGet]
            [ActionName("testb")]
            public IHttpActionResult TestB()
            {
                return Ok("textB");
            }
        }
    }
    

    Y cuando intento ejecutar cualquiera de las siguientes URL

    http://localhost/Intranet2/Blog/api/Default1/testa

    http://localhost/Intranet2/Blog/api/Default1/testb

    http://localhost/Intranet2/Blog/api/Default1/postlike

    Que corresponden a los metodos de las acciones, tengo el mismo error:

    {
    $id: "1",
    Message: "An error has occurred.",
    ExceptionMessage: "Multiple actions were found that match the request: System.Web.Http.IHttpActionResult PostLikeMap() on type Intranet2.Areas.Blog.Controllers.Default1Controller System.Web.Http.IHttpActionResult TestA() on type Intranet2.Areas.Blog.Controllers.Default1Controller System.Web.Http.IHttpActionResult TestB() on type Intranet2.Areas.Blog.Controllers.Default1Controller",
    ExceptionType: "System.InvalidOperationException",
    StackTrace: " at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext) at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()"
    }

    Al parecer no toma las rutas, Alguna nueva sugerencia?

    Nota: he leido por alli que la version del "System.Web.Http" con la herencia de la clase "ApiController", puedar ser el problema, conoces algo al respecto?

    gracias


    Gracias Carlos Bolivar

    jueves, 28 de agosto de 2014 12:20
  • Solucionado!

    Gracias Eduard, tenias razon, el problema estaba que yo poseia AREAS en mi solucion, y no estaba colocando la configuracion de las rutas que me indicastes en el lugar correcto, quedo de la siguiente manera:

    public class BlogAreaRegistration : AreaRegistration 
        {
            public override string AreaName 
            {
                get 
                {
                    return "Blog";
                }
            }
    
            public override void RegisterArea(AreaRegistrationContext context) 
            {
                context.Routes.MapHttpRoute(
                    name: AreaName + "_DefaultApiAction",
                    routeTemplate: AreaName + "/api/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                context.Routes.MapHttpRoute(
                    name: AreaName + "_DefaultApi",
                    routeTemplate: AreaName + "/api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                context.MapRoute(
                    AreaName + "_Default",
                    AreaName + "/{controller}/{action}/{id}",
                    new { action = "Index", id = UrlParameter.Optional }
                );
            }
        }

    Para compartir, la solucion fue colocar las ruta en el Area Registation.



    Gracias Carlos Bolivar

    jueves, 28 de agosto de 2014 13:23