2014-12-09 4 views
0

В нашем приложении пользователи могут создавать объекты и давать им имя. Эти данные хранятся в базе данных с помощью typeId. У меня есть контроллер апи, который в настоящее время можно назвать, с именем, какКонтроллеры маршрутизации asp.net mvc

api/data 

Этот контроллер имеет базовый Get, Put, Post и удалить методы.

Теперь я хотел бы, чтобы пользователи могли вызвать этот контроллер по типу объекта. Так что, если они установки 3 различных объектов и назвать их компании, контакты и проект, я хотел бы, чтобы они были в состоянии вызвать контроллер апи/данных, используя эти имена, подобные этим

api/company 
api/contact 
api/project 

Я не знаю, что эти типы объектов unitl runtime, поэтому я не могу закодировать их вручную.

Теперь я есть и другие контроллеры, которые я не хочу, произведенное этим, так что если у меня есть нормальный контроллер называется страницу, то я все равно хочу, чтобы быть в состоянии назвать его

api/page 

Есть ли Я могу это сделать? Почти перехватите вызов контроллера, посмотрите, совпадает ли имя с именем, которое у меня есть в базе данных, и если это передать его контроллеру данных, то пусть это будет нормально работать.

ответ

0

Я думаю, вы должны

HomeController:

ActionResult Index(string name) 
{ 
// check if name exists in DB 
} 

я не видел другого способа сделать то, что вы хотите, даже путем редактирования маршрутов ... или, может быть, если вы делаете маршруты с БД, но также ...

0

Насколько вы используете контроллер 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} 
     ); 
+0

Я не знаю этих типов объектов до выполнения, поэтому я не могу их кодировать, но мне нужен способ «перенаправить» во время выполнения на основе значения. – Gillardo

+1

Знаете ли вы те, что не из db? если да, см. мой ответ. Это в основном обратный ответ. –

+1

Если вы не знаете точных имен, система не сможет найти имя метода. Вы можете преобразовать свои имена в дополнительные параметры URI и указать один специальный маршрут для этого: –

0

Вам нужно будет добавить маршрут для каждого объекта в вашей БД, или, вернее, каждый объект не из БД, и у всех остальных маршрут к путь по умолчанию. Возможно, вам захочется взглянуть на использование регулярного выражения с вашей маршрутизацией, если вы вообще можете префикс имен объектов.

+0

can not создать маршрут для всех имен, которые были созданы, поскольку пользователь может выбрать имя, хотя он не допускает пробелов. Невозможно ли перехватить вызов контроллера и «перенаправить» его на основе некоторых правил? – Gillardo

+1

В этом случае вам нужно будет сделать это в событии BeginRequest в Global.asax. У этого может быть больше информации - http://stackoverflow.com/questions/19579327/intercept-routes-before-controller-is-created –

0

Маршрутизация веб-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, ...) 
{ ... } 
0

мне удалось сделать то, что я хотите с помощью атрибута 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/ 

Надеюсь, что это поможет кому-то еще попытаться сделать что-то подобное.

Смежные вопросы