ФОН
У нас есть несколько ссылок на нашем сайте, которые имеют следующие форматы:
http://oursite.com/books/c_sharp_in_depth_12345.
Чтобы справиться с этим, мы используем простое свойство с именем Url
:
public class Book
{
public string Url { get; set;}
}
В основном, URL-адрес берется из домена нашего веб-сайта, раздела сайта (например, книги), названия страницы и уникального идентификатора, идентифицирующего ресурс. Полный URL хранится в базе данных.
Нам не нравится тот факт, что в нашей базе данных хранится имя раздела. Это свойство свойства веб-слоя, а не свойство книги. База данных не должна зависеть от веб-слоя.
Таким образом, мы удаляем раздел из URL и получаем следующее:
public class Book
{
public string UrlWithoutSection { get; set;}
}
ОК, это работает для этого URL. Но затем SEO-царь нашей компании говорит, что наш URL неверен и что Google, наша единственная настоящая любовь, будет любить нас, только если мы переписываем наши URL-адреса следующим образом:
http://oursite.com/programming-books/c-sharp-in-depth-12345
О-о, я думал, что мы удалили зависимость базы данных от веб-слоя, но мы этого не сделали. Оказывается, мы удалили зависимость от раздела, но формат URL все еще существует в базе данных. Мы исправляем это, абстрагируя URL в объект:
public class OurUrl
{
public string title { get; set; }
public string id { get; set; }
}
Круто, теперь зависимость от веб-слоя исчезла. О, вот на этот раз наш генеральный директор приходит к нам. Мы только что купили новую компанию, и теперь мы продаем журналы. Отлично? URL-адреса журнала будут выглядеть так:
http://oursite.com/magazines/computers/stack-overflow-the-magazine/2012/01/01/12345
ОК, нет проблем, просто создайте другой объект.
public class OurMagazineUrl : OurUrl
{
public DateTime PublishedDate { get; set; }
// Magazine enum will have to be created.
public MagazineType Type { get; set; }
}
Это работает, за исключением того, что я начинаю понимать, что у нас есть планы на большой сайт. Много URL-адресов. Много разных форматов URL. Создание нового класса каждый раз кажется большой головной болью.
проблема в ореховой скорлупе
Как вы обрабатываете URL-адреса, чтобы веб-уровень был правильно отделен от бизнес-уровня и уровня данных? У меня есть несколько мыслей о решениях:
БОЛЬШЕ О ПРОБЛЕМЕ
Я надеюсь, что это поможет прояснить некоторую путаницу.
Мы используем ASP.Net MVC. Мы используем маршруты. Мы используем помощников. Мы передаем плоские DTO нашему веб-слою, а не бизнес-объектам. Эта проблема касается уровня обслуживания и взрыва DTO.
В основном это новостной сайт с большим трафиком, а не бизнес-сайт. Он может иметь много разных URL-адресов, и URL-адреса могут меняться в любое время. Они могут быть сложными и произвольно определяться руководством.
Примеры URL (ненастоящие, составлены для примера).
1. http://oursite.com/news/wi/politics/supreme-court/recent-ruling-someid
2. http://oursite.com/news/wi/politics/election-2012/candidate-x-takes-stand-on-issue-y-someid
3. http://oursite/com/news/politics/mayor-says-things-are-a-ok-someid
4. http://oursite.com/news/milwaukee/local-bar-named-to-HOF-someid
5. http://oursite.com/news/wi/politics/supreme-court-someid
6. http://oursite.com/news/whatever-cat-our-CEO-wants/subcat1/subcat2/etc/2011/10/31/some-story-someid
Все вышеперечисленное является «статьями», и у нас есть класс Article. Статья имеет ряд навигационных свойств, таких как AuthorObject, RelatedLinksCollection и т. Д. Бизнес-объекты слишком тяжелы для передачи клиенту, поэтому мы передаем DTO, которые выравнивают информацию (например, AuthorName). Приведенные выше ссылки, однако, могут требовать разной информации, даже если они все являются «статьями».
- нужна категория, подкатегория, заголовок и идентификатор
- нужна категория, подкатегория, политикаКатегория, название и идентификатор
- нужна категория, название и идентификатор
- нужна категория, название и идентификатор
- нужна категория, подкатегория, заголовок и идентификатор
- требуется CeoCategory, CeoSubcategory, Опубликованная дата, название и идентификатор
В статических языках программирования, таких как c #, обычным способом было бы обработать это, создав отдельные классы DTO. Вы можете добавить наследование, чтобы уменьшить часть кода, но у вас все равно останется несколько классов "article" dto.
public class IArticleDto {
public string title { get; set; }
public string body { get; set; }
public string Category { get; set; }}
public class StateArticleDto: IArticleDto {
public string title { get; set; }
public string body { get; set; }
public string Category { get; set; }}
public string StateCode { get; set; }
public string Subcategory { get; set; }
}
public class SupremeCourtArticleDto: IArticleDto {
public string title { get; set; }
public string body { get; set; }
public string Category { get; set; }}
public string Subcategory { get; set; }
}
public class ArbitraryCeoArticleDto: IArticleDto {
//who knows
}
и т.д.
Возможность писать собственные URL-адреса любым возможным способом, не подлежащим обсуждению. Если статья относится к чему-либо (состояние, категория и т. Д.), Она может стать частью URL.
Решения
Продолжайте добавлять Url
объектов по мере необходимости.Как много?По крайней мере, дюжина, но назвать их будет проблематично.Выполнение одного для бизнес-объекта решает проблему с именем, но это означает, что десятки или сотни новых объектов.Гадость.
IOC - передать шаблон маршрута на уровень доступа к данным через конфигурацию.Слой доступа к данным может затем создать полный URL-адрес.Имя шаблона URL все еще является проблемой.
Используйте Dictionary<TKey, TValue>
, KeyValuePair<TKey, TValue>
и т. Д. Для ввода.
Используйте Expando
или DynamicObject
длядетали URL.Таким образом, url будет содержать несколько основных свойств (name
и id
), но при необходимости могут быть добавлены другие свойства.
Я думаю об использовании 4), потому что этопохоже, что динамическое программирование работает лучше, чем статические языки.Однако, возможно, я просто смотрю на это больше всего, потому что мне нравятся новые игрушки, с которыми я могу играть (раньше я не использовал expando).
Это лучше, чем 1) из-за взрыва объекта,Я не уверен, что 2) будет работать для сложных сценариев.Вы можете передать простое имя маршрута + информацию о маршруте на уровень данных, используя DI, но это кажется труднее сделать без дополнительного усиления.И это, вероятно, не будет работать для сложных маршрутов - для этого, я думаю, вам нужно иметь механизм правил на стороне пользовательского интерфейса.
По сравнению с 3), я думаю, что 4) немного лучше,Кто-то исправит меня, если я ошибаюсь, но динамические типы кажутся не более чем синтетическим сахаром поверх словаря, но с преимуществом более чистого кода.Просто мысль.