c# - atributo - alt title
La cadena de consulta no funciona al usar el enrutamiento de atributos (8)
Estoy usando System.Web.Http.RouteAttribute
y System.Web.Http.RoutePrefixAttribute
para habilitar URL más limpias para mi aplicación Web API 2. Para la mayoría de mis solicitudes, puedo usar el enrutamiento (por ejemplo, Controller/param1/param2
) o puedo usar cadenas de consulta (por ejemplo, Controller?param1=bob¶m2=mary
).
Desafortunadamente, con uno de mis Controladores (y solo uno), esto falla. Aquí está mi controlador:
[RoutePrefix("1/Names")]
public class NamesController : ApiController
{
[HttpGet]
[Route("{name}/{sport}/{drink}")]
public List<int> Get(string name, string sport, string drink)
{
// Code removed...
}
[HttpGet]
[Route("{name}/{drink}")]
public List<int> Get(string name, string drink)
{
// Code removed...
}
}
Cuando hago una solicitud para utilizar el enrutamiento, ambos funcionan bien. Sin embargo, si uso una cadena de consulta, falla, diciéndome que esa ruta no existe.
He intentado agregar lo siguiente a la WebApiConfig.cs
'' Register(HttpConfiguration config)
'' de la clase Register(HttpConfiguration config)
(antes y después de la ruta predeterminada), pero no hizo nada:
config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"/d+" });
Entonces, para mayor claridad, me gustaría poder hacer ambas cosas:
localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke
y,
localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke
pero lamentablemente las versiones de cadena de consulta no funcionan! :(
Actualizado
He eliminado por completo la segunda Acción y ahora intento usar solo una Acción singular con parámetros opcionales. Cambié el atributo de mi ruta a [Route("{name}/{drink}/{sport?}")]
Ya que Tony sugirió que el deporte sea nulo, pero esto ahora impide localhost:12345/1/Names/Ted/coke
de ser una ruta válida por alguna razón. Las cadenas de consulta se comportan del mismo modo que antes.
Actualización 2 Ahora tengo una acción singular en mi controlador:
[RoutePrefix("1/Names")]
public class NamesController : ApiController
{
[HttpGet]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
// Code removed...
}
}
pero aún así, el uso de cadenas de consulta no encuentra una ruta adecuada, mientras que el uso del método de enrutamiento sí lo hace.
Aquí hay una ligera desviación de la respuesta de @bhargav kishore mummadireddy , pero una desviación importante. Su respuesta predeterminará los valores de la cadena de consulta a un valor real no vacío. Esta respuesta los dejará predeterminados para vaciarse.
Le permite llamar al controlador a través del enrutamiento de ruta o mediante la cadena de consulta. Básicamente, establece el valor predeterminado de la cadena de consulta vacía, lo que significa que siempre se enrutará.
Esto fue importante para mí, porque quiero devolver 400 (Solicitud incorrecta) si no se especifica una cadena de consulta, en lugar de que ASP.NET devuelva el error "No se pudo encontrar este método en este controlador".
[RoutePrefix("api/AppUsageReporting")]
public class AppUsageReportingController : ApiController
{
[HttpGet]
// Specify default routing parameters if the parameters aren''t specified
[Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")]
public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate)
{
if (String.IsNullOrEmpty(userId))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified.");
}
if (!startDate.HasValue)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified.");
}
if (!endDate.HasValue)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified.");
}
}
}
Como tiene [Route("{name}/{drink}/{sport?}")]
Como enrutamiento de atributos, este código nunca será golpeado.
config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"/d+" });
Entonces, solo la ruta de atributo [Route("{name}/{drink}/{sport?}")]
Se cumplirá aquí. Desde su solicitud localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
, no tiene nombre, deporte o bebida en la URL, no va a coincidir con esta ruta de atributo. No consideramos los parámetros de cadena de consulta al hacer coincidir las rutas.
Para resolver esto, necesitas hacer que los 3 sean opcionales en tu ruta de atributo. Entonces coincidirá con la solicitud.
Con el enrutamiento de atributos, debe especificar valores predeterminados para que sean opcionales.
[Route("{name}/{sport=Football}/{drink=Coke}")]
La asignación de un valor le permitirá ser opcional para que no tenga que incluirlo y pasará el valor para especificarlo.
No he probado la cadena de consulta para esto, pero debería funcionar igual.
Acabo de volver a leer la pregunta y veo que tiene 2 Obtener verbos con el mismo camino, creo que esto causaría conflicto, ya que el enrutamiento no sabría cuál utilizar, tal vez usar los parámetros opcionales ayudará. También puede especificar que uno puede ser nulo y verificar el método de cómo proceder.
[Route("{name}/{sport?}/{drink?}")]
Luego, compruebe las variables en el método para ver si son nulas y manipular según sea necesario.
Espero que esto ayude, ¿algunos? lol
Si no es así, quizás este sitio tenga más detalles sobre el enrutamiento de atributos.
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
Clip desde ese sitio:
Parámetros opcionales y valores predeterminados Puede especificar que un parámetro sea opcional agregando un signo de interrogación al parámetro, es decir:
[Route("countries/{name?}")] public Country GetCountry(string name = "USA") { }
Actualmente, se debe especificar un valor predeterminado en el parámetro opcional para que la selección de acciones tenga éxito, pero podemos investigar el levantamiento de esa restricción. (Por favor, háganos saber si esto es importante).
Los valores predeterminados se pueden especificar de manera similar:
[Route("countries/{name=USA}")] public Country GetCountry(string name) { }
El parámetro opcional ''?'' y los valores predeterminados deben aparecer después de las restricciones en línea en la definición del parámetro.
Después de mucho violín y googlear, he encontrado una ''solución''. No sé si esto es ideal / mejor práctica / simple viejo error, pero resuelve mi problema.
Todo lo que hice fue agregar [Route("")]
además de los atributos de ruta que ya estaba usando. Básicamente, esto permite que el enrutamiento de la API web 2 permita cadenas de consulta, ya que ahora es una ruta válida.
Un ejemplo sería ahora:
[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
// Code removed...
}
Esto hace que tanto localhost:12345/1/Names/Ted/coke
como localhost:12345/1/Names?name=Ted&drink=coke
valid.
Estaba enfrentando el mismo problema de ''¿Cómo incluir los parámetros de búsqueda como una cadena de consulta?'', Mientras intentaba crear una API web para mi proyecto actual. Después de googlear, lo siguiente está funcionando bien para mí:
Acción del controlador Api:
[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]
public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{
}
La url que probé a través del cartero:
http://localhost/PD/search?categoryid=all-products&ordercode=star-1932
http://localhost/PD is my hosted api
Solo una nota lateral de mi parte también. Para que los parámetros de queryString funcionen, debe proporcionar un valor predeterminado para los parámetros de su método para hacerlo opcional . Del mismo modo que lo haría cuando normalmente invoca un método C #.
[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{
...
[HttpGet]
[Route("{profileUid}")]
public IHttpActionResult GetProfile(string profileUid, long? someOtherId)
{
// ...
}
...
}
Esto me permite llamar al punto final así:
/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123
Usar Route("search/{categoryid=categoryid}/{ordercode=ordercode}")
le permitirá usar tanto Querystrings como parámetros de ruta en línea respondidos por mosharaf hossain . Escribir esta respuesta como esto debería ser la mejor respuesta y la mejor manera. Usar Route("")
causará problemas si tiene múltiples Gets / Puts / Posts / Deletes.
Yo uso el atributo FromUri como solución
[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)