113

WCF Web API から新しい ASP.NET MVC 4 Web API に変換しています。UsersController があり、Authenticate という名前のメソッドが必要です。GetAll、GetOne、Post、および Delete を実行する方法の例を見ましたが、これらのサービスにメソッドを追加したい場合はどうすればよいでしょうか? たとえば、私の UsersService には、ユーザー名とパスワードを渡す Authenticate というメソッドが必要ですが、機能しません。

public class UsersController : BaseApiController
{
    public string GetAll()
    {
        return "getall!";
    }

    public string Get(int id)
    {
        return "get 1! " + id;
    }

    public User GetAuthenticate(string userName, string password, string applicationName)
    {
        LogWriter.Write(String.Format("Received authenticate request for username {0} and password {1} and application {2}",
            userName, password, applicationName));

        //check if valid leapfrog login.
        var decodedUsername = userName.Replace("%40", "@");
        var encodedPassword = password.Length > 0 ? Utility.HashString(password) : String.Empty;
        var leapFrogUsers = LeapFrogUserData.FindAll(decodedUsername, encodedPassword);

        if (leapFrogUsers.Count > 0)
        {
            return new User
            {
                Id = (uint)leapFrogUsers[0].Id,
                Guid = leapFrogUsers[0].Guid
            };
        }
        else
            throw new HttpResponseException("Invalid login credentials");
    }
}

myapi/api/users/ を参照すると GetAll が呼び出され、myapi/api/users/1 を参照すると Get が呼び出されますが、myapi/api/users/authenticate?username={0} を呼び出すと&password={1} の場合、Get (認証ではなく) が呼び出され、エラーが発生します。

パラメーター ディクショナリには、'Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController' のメソッド 'System.String Get(Int32)' の null 非許容型 'System.Int32' のパラメーター 'id' の null エントリが含まれています。オプションのパラメーターは、参照型または null 許容型であるか、オプションのパラメーターとして宣言する必要があります。

Authenticate などのカスタム メソッド名を呼び出すにはどうすればよいですか?

4

8 に答える 8

89

これは、通常のRESTメソッドもサポートしながら、追加のGETメソッドを組み込むためにこれまでに思いついた最良のメソッドです。次のルートを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:33:28.537 に答える
13

ASP.NET MVC 6でASP.NET 5を使用している場合、通常は MVC に (既定の RESTful 規則を使用して) 適切なルート コレクションを作成させるため、これらの回答のほとんどは機能しません。自由に編集する呼び出しはありません。Routes.MapRoute()

ConfigureServices()ファイルによって呼び出されたメソッドは、MVCStartup.csを ASP.NET 5 に組み込まれた依存性注入フレームワークに登録します。これにより、ApplicationBuilder.UseMvc()後でそのクラスを呼び出すと、MVC フレームワークはこれらの既定のルートをアプリに自動的に追加します。UseMvc()フレームワークのソース コード内のメソッドの実装を調べることで、フードの背後で何が起こっているかを見ることができます。

public static IApplicationBuilder UseMvc(
    [NotNull] this IApplicationBuilder app,
    [NotNull] Action<IRouteBuilder> configureRoutes)
{
    // Verify if AddMvc was done before calling UseMvc
    // We use the MvcMarkerService to make sure if all the services were added.
    MvcServicesHelper.ThrowIfMvcNotRegistered(app.ApplicationServices);

    var routes = new RouteBuilder
    {
        DefaultHandler = new MvcRouteHandler(),
        ServiceProvider = app.ApplicationServices
    };

    configureRoutes(routes);

    // Adding the attribute route comes after running the user-code because
    // we want to respect any changes to the DefaultHandler.
    routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(
        routes.DefaultHandler,
        app.ApplicationServices));

    return app.UseRouter(routes.Build());
}

これの良いところは、フレームワークがすべての困難な作業を処理し、すべてのコントローラーのアクションを反復処理してデフォルト ルートを設定することで、冗長な作業を節約できることです。

悪い点は、独自のルートを追加する方法についてのドキュメントがほとんどまたはまったくないことです。幸いなことに、規約ベースおよび/または属性ベースのアプローチ (別名属性ルーティング)を使用することで、これを簡単に行うことができます。

コンベンションベース

Startup.cs クラスで、これを置き換えます。

app.UseMvc();

これとともに:

app.UseMvc(routes =>
            {
                // Route Sample A
                routes.MapRoute(
                    name: "RouteSampleA",
                    template: "MyOwnGet",
                    defaults: new { controller = "Items", action = "Get" }
                );
                // Route Sample B
                routes.MapRoute(
                    name: "RouteSampleB",
                    template: "MyOwnPost",
                    defaults: new { controller = "Items", action = "Post" }
                );
            });

属性ベース

MVC6 の優れた点は、次のように適切なand/or /テンプレート パラメーターを使用してControllerクラスやメソッドを装飾することにより、コントローラーごとにルートを定義することもできることです。ActionRouteAttributeHttpGetHttpPost

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace MyNamespace.Controllers
{
    [Route("api/[controller]")]
    public class ItemsController : Controller
    {
        // GET: api/items
        [HttpGet()]
        public IEnumerable<string> Get()
        {
            return GetLatestItems();
        }

        // GET: api/items/5
        [HttpGet("{num}")]
        public IEnumerable<string> Get(int num)
        {
            return GetLatestItems(5);
        }       

        // GET: api/items/GetLatestItems
        [HttpGet("GetLatestItems")]
        public IEnumerable<string> GetLatestItems()
        {
            return GetLatestItems(5);
        }

        // GET api/items/GetLatestItems/5
        [HttpGet("GetLatestItems/{num}")]
        public IEnumerable<string> GetLatestItems(int num)
        {
            return new string[] { "test", "test2" };
        }

        // POST: /api/items/PostSomething
        [HttpPost("PostSomething")]
        public IActionResult Post([FromBody]string someData)
        {
            return Content("OK, got it!");
        }
    }
}

このコントローラーは、次のリクエストを処理します。

 [GET] api/items
 [GET] api/items/5
 [GET] api/items/GetLatestItems
 [GET] api/items/GetLatestItems/5
 [POST] api/items/PostSomething

また、2 つのアプローチを一緒に使用すると、属性ベースのルート (定義されている場合) が規則ベースのルートをオーバーライドし、両方とも で定義されたデフォルト ルートをオーバーライドすることに注意してくださいUseMvc()

詳細については、私のブログの次の投稿を読むこともできます。

于 2016-02-14T19:19:33.973 に答える
9

名前付きアクションの詳細については、この記事を参照してください。また、アクション名の前に「get」を付ける代わりに、[HttpGet] 属性を使用できることも示しています。

http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

于 2012-03-08T16:46:15.243 に答える