0

私は、MVC4 RC に基づいて、モデルとしてデータベース ファーストの Entity Framework を使用して、Web API に取り組んでいます。私が持っているエンティティの 2 つはItemGroupです。これら 2 つのエンティティ間には多対多の関係があります。

さて、標準の HTTP メソッド ( GETPOSTPUTおよびDELETE) を使用して、両方の CRUD 操作の API を非常に簡単に実装した後、グループへのアイテムのバインドとグループからのアイテムのバインド解除を実装したいと思うようになりました。

LOCKandなどの他の動詞を試しUNLOCKてみましたが成功しませんでした (それらはサポートしていないようです) 。POSTPUT

あなたの善良な人々の中に、これを実装する方法を知っている人はいますか?

どうもありがとう!

4

1 に答える 1

1

多対多をルート リソースのサブコレクションとして表すことができます。例 /items/1234 と /groups/4567 があります - /items/1234/groups または /groups/4567/items としてグループをサブコレクションとして持つことができます

どちらの方法も等しく有効です。私は通常、 aを使用しPUTてリレーションシップを設定し、 a を使用しDELETEてそれを削除するというルートをたどります。これは実際には REST ではないと言う人もいますが、私が使用したシナリオではうまく機能しました。

PUT /items/1234/groups/4567- アイテム 1234 とグループ 4567 の間の関係を作成します - アイテム 1234 とグループ 4567 DELETE /items/1234/groups/4567の間の関係を削除します

この投稿は私を大いに助けました。このラストを調べていたら…

RESTful API で多対多の関係を処理する方法は?

更新: ルーティング

したがって、これらのより複雑なシナリオでは、より具体的なルートを単純に使用することになりました。すべてを単一の一般的なルートに詰め込もうとすると、すぐに醜くなる可能性があります。関連する URL が適切なコントローラーとアクションにルーティングされることを確認する一連の単体テストがあります。

    // routes
    routes.MapHttpRoute(
        name: "items.groups",
        routeTemplate: "items/{itemId}/groups/{groupId}",
        defaults: new { controller = "ItemGroup", groupId = RouteParameter.Optional });

次に、ItemGroupController には Get、Delete、および Put メソッドがあります。このように単体テストを行います...

    // unit tests
    [Test]
    public void PutItemGroup()
    {
        RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Put, "~/items/1234/groups/4567");
        Assert.IsNotNull(routingResult);
        Assert.AreEqual("ItemGroup", routingResult.Controller);
        Assert.AreEqual("Put", routingResult.Action);
        Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
        Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
    }

    [Test]
    public void GetItemGroups()
    {
        RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Get, "~/items/1234/groups");
        Assert.IsNotNull(routingResult);
        Assert.AreEqual("ItemGroup", routingResult.Controller);
        Assert.AreEqual("GetAll", routingResult.Action);
        Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
    }

    [Test]
    public void GetItemGroup()
    {
        RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Get, "~/items/1234/groups/4567");
        Assert.IsNotNull(routingResult);
        Assert.AreEqual("ItemGroup", routingResult.Controller);
        Assert.AreEqual("Get", routingResult.Action);
        Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
        Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
    }

    [Test]
    public void DeleteItemGroup()
    {
        RoutingResult routingResult = this.GenerateRoutingResult(HttpMethod.Delete, "~/items/1234/groups/4567");
        Assert.IsNotNull(routingResult);
        Assert.AreEqual("ItemGroup", routingResult.Controller);
        Assert.AreEqual("Delete", routingResult.Action);
        Assert.AreEqual("1234", routingResult.RouteData.Values["itemId"]);
        Assert.AreEqual("4567", routingResult.RouteData.Values["groupId"]);
    }

    private RoutingResult GenerateRoutingResult(HttpMethod method, string relativeUrl)
    {
        HttpConfiguration httpConfiguration = new HttpConfiguration(this.HttpRoutes);
        HttpRequestMessage request = new HttpRequestMessage(method, string.Format("http://test.local/{0}", relativeUrl.Replace("~/", string.Empty)));
        IHttpRouteData routeData = this.HttpRoutes.GetRouteData(request);

        Assert.IsNotNull(routeData, "Could not locate route for {0}", relativeUrl);

        this.RemoveOptionalRoutingParameters(routeData.Values);

        request.Properties.Add(HttpPropertyKeys.HttpRouteDataKey, routeData);
        request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, httpConfiguration);

        IHttpControllerSelector controllerSelector = new DefaultHttpControllerSelector(httpConfiguration);
        HttpControllerContext controllerContext = new HttpControllerContext(httpConfiguration, routeData, request)
            {
                ControllerDescriptor = controllerSelector.SelectController(request)
            };

        HttpActionDescriptor actionDescriptor = controllerContext.ControllerDescriptor.HttpActionSelector.SelectAction(controllerContext);
        if (actionDescriptor == null)
        {
            return null;
        }

        return new RoutingResult
            {
                Action = actionDescriptor.ActionName,
                Controller = actionDescriptor.ControllerDescriptor.ControllerName,
                RouteData = routeData
            };
    }

    private void RemoveOptionalRoutingParameters(IDictionary<string, object> routeValueDictionary)
    {
        int count = routeValueDictionary.Count;
        int index1 = 0;
        string[] strArray = new string[count];
        foreach (KeyValuePair<string, object> keyValuePair in routeValueDictionary)
        {
            if (keyValuePair.Value == RouteParameter.Optional)
            {
                strArray[index1] = keyValuePair.Key;
                ++index1;
            }
        }

        for (int index2 = 0; index2 < index1; ++index2)
        {
            string key = strArray[index2];
            routeValueDictionary.Remove(key);
        }
    }

    private class RoutingResult
    {
        public string Controller { get; set; }

        public string Action { get; set; }

        public IHttpRouteData RouteData { get; set; }
    }

乾杯、ディーン

于 2012-07-15T14:06:01.383 に答える