188

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 でコードを機能させるにはどうすればよいかということです。

4

19 に答える 19

264

これは、追加の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)});

以下のテストクラスでこのソリューションを検証しました。以下のコントローラーで各メソッドを正常に実行できました。

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属性を追加することをお勧めします

于 2012-08-29T19:35:10.553 に答える
62

これから行く:

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 サービス アプリケーションでこれを試してみましたが、魅力的に機能します :)

于 2012-04-17T12:04:36.380 に答える
37

コードを介して手動で属性を追加するよりも、属性をよりクリーンに使用できることがわかりました。簡単な例を次に示します。

[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

于 2014-03-25T20:21:22.340 に答える
11

次のように、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 }
);
于 2012-02-29T19:56:15.493 に答える
4

デフォルトでは、[Route("api/[controller]") は .Net Core/Asp.Net Web API によって生成されます。少し変更する必要があります。[Route("api/[controller]/[アクション]")]。私はダミーの解決策について言及しました:

// Default generated controller
//
[Route("api/[controller]")
public class myApiController : Controller
{
    [HttpGet]
    public string GetInfo()
    {
        return "Information";
    }
}

//
//A little change would do the magic
//

[Route("api/[controller]/[action]")]
public class ServicesController : Controller
{
    [HttpGet]
    [ActionName("Get01")]
    public string Get01()
    {
        return "GET 1";
    }

    [HttpGet]
    [ActionName("Get02")]
    public string Get02()
    {
        return "Get 2";
    }
    
    [HttpPost]
    [ActionName("Post01")]
    public HttpResponseMessage Post01(MyCustomModel01 model)
    {
        if (!ModelState.IsValid)
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        
        //.. DO Something ..
        return Request.CreateResonse(HttpStatusCode.OK, "Optional Message");
    }
    
    [HttpPost]
    [ActionName("Post02")]
    public HttpResponseMessage Post02(MyCustomModel02 model)
    {
        if (!ModelState.IsValid)
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        
        //.. DO Something ..
        return Request.CreateResonse(HttpStatusCode.OK, "Optional Message");
    }


}
于 2020-11-25T14:39:10.193 に答える
3

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 の廃止と MVC スタックでの ASP.Net WebAPI への移行では有効ではありません]

于 2012-02-29T14:57:49.810 に答える
3

あなたが答えを見つけたかどうかはわかりませんが、私はこれをやったのでうまくいきました

public IEnumerable<string> 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 }
);
于 2012-03-19T08:07:34.430 に答える
1

属性でベースパスを指定して[Route]から、ベースパスに追加すると[HttpGet]うまくいきました。あなたが試すことができます:

    [Route("api/TestApi")]      //this will be the base path
    public class TestController : ApiController
    {
        [HttpGet]  //example call: 'api/TestApi'
        public string Get()
        {
            return string.Empty;
        }
    
        [HttpGet("{id}")]  //example call: 'api/TestApi/4'
        public string GetById(int id) //method name won't matter
        {
            return string.Empty;
        }
    
        //....

何度も使いたくなかったので、理解するのに時間がかかりました[Route]

于 2020-09-05T15:59:09.463 に答える
0

上記の例はどれも私の個人的なニーズには役立ちませんでした。以下は私がやったことです。

 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) });

何が起こるかというと、このルートがデフォルトのGET、POST、PUT、およびDELETEメソッドにのみ一致するように、メソッドの偽物の種類が制約されます。そこでの「真」は、配列内の項目の一致をチェックしたいことを示しています。falseの場合は、strYouでそれらを除外すると言うことになります。次に、次のようなこのデフォルトの方法より上のルートを使用できます。

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

http://www.domain.com/Account/Status/Active上記では、基本的に次のURL=>などを探しています。

上記を超えて、私はあまりにも夢中になるかどうかはわかりません。結局のところ、それはリソースごとである必要があります。しかし、さまざまな理由から、わかりやすいURLをマップする必要があると思います。Web Apiが進化するにつれて、ある種のプロビジョニングがあると私はかなり確信しています。時間があれば、より永続的なソリューションを構築して投稿します。

于 2012-09-07T17:07:06.067 に答える
0

同じファイル内に複数のアクションがある場合は、同じ引数 (例: 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 }
);
于 2016-04-12T15:47:42.160 に答える
0

上記のルーティングソリューションのいずれも機能させることができませんでした-構文の一部が変更されたようで、私はまだ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;
}
于 2013-06-17T12:22:59.493 に答える
-1

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";
        }
}

これが私がそれを解決した方法です。それが誰かを助けることを願っています。

于 2017-01-06T15:36:16.457 に答える