0

我正在开发一个基于 MVC4 RC 并使用数据库优先实体框架作为我的模型的 Web API。我拥有的 2 个实体是ItemGroup。这两个实体之间存在多对多关系。

现在,在使用标准 HTTP 方法(、、和)非常轻松地实现了两者的 CRUD 操作 API 之后GET,我POST开始想要实现项目与组的绑定和解除绑定。PUTDELETE

我尝试了其他动词,例如LOCKand UNLOCK,但没有成功(他们似乎不支持它们),并试图以某种方式操纵POSTandPUT命令,再次没有成功。

你们中的任何一个好人都知道如何实现这一点吗?

非常感谢!

4

1 回答 1

1

您可以将多对多表示为根资源上的子集合。例如,您有 /items/1234 和 /groups/4567 - 您可以将组作为 /items/1234/groups 或 /groups/4567/items 的子集合

无论哪种方式都同样有效。我通常会使用 aPUT来设置关系并使用 aDELETE来删除它——有些人会说这不是真正的 REST,但在我使用它的场景中它工作得很好。

PUT /items/1234/groups/4567- 创建项目 1234 和组 4567 DELETE /items/1234/groups/4567之间的关系 - 删除项目 1234 和组 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 回答