Один контроллер с несколькими методами GET в ASP.NET Web API - PullRequest
148 голосов
/ 29 февраля 2012

В Web API у меня был класс схожей структуры:

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) { ... }
}

Поскольку мы могли отображать отдельные методы, было очень просто получить правильный запрос в нужном месте.Для аналогичного класса, который имел только один метод 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

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

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

Ответы [ 14 ]

0 голосов
/ 06 января 2017

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

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

Затем создайте контроллер, подобный этому:

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

        [HttpGet]
        public IQueryable<DropDownModel> DropDowTipoContacto()
        {
            return db.TipoContacto.Select(y =>
                  new DropDownModel
                  {
                      Id = y.Id,
                      Value = y.Nombre,
                  });
        }

        [HttpGet]
        public string FindProductsByName()
        {
            return "FindProductsByName";
        }
}

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

0 голосов
/ 12 апреля 2016

Если у вас есть несколько действий в одном файле, передайте один и тот же аргумент, например, 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 }
);
0 голосов
/ 17 июня 2013

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

// 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;
}
0 голосов
/ 07 сентября 2012

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

 public class ContainsConstraint : IHttpRouteConstraint
{       
    public string[] array { get; set; }
    public bool match { get; set; }

    /// <summary>
    /// Check if param contains any of values listed in array.
    /// </summary>
    /// <param name="param">The param to test.</param>
    /// <param name="array">The items to compare against.</param>
    /// <param name="match">Whether we are matching or NOT matching.</param>
    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<string, object> 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) });

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...