Один controller с несколькими методами GET в ASP.NET Web API

В Web API у меня был class аналогичной структуры:

public class SomeController : ApiController { [WebGet(UriTemplate = "{itemSource}/Items")] public SomeValue GetItems(CustomParam parameter) { ... } [WebGet(UriTemplate = "{itemSource}/Items/{parent}")] public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } } 

Поскольку мы могли отображать отдельные методы, было очень просто получить правильный запрос в нужном месте. Для аналогичного classа, который имел только один метод GET но также имел параметр Object , я успешно использовал IActionValueBinder . Однако в описанном выше случае возникает следующая ошибка:

 Multiple actions were found that match the request: SomeValue GetItems(CustomParam parameter) on type SomeType SomeValue GetChildItems(CustomParam parameter, SomeObject parent) on type SomeType 

Я пытаюсь подойти к этой проблеме, переопределив метод ApiController но пока не повезло. Любые советы по этому вопросу?

Edit: Я забыл упомянуть, что теперь я пытаюсь переместить этот код в ASP.NET Web API, который имеет другой подход к маршрутизации. Вопрос в том, как заставить код работать в ASP.NET Web API?

Это лучший способ найти дополнительные методы GET и поддерживать обычные методы REST. Добавьте в свой WebApiConfig следующие маршруты:

 routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" }); routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}"); routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }); routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)}); 

Я проверил это решение с помощью тестового classа ниже. Я смог успешно использовать каждый метод в моем controllerе ниже:

 public class TestController : ApiController { public string Get() { return string.Empty; } public string Get(int id) { return string.Empty; } public string GetAll() { return string.Empty; } public void Post([FromBody]string value) { } public void Put(int id, [FromBody]string value) { } public void Delete(int id) { } } 

Я подтвердил, что он поддерживает следующие запросы:

 GET /Test GET /Test/1 GET /Test/GetAll POST /Test PUT /Test/1 DELETE /Test/1 

Обратите внимание: если ваши дополнительные действия GET не начинаются с «Get», вы можете добавить к этому атрибуту атрибут HttpGet.

Исходя из этого:

 config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional }); 

К этому:

 config.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional }); 

Следовательно, теперь вы можете указать, какое действие (метод) вы хотите отправить HTTP-запрос.

размещение на «http: // localhost: 8383 / api / Command / PostCreateUser» вызывает:

 public bool PostCreateUser(CreateUserCommand command) { //* ... *// return true; } 

и публикация на «http: // localhost: 8383 / api / Command / PostMakeBooking» вызывает:

 public bool PostMakeBooking(MakeBookingCommand command) { //* ... *// return true; } 

Я пробовал это в собственном веб-приложении WEB API, и он работает как шарм 🙂

Я считаю, что атрибуты чище использовать, чем вручную добавлять их через код. Вот простой пример.

 [RoutePrefix("api/example")] public class ExampleController : ApiController { [HttpGet] [Route("get1/{param1}")] // /api/example/get1/1?param2=4 public IHttpActionResult Get(int param1, int param2) { Object example = null; return Ok(example); } } 

Вы также нуждаетесь в этом в своем webapiconfig

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

Некоторые полезные ссылки http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api. Этот пояс объясняет, как улучшить маршрутизацию. http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

Вам необходимо определить дальнейшие маршруты в global.asax.cs следующим образом:

 routes.MapHttpRoute( name: "Api with action", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); 

Я не уверен, нашел ли у вас ответ, но я сделал это, и он работает

 public IEnumerable Get() { return new string[] { "value1", "value2" }; } // GET /api/values/5 public string Get(int id) { return "value"; } // GET /api/values/5 [HttpGet] public string GetByFamily() { return "Family value"; } 

Сейчас в global.asx

 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapHttpRoute( name: "DefaultApi2", routeTemplate: "api/{controller}/{action}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); 

Вы пытались переключиться на WebInvokeAttribute и установить метод «GET»?

Я полагаю, что у меня была аналогичная проблема, и я решил явно указать, какой метод (GET / PUT / POST / DELETE) ожидается в большинстве, если не во всех, моих методах.

 public class SomeController : ApiController { [WebInvoke(UriTemplate = "{itemSource}/Items"), Method="GET"] public SomeValue GetItems(CustomParam parameter) { ... } [WebInvoke(UriTemplate = "{itemSource}/Items/{parent}", Method = "GET")] public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } } 

WebGet должен обработать его, но я видел, что у него есть некоторые проблемы с несколькими Get гораздо меньше нескольких Get из того же типа возврата.

[Изменить: ничто из этого не действует при закате WCF WebAPI и переходе на ASP.Net WebAPI в стек MVC]

С новым Web Api 2 стало проще иметь несколько методов get.

Если параметр, переданный методам GET , достаточно различен, чтобы система маршрутизации атрибутов различала их типы, как в случае с int s и Guid вы можете указать ожидаемый тип в атрибуте [Route...]

Например –

 [RoutePrefix("api/values")] public class ValuesController : ApiController { // GET api/values/7 [Route("{id:int}")] public string Get(int id) { return $"You entered an int - {id}"; } // GET api/values/AAC1FB7B-978B-4C39-A90D-271A031BFE5D [Route("{id:Guid}")] public string Get(Guid id) { return $"You entered a GUID - {id}"; } } 

Подробнее об этом подходе см. Здесь http://nodogmablog.bryanhogan.net/2017/02/web-api-2-controller-with-multiple-get-methods-part-2/

Еще один вариант – дать методам GET разные маршруты.

  [RoutePrefix("api/values")] public class ValuesController : ApiController { public string Get() { return "simple get"; } [Route("geta")] public string GetA() { return "A"; } [Route("getb")] public string GetB() { return "B"; } } 

См. Здесь для более подробной информации – http://nodogmablog.bryanhogan.net/2016/10/web-api-2-controller-with-multiple-get-methods/

Я пытался использовать маршрутизацию атрибутов Web Api 2, чтобы разрешить несколько методов Get, и я включил полезные предложения из предыдущих ответов, но в controllerе я только украсил «специальный» метод (пример):

 [Route( "special/{id}" )] public IHttpActionResult GetSomethingSpecial( string id ) { 

… также не помещая [RoutePrefix] в верхней части controllerа:

 [RoutePrefix("api/values")] public class ValuesController : ApiController 

Я получал ошибки, заявляя, что никакой маршрут не найден в соответствии с представленным URI. Как только у меня был как [Маршрут], украшающий метод, так и [RoutePrefix], украшавший controller в целом, он работал.

В ASP.NET Core 2.0 вы можете добавить атрибут Route к controllerу:

 [Route("api/[controller]/[action]")] public class SomeController : Controller { public SomeValue GetItems(CustomParam parameter) { ... } public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... } } 

Ни один из приведенных выше примеров не работал для моих личных нужд. Ниже я так и сделал.

  public class ContainsConstraint : IHttpRouteConstraint { public string[] array { get; set; } public bool match { get; set; } ///  /// Check if param contains any of values listed in array. ///  /// The param to test. /// The items to compare against. /// Whether we are matching or NOT matching. public ContainsConstraint(string[] array, bool match) { this.array = array; this.match = match; } public bool Match(System.Net.Http.HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary values, HttpRouteDirection routeDirection) { if (values == null) // shouldn't ever hit this. return true; if (!values.ContainsKey(parameterName)) // make sure the parameter is there. return true; if (string.IsNullOrEmpty(values[parameterName].ToString())) // if the param key is empty in this case "action" add the method so it doesn't hit other methods like "GetStatus" values[parameterName] = request.Method.ToString(); bool contains = array.Contains(values[parameterName]); // this is an extension but all we are doing here is check if string array contains value you can create exten like this or use LINQ or whatever u like. if (contains == match) // checking if we want it to match or we don't want it to match return true; return false; } 

Чтобы использовать вышеизложенное в своем маршруте, используйте:

 config.Routes.MapHttpRoute("Default", "{controller}/{action}/{id}", new { action = RouteParameter.Optional, id = RouteParameter.Optional}, new { action = new ContainsConstraint( new string[] { "GET", "PUT", "DELETE", "POST" }, true) }); 

Что происходит, так это тип подделок в методе ограничения, так что этот маршрут будет соответствовать только методам GET, POST, PUT и DELETE по умолчанию. «Истина» там говорит, что мы хотим проверить соответствие элементов в массиве. Если бы это было ложно, вы бы сказали, что исключить из них в strYou можно использовать маршруты выше этого метода по умолчанию, например:

 config.Routes.MapHttpRoute("GetStatus", "{controller}/status/{status}", new { action = "GetStatus" }); 

В приведенном выше примере он по существу ищет следующий URL => http://www.domain.com/Account/Status/Active или что-то в этом роде.

Помимо вышеизложенного, я не уверен, что сойду с ума. В конце концов, это должно быть на ресурс. Но я вижу необходимость в картографировании дружественных URL-адресов по различным причинам. Я чувствую себя вполне уверенно, как развивается Web Api, будет какое-то положение. Если время я построю более постоянное решение и пост.

Не удалось заставить какие-либо из вышеперечисленных решений маршрутизации работать – некоторые из синтаксиса, похоже, изменились, и я все еще новичок в MVC – в крайнем случае, хотя я собрал этот действительно ужасный (и простой) хак, который доставит меня на данный момент – обратите внимание, что это заменяет метод «public MyObject GetMyObjects (long id)» – мы меняем тип «id» на строку и меняем тип возвращаемого объекта на объект.

 // GET api/MyObjects/5 // GET api/MyObjects/function public object GetMyObjects(string id) { id = (id ?? "").Trim(); // Check to see if "id" is equal to a "command" we support // and return alternate data. if (string.Equals(id, "count", StringComparison.OrdinalIgnoreCase)) { return db.MyObjects.LongCount(); } // We now return you back to your regularly scheduled // web service handler (more or less) var myObject = db.MyObjects.Find(long.Parse(id)); if (myObject == null) { throw new HttpResponseException ( Request.CreateResponse(HttpStatusCode.NotFound) ); } return myObject; } 

Если у вас несколько действий в одном файле, то передайте тот же аргумент, например Id для всех действий. Это потому, что действие может только идентифицировать Id, поэтому вместо того, чтобы давать какое-либо имя аргументу, просто объявляйте Id как это.


 [httpget] [ActionName("firstAction")] firstAction(string Id) {..... ..... } [httpget] [ActionName("secondAction")] secondAction(Int Id) {..... ..... } //Now go to webroute.config file under App-start folder and add following routes.MapHttpRoute( name: "firstAction", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); routes.MapHttpRoute( name: "secondAction", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); 

Простая альтернатива

Просто используйте строку запроса.

маршрутизация

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

controller

 public class TestController : ApiController { public IEnumerable Get() { } public SomeViewModel GetById(int objectId) { } } 

Запросы

 GET /Test GET /Test?objectId=1 

Заметка

Имейте в виду, что параметр строки запроса не должен быть «id» или каким-либо параметром в настроенном маршруте.

Измените WebApiConfig и добавьте в конец еще один Routes.MapHttpRoute, как это:

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

Затем создайте controller следующим образом:

 public class ServiceController : ApiController { [HttpGet] public string Get(int id) { return "object of id id"; } [HttpGet] public IQueryable DropDowEmpresa() { return db.Empresa.Where(x => x.Activo == true).Select(y => new DropDownModel { Id = y.Id, Value = y.Nombre, }); } [HttpGet] public IQueryable DropDowTipoContacto() { return db.TipoContacto.Select(y => new DropDownModel { Id = y.Id, Value = y.Nombre, }); } [HttpGet] public string FindProductsByName() { return "FindProductsByName"; } } 

Вот как я это решил. Надеюсь, это поможет кому-то.

  • Исключение BadImageFormatException при загрузке 32-разрядной библиотеки DLL, целью является x86
  • определить, является ли файл изображением
  • Как сделать cin брать только числа
  • Предупреждение компилятора "No newline at end of file"
  • Роллинг-срединный алгоритм в C
  • Какова служебная нагрузка для std :: function?
  • Отправить электронную почту через C # через аккаунт Google Apps
  • Неактивность и активность WPF
  • std :: sort не всегда вызывает std :: swap
  • Как найти утечку памяти в коде / проекте на C ++?
  • Как получить json.net для сериализации членов classа, полученных из List ?
  • Давайте будем гением компьютера.