簡體   English   中英

ASP.NET Web API中的多個PUT方法

[英]Multiple PUT methods in ASP.NET Web API

我有一個控制器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 mehods。 但是如果動作名稱被附加到url,則調用PutAddContactsPutRemoveContacts ,例如:

獲取組/ - 調用Get方法

POST組/ - 調用Post方法

PUT組/ - 調用Put方法

DELETE groups / - 調用Delete方法

PUT groups / addcontacts - 調用PutAddContacts方法

PUT groups / removecontacts - 調用PutRemoveContacts方法

是否可以設置路由來執行此操作,或者如果我想在URL中使用操作名稱,是否需要沿着RPC路由進行路由?

你現在有什么
要使用上述方法,您需要使用RPC。 這是因為你的例子已經完成了RPC的做事方式。 默認的WebAPI路由鼓勵RESTful設置,但如果您對路由進行了微小的更改,一切都將開始工作。 例如,您可以將默認路由更改為典型的MVC路由:

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

添加路由后,以典型的MVC方式調用您使用控制器名稱和操作的內容。 但是,從你的問題來看,我懷疑你確實想要成為RESTful,而不僅僅是讓它工作所以請繼續閱讀......

保持沉默
REST 不需要HTTP ,盡管兩者經常在一起討論。 REST實際上是關於具有語義准確表示的每個資源。 使用HTTP時,這意味着尊重HTTP語義的唯一URI。 因此,例如,使用HTTP GET的調用永遠不應該修改數據,因為這違反了HTTP的GET定義和混淆HTTP基礎設施(如緩存)。

POST / PUT與MERGE / PATCH
我們都熟悉GET,POST,PUT,HEAD等作為HTTP方法。 通常 ,GET用於檢索,POST用於添加,PUT用於修改(盡管存在很多爭議)。 但是,您有兩種類型的修改:添加項目和從集合中刪除項目。 PUT還是別的什么呢? 社區還沒有完全確定如何做到這一點。

  • 選項1:自定義媒體類型 - HTTP規范確實允許所有排序方法,它是真正限制我們熟悉的子集的瀏覽器。 因此,您可以創建MERGE(Roy Fielding解決方法)或PATCH(oData work around)方法,並定義此新媒體類型的行為 - 可能是一個用於添加,另一個用於刪除。

  • 選項2:使用POST / PUT - 使用PUT添加和刪除聯系人。 只需將ID列表視為切換(如果存在則刪除,如果缺少添加)或者altatley包含足夠的信息以了解要執行的操作。 然后返回HTTP 303,指示客戶端它具有陳舊狀態並刷新。

  • 選項3:完整列表 - 如果您的設置大小合理,則每次要更新時都可以傳遞完整的聯系人列表。 這種邏輯是一種超級簡單的擦除和替換。

從RESTful角度來看,真正重要的是您的應用程序在所有方法中以一致的方式運行。 因此,如果MERGE意味着添加,它應該始終意味着添加。 如果您希望將一組完整的ID傳遞給PUT,那么總是傳遞一套完整的ID。

控制器設計
如果是我,我會把你的控制器分成多個控制器。 一個控制器處理組另一個交易聯系人(作為一個組),第三個處理一個組內的一個聯系人。 就像是 ...

//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 ),您可以查看我寫的這篇文章 恕我直言,asp.net的路由需要調整以支持嵌套更容易......但這是一個不同的問題;-)

為了回應EBarr所說的,在Web API中進行分層路由可能會有點痛苦。 我在我的服務中經常使用它,所以我為Web API構建了替換路由服務。 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的引用並進行試用。 如果您對這種路由可以走多遠感到好奇,那么這里有一個更復雜的示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM