Правильный подход к созданию гипермедиа в C# webapi

Я делаю некоторые исследования о том, как реализовать гипермедиа для конкретного ресурса, но не могу найти реальный пример реализации, просто абстракции...

Знаете, в разных статьях парень создавал такой метод:

public List<Link> CreateLinks(int id)
{
    ...//Here the guy put these three dots, whyyyyyyyyyy?
}

Что у меня так далеко:

public Appointment Post(Appointment appointment)
    {
        //for sake of simplicity, just returning same appointment
        appointment = new Appointment{
            Date = DateTime.Now,
            Doctor = "Dr. Who",
             Slot = 1234,
            HyperMedia = new List<HyperMedia>
            {
                new HyperMedia{ Href = "/slot/1234", Rel = "delete" },
                new HyperMedia{ Href = "/slot/1234", Rel = "put" },
            }
        };

        return appointment;
    }

И Назначение класса:

public class Appointment
{
    [JsonProperty("doctor")]
    public string Doctor { get; set; }

    [JsonProperty("slot")]
    public int Slot { get; set; }
    [JsonProperty("date")]
    public DateTime Date { get; set; }

    [JsonProperty("links")]
    public List<HyperMedia> HyperMedia { get; set; }
}

public class HyperMedia
{
    [JsonProperty("rel")]
    public string Rel { get; set; }

    [JsonProperty("href")]
    public string Href { get; set; }
}

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

Я использую C# Webapi, а не C# MVC.

2 ответа

Решение
  1. Для динамического добавления маршрутов в коллекцию HyperMedia вы можете использовать именование маршрутов:

    • Определите свой маршрут с определенным именем (например, для удаления):

      [Route("{id:int}", Name = "AppointmentDeletion")]
      public IHttpActionResult Delete(int slot)
      {
          //your code
      }
      
    • Используйте его методом UrlHelper.Link:

      public Appointment Post(Appointment appointment)
      {
          appointment = new Appointment
          {
              HyperMedia = new List<HyperMedia>
              {
                  new HyperMedia
                  { 
                      Href = Url.Link("AppointmentDeletion", new { slot = 1234 }), 
                      Rel = "delete" 
                  }
              }
      
          return appointment;
      }; 
      
  2. Также возможно динамически добавлять ссылки на результирующий объект, не объявляя свойство HyperMedia для каждого класса:

    • Определите класс без ссылок:

      public class Appointment
      {
          [JsonProperty("doctor")]
          public string Doctor { get; set; }
      
          [JsonProperty("slot")]
          public int Slot { get; set; }
      
          [JsonProperty("date")]
          public DateTime Date { get; set; }
      } 
      
    • Определите метод расширения:

      public static class LinkExtensions
      {
          public static dynamic AddLinks<T>(this T content, params object[] links)
          {
              IDictionary<string, object> result = new ExpandoObject();
      
              typeof (T)
                  .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                  .ToList()
                  .ForEach(_ => result[_.Name.ToLower()] = _.GetValue(content));
      
              result["links"] = links;
      
              return result;
          }
      }
      
    • Используй это:

      public IHttpActionResult Post(Appointment appointment)
      {
          return Ok(appointment.AddLinks(new HyperMedia
          { 
              Href = Url.Link("AppointmentDeletion", new { slot = 1234 }), 
              Rel = "delete" 
          }));
      }
      

Вы можете определенно извлечь Rel в Enum (2 на самом деле, стандартный - Delete, Put и т. д. - и пользовательский - последний может содержать пользовательские отношения, такие как customer-by-id).

Вы также можете построить Href параметры динамически (извлекают параметры из свойств объекта), но что касается самого ресурса... вы, вероятно, застряли с жестким кодированием (вы также можете посмотреть на отражение).

Другие вопросы по тегам