[英]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,則調用PutAddContacts
和PutRemoveContacts
,例如:
獲取組/ - 調用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.