簡體   English   中英

路由控制器asp.net mvc

[英]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.

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