6

Groups次のアクションを持つコントローラーがあります。

public GroupModel Get(int ID)

public GroupModel Post(CreateGroupModel model)

public void Put(PublicUpdateGroupModel model)

public void PutAddContacts(UpdateContactsModel model)

public void PutRemoveContacts(UpdateContactsModel model)

public void Delete(int ID)

そして、私がやりたいことは、標準の REST ルーティングを使用して、標準の get、post、put、delete メソッドを呼び出すことです。ただし、アクション名が URL に追加されている場合はPutAddContactsand を呼び出します。次に例を示します。PutRemoveContacts

GET グループ/ - Get メソッドを呼び出します

POST groups/ - Post メソッドを呼び出します

PUT グループ/ - Put メソッドを呼び出します

DELETE groups/ - Delete メソッドを呼び出します

PUT groups/addcontacts - PutAddContacts メソッドを呼び出します

PUT グループ/連絡先の削除 - PutRemoveContacts メソッドを呼び出します

これを行うためにルーティングを設定することは可能ですか? または、URL でアクション名を使用したい場合、ルーティングのために RPC ルートをたどる必要がありますか?

4

2 に答える 2

12

今持っている
もの 上記のようにメソッドを利用するには、RPC に移行する必要があります。これは、あなたの例が RPC スタイルの処理にすでに半分浸かっているためです。デフォルトの WebAPI ルートは RESTful なセットアップを推奨しますが、ルートにわずかな変更を加えると、すべてが機能し始めます。たとえば、デフォルト ルートを典型的な MVC ルートのようなものに変更できます。

routes.MapRoute( name    : "Default",       
                 url     : "{controller}/{action}/{id}",
                 defaults: new { controller = "Home", 
                                 action     = "Index", 
                                 id         = UrlParameter.Optional });

ルートを追加した後、コントローラー名とアクションを使用する典型的な MVC の方法で物事を呼び出します。ただし、あなたの質問から、あなたは実際にRESTfulになりたいと思っているのではないかと思います.

RESTful であること
RESTは HTTP を必要としませんが、この 2 つは一緒に議論されることがよくあります。REST は、意味的に正確な表現を持つすべてのリソースに関するものです。HTTP を使用する場合、HTTP セマンティクスを尊重する一意の URI を意味します。したがって、たとえば、HTTP GET を使用する呼び出しは、データを変更してはなりません。これは、HTTP の GET の定義に違反し、キャッシュなどの混乱した HTTP インフラストラクチャに違反するためです。

POST/PUT vs MERGE/PATCH
GET、POST、PUT、HEAD などの HTTP メソッドはよく知られています。一般に、GET は取得用、POST は追加用、PUT は変更用です (ただし、多くの議論があります)。ただし、アイテムの追加とコレクションからのアイテムの削除の 2 種類の変更があります。それで、それらは両方ともPUTですか、それとも何か他のものですか?コミュニティは、これを行う方法を完全には決めていません

  • オプション 1: カスタム メディア タイプ - HTTP 仕様では、あらゆる種類のメソッドが実際に許可されています。実際には、おなじみのサブセットに制限されているのはブラウザーです。そのため、MERGE (Roy Fielding の回避策) または PATCH (oData の回避策)メソッドを作成し、この新しいメディア タイプの動作を定義できます。1 つは追加用、もう 1 つは削除用です。

  • オプション 2: POST/PUT を使用 - 連絡先の追加と削除の両方に PUT を使用します。ID のリストをトグル (存在する場合は削除、欠落している場合は追加) のように扱うか、代わりに何をすべきかを知るのに十分な情報を含めます。次に、クライアントに古い状態であることを示す HTTP 303 を返し、更新します。

  • オプション 3: 完全なリスト- セットのサイズが妥当な場合は、更新するたびに連絡先の完全なリストをいつでも渡すことができます。このように、ロジックは非常に単純な消去と置換です。

RESTful の観点から本当に重要なことは、アプリケーションがすべてのメソッドで一貫した方法で動作することです。したがって、MERGE が追加を意味する場合は、常に追加を意味する必要があります。ID の完全なセットが PUT に渡されると予想される場合は、常に完全なセットを渡します。

コントローラーの設計
私だったら、あなたのコントローラーを複数のコントローラーに分割します。1 つのコントローラーはグループを処理し、別のコントローラーは (グループとして) 連絡先を処理し、3 番目のコントローラーはグループ内の 1 つの連絡先を処理します。何かのようなもの ...

//api/Group/
public List<GroupModel> Get()
public GroupModel Get(int ID)
public GroupModel Post(GroupModel model)  //add a group
public GroupModel Put(GroupModel model)   //update a group (see comments above)
public void Delete(int ID)


//api/GroupContacts/
public ContactsModel Get()                    //gets complete list
public void PostContacts(ContactsModel model) //pushes a COMPLETE new state
public void Delete()                          //delete entire group of contacts


//api/GroupContact/354/
public ContactModel Get(int id)             //get contact id #354
public void PostContact(ContactModel model) //add contact (overwrite if exits)
public void Delete(int id)                  //delete contact if exists

URL を入れ子 (例: /api/Group/Contacts, ) に表示したい場合は、私が書いたこの別の投稿を/api/Group/Contact見ることができます。IMHO、asp.netのルーティングは、ネストを少し簡単にサポートするために調整する必要があります...しかし、それは別の問題です;-)

于 2012-09-10T11:58:15.483 に答える
4

EBarrが言ったことを反映するために、WebAPIで階層型ルーティングを行うのは少し面倒です。私は自分のサービスでそれを頻繁に使用しているので、WebAPIの代替ルーティングサービスを構築しました。Nugetはここにあり、ソースはGitHubにあります

このルーティングへのアプローチでは、パスセグメントの階層としてURI名前空間を構築する必要があります。完全なURIパターンをコントローラーに一致させるのではなく、パスセグメントのツリー内の任意のポイントにコントローラーをアタッチします。

私があなたがやろうとしていることと同様のURIで小さなセルフホストサンプルを作成したように見えることをあなたに理解させるために:

internal class Program
{
   private static void Main(string[] args)
   {
    var baseAddress = new Uri("http://oak:8700/");

    var configuration = new HttpSelfHostConfiguration(baseAddress);
    var router = new ApiRouter("api", baseAddress);

    // /api/Contacts
    router.Add("Contacts", rcs => rcs.To<ContactsController>());

    // /api/Contact/{contactid}
    router.Add("Contact", rc =>
                          rc.Add("{contactid}", rci => rci.To<ContactController>()));

    // /api/Group/{groupid}
    // /api/Group/{groupid}/Contacts
    router.Add("Group", rg =>
                        rg.Add("{groupid}", rgi => rgi.To<GroupController>() 
                                                       .Add("Contacts", rgc => rgc.To<GroupContactsController>())));


    configuration.MessageHandlers.Add(router);

    var host = new HttpSelfHostServer(configuration);
    host.OpenAsync().Wait();

    Console.WriteLine("Host open.  Hit enter to exit...");

    Console.Read();

    host.CloseAsync().Wait();
  }
}

public class GroupController : TestController { }
public class ContactsController : TestController { }
public class ContactController : TestController { }
public class GroupContactsController : TestController { }


public class TestController : ApiController
{
    public HttpResponseMessage Get()
    {
        var pathRouteData = (PathRouteData) Request.GetRouteData();

        var paramvalues = new StringBuilder();

        foreach (KeyValuePair<string, object> keyValuePair in pathRouteData.Values)
        {
            paramvalues.Append(keyValuePair.Key);
            paramvalues.Append(" = ");
            paramvalues.Append(keyValuePair.Value);
            paramvalues.Append(Environment.NewLine);
        }

        var url = pathRouteData.RootRouter.GetUrlForController(this.GetType());

        return new HttpResponseMessage()
                   {
                       Content = new StringContent("Response from " + this.GetType().Name + Environment.NewLine
                                                   + "Url: " + url.AbsoluteUri
                                                   + "Parameters: " + Environment.NewLine
                                                   + paramvalues.ToString())
                   };
    }
}

このコードをコンソールアプリに貼り付け、Microsoft.AspNet.WebApi.SelfHostおよびTavis.WebApiRouter nugetsへの参照を追加して、試してみることができるはずです。この種のルーティングをどこまで実行できるかについて知りたい場合は、ここにもっと複雑なサンプルがあります。

于 2012-09-10T15:08:21.663 に答える