[英]Routing Controllers asp.net mvc
在我們的應用程序中,用戶可以創建對象並為其命名。 此數據使用typeId存儲在數據庫中。 我有一個目前可以調用的api控制器,其名稱類似於
api/data
該控制器具有基本的Get,Put,Post和Delete方法。
現在,我希望用戶能夠按對象類型調用此控制器。 因此,如果他們設置3個不同的對象並將其稱為公司,聯系人和項目,我希望他們能夠使用這些名稱來調用api /數據控制器,類似於此
api/company
api/contact
api/project
我不知道這些對象類型是unitl運行時,所以我無法手動編碼。
現在,我還有其他我不希望受此影響的控制器,因此,如果我有一個稱為page的普通控制器,那么我仍然希望能夠通過以下方式調用它
api/page
有辦法可以做到嗎? 幾乎攔截了對控制器的調用,看看該名稱是否等於我在數據庫中擁有的名稱,如果是,則將該名稱傳遞給數據控制器,否則讓它按常規進行處理。
我想你應該
家庭控制器:
ActionResult Index(string name)
{
// check if name exists in DB
}
我什至沒有看到通過編輯路由來做您想要的事情的其他方法...或者也許您用DB做路由卻很好...
就使用api控制器而言,您可以使用RoutePrefix和Route批注。 例如:
[RoutePrefix("api")]
public class DataController : ApiController
{
[Route("company")]
public IEnumerable<CompanyViewModel> GetCompanies()
{
....
}
}
但這可能與默認路由定義沖突。 如果是這樣,請嘗試專門為此控制器定義路由:
config.Routes.MapHttpRoute(
name: "CompanyApi",
routeTemplate: "api/company/{id}",
defaults: new {controller = "DataController" , id = RouteParameter.Optional}
);
您將需要為數據庫中的每個對象添加一條路由,或者為數據庫中的每個對象添加一條路由,並將所有其他路由都路由到默認路徑。 如果您完全可以為對象名稱加上前綴,則可能要考慮在路由中使用正則表達式。
Web API路由使用穿透邏輯,因此首先要聲明您的已知路由,然后使用通用處理程序來捕獲所有其他請求並進行相應處理。 例如,在設置HttpConfiguration
時使用以下代碼:
// Define all known routes using attributes.
config.MapHttpAttributeRoutes();
// Generic route to handle all other requests
config.Routes.MapHttpRoute(
name: "DynamicRoute",
routeTemplate: "api/{dataType}",
defaults: new { controller = "data" }
);
然后,在您的DataController
您可以執行將dataType作為參數的操作:
public async Task<IHttpActionResult> Get(string dataType, ...)
{ ... }
我已經通過在控制器上使用RoutePrefix屬性和一個額外的MapRoute來完成我想要的事情,並對其施加了約束。
這是代碼,如果有人嘗試做類似的事情
首先將routePrefix添加到要調用的控制器
[RoutePrefix("api/{myCustomName}")]
public MyController : ApiController {
}
現在在我的WebApiConfig文件中,我需要添加以下行
// Web API routes
config.MapHttpAttributeRoutes();
// handle calling MyController using custom name
config.Routes.MapHttpRoute(
name: "ModuleDataApi",
routeTemplate: "api/{myCustomName}/{id}",
defaults: new { controller = "MyController" },
constraints: new { moduleType = new MyCustomRouteConstraint() }
);
現在創建檢查是否存在有效匹配的約束。 在我的代碼中,如果文本文件不存在,我將在其中填充詳細信息,並且在添加新的自定義名稱時,我將刪除/刷新此文件。 我相信,這樣做每次都會比數據庫查詢更好,因為我最多可能在這里大約有20個名稱/值對。
所以像這樣創建約束
public class MyCustomRouteConstraint : IHttpRouteConstraint
{
private DbContext _context;
private static object fileLockObject = new object();
public MyCustomRouteConstraint ()
{
_context = new DbContext();
}
public bool Match(System.Net.Http.HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
var appDataPath = System.Web.Hosting.HostingEnvironment.MapPath("~/App_Data/CustomNameRouteCache.txt");
// lock variable so no 2 or more threads can try to create file at once
lock (fileLockObject)
{
var list = new List<MyRouteModel>();
// check if our cache file exists, if not, lets create it
if (!File.Exists(appDataPath))
{
using (var writer = new System.IO.StreamWriter(appDataPath))
{
// get all modules
var names = _context.CustomNames.ToList();
foreach (var item in names)
{
list.Add(Mapper.Map<MyRouteModel>(item));
}
// serialize the list to the file in json format
var json = JsonConvert.SerializeObject(list);
// write to file
writer.Write(json);
};
}
else
{
// open file and get json contents
using (var reader = new System.IO.StreamReader(appDataPath))
{
var json = reader.ReadToEnd();
list = JsonConvert.DeserializeObject<List<MyRouteModel>>(json);
}
}
// lets search our list and see if this value is in our modules
foreach (var item in list)
{
if (item.Name.Equals(values[parameterName].ToString()))
{
return true;
}
}
}
return false;
}
}
現在,這似乎可以正常工作,我可以使用以下路徑或用戶在運行時創建的任何其他路徑來調用MyController
api/company/
api/contact/
api/project/
api/whateveryouwant/
希望這可以幫助其他嘗試做類似事情的人
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.