Чак Норрис
- Вопросы
- Ответы
Имя | Неизвестно |
Возраст | Неизвестно |
Сайт | Неизвестно |
Неизвестно | |
Участвует в проекте | 1105 дн., 12 час., 34 мин. |
Последняя активность | 536 дн., 21 час., 25 мин. назад |
Ответы
Перейти к вопросу →
Самый простой способ — подписаться на событие BeginRequest
в файле Global.asax и в теле обработчика выполнить все необходимые действия:
void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
string currentLocation = context.Request.Path.ToLower();
string rewritedLocation = GetRewritedLocation(currentLocation); 1
if (currentLocation != rewritedLocation)
{
context.RewritePath(rewritedLocation); 2
}
}
1 — метод GetRewritedLocation
содержит логику подмены (код не приводится);
2 — собственно, подмена URL.
Поскольку код из Global.asax сложно тестировать и повторно использовать, то лучшим решением будет реализация той же логики в http-модуле (IHttpModule). В коде модуля, как и в коде Global.asax, можно подписаться на событие начала обработки запроса и выполнить аналогичную подмену.
Перейти к вопросу →
В MSDN описано понятие Version Tolerant Serialization (VTS), которое обозначает сериализацию, «терипимую» к изменению версии.
Version Tolerant Serialization — это набор фич, включенных в .NET Framework 2.0, которые облегчают внесение изменений в сериализуемые классы. VTS доступно для классов, помеченных атрибутом
SerializableAttribute
. Благодаря VTS можно добавлять новые поля к классам без нарушения совместимости с сериализованными данными предыдущих версий. Фичи VTS работают когда используетсяBinaryFormatter
и частично работают дляSoapFormatter
.
В частности VTS позволяет добавить свойства в класс и при этом:
- старые версии приложения смогут работать с новой версией сериализованного класса, игнорируя неизвестное поле (Tolerance of Extraneous or Unexpected Data).
- новые версии приложения смогут десериализовать старые классы, задавая пропущенным свойствам значения по умолчанию (Tolerance of Missing Data).
Пункт 1 работает из коробки, а вот для пункта 2 нужно пометить соответствующее поле атрибутом OptionalFieldAttribute
:
[Serializable]
public class Customer
{
public string FirstName;
public string LastName;
[OptionalField]
public string Country;
}
Атрибут OptionalFieldAttribute
имеет свойство VersionAdded
, которое хранит порядковый номер версии файла (начиная с 2). Каждый раз при добавлении нового свойства в класс нужно помечать это поле атрибутом OptionalFieldAttribute
и указывать версию изменения.
Если при десериализации не удается найти значение какого-то из свойств/полей, то этому свойству/полю присваивается значение по умолчанию. Чтобы изменить такое поведение нужно использовать специальные атрибуты, позволяющие реагировать на события (де)сериализации:
- OnDeserializingAttribute — отмечается метод, который будет вызван перед десериализацией;
- OnDeserializedAttribute — отмечается метод, который будет вызван после десериализацией;
- OnSerializingAttribute — отмечается метод, который будет вызван перед сериализацией;
- OnSerializedAttribute — отмечается метод, который будет вызван после сериализацией;
Пример использования:
[Serializable]
public class Customer
{
public string FirstName;
public string LastName;
[OptionalField]
public string Country;
[OnDeserializing]
private void ResetCountry (StreamingContext sc)
{
Country = "Россия";
}
}
У описанного подхода есть серьезные недостатки: во-первых, он работает только с бинарной сериализацией (поправьте если тут я ошибаюсь), и во-вторых, если сериализуется сложный граф объектов, структура которого меняется от версии к версии, то средств VTS становится явно недостаточно.
Перейти к вопросу →
Fluent NHibernate предоставляет альтернативу стандартным XML-файлам конфигурации меппинга NHibernate. Вместо написания XML документов (.hbm.xml), Fluent NHibernate позволяет вам писать меппинг в строго типизированной форме, на языке C#. Это обеспечивает легкость рефакторинга, улучшает читабельность и локаничность кода.
Простой пример
Обычная конфигурация NHibernate:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="QuickStart" assembly="QuickStart">
<class name="Cat" table="Cat">
<id name="Id">
<generator class="identity" />
</id>
<property name="Name">
<column name="Name" length="16" not-null="true" />
</property>
<property name="Sex" />
<many-to-one name="Mate" />
<bag name="Kittens">
<key column="mother_id" />
<one-to-many class="Cat" />
</bag>
</class>
</hibernate-mapping>
Конфигурация с использованием Fluent NHibernate:
public class CatMap : ClassMap<Cat>
{
public CatMap()
{
Id(x => x.Id);
Map(x => x.Name)
.Length(16)
.Not.Nullable();
Map(x => x.Sex);
References(x => x.Mate);
HasMany(x => x.Kittens);
}
}
Как видно из примера, правила меппинга описываются в конструкторе класса-наследника ClassMap<>
. Для определения конкретных правил используются методы Id
, Map
, References
и тп, а также методы-расширения, позволяющие писать fluent-конструкции. Чтобы меппинг вступил в силу нужно соответствующим образом настроить SessionFactory
:
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(
SQLiteConfiguration.Standard
.UsingFile("firstProject.db")
) 1
.Mappings(m => 2
m.FluentMappings.AddFromAssemblyOf<Program>())
.BuildSessionFactory();
}
Fluent NHibernate позволяет задавать настройки источника данных 1 и указать классы меппинга 2.
Перейти к вопросу →
Правила каскадирования задаются атрибутом cascade
в конфигуровочном файле. Возможные варианты cascade:
none — не использовать никаких автоматических правил, в этом случае ответственность за целостность данных лежит на пользователе и движке БД.
save-update — когда объект сохраняется или обновляется, проверяются и создаются/обновляются все зависимые объекты (если это необходимо).
delete — при удалении объекта удаляются все ассоциированные с ним объекты.
delete-orphans - при удалении объекта удаляются все ассоциированные с ним объекты. В дополнение к этому, когда дочерний объект A
удаляется из списка ассоциированных объектов родителя B
(B.ListOfA.Remove(A)
) и не назначается другому родителю (так называемый orphaned объект), то A
также удаляется вместе с B
.
all — когда объект сохраняется, обновляется или удаляется, проверяются и создаются/обновляются/добавляются все зависимые объекты (если это необходимо). Аналогично совместному применению правил delete
и save-update
.
all-delete-orphans - когда объект сохраняется, обновляется или удаляется, проверяются и создаются/обновляются/добавляются все зависимые объекты (аналогично all
). В дополнение к этому, когда дочерний объект A
удаляется из списка ассоциированных объектов родителя B
(B.ListOfA.Remove(A)
) и не назначается другому родителю, то A
также удаляется вместе с B
.
Внимание! В разных версиях NHibernate может использоваться разное написание слова orphans (orphans или orphan). Если получаете исключение типа
Unsupported cascade style: delete-orphans
то это ваш случай.
Перейти к вопросу →
Синтаксис NVelocity идентичен Velocity для Java (за исключением расширений, поддерживаемых разными реализациями). Поэтому можно использовать те же инструменты, что и для Java версии. Например, для редактора jEdit есть простенькое расширение подсветки синтаксиса Velocity. И, конечно, есть соответствующие плагины для всех популярных Java (см Velocity and Development Tools)
Перейти к вопросу →
Есть интересный способ работы с XML. Нужно создать XSD схему для документа, затем с помощью xsd.exe сгенерировать классы, соответствующие xml-структуре. После этого можно использовать стандартный XmlSerializer для загрузки/сохранения объектов.
Перейти к вопросу →
Наверное нужно выкинуть ArgumentException
с соответствующим сообщением. Или унаследоваться от ArgumentException
и добавить туда дополнительную информацию о типе, к которому не удалось привести.
Перейти к вопросу →
Классический способ — использовать XmlDocument
Открываем файл:
XmlDocument doc = new XmlDocument();
doc.Load("test.xml");
Выбираем узлы или атрибуты, используя запросы XPath:
// Выбираем единичный узел.
XmlNode node = doc.DocumentElement.SelectSingleNode("/foo/bar");
// Выбираем все узлы по запросу.
XmlNode[] nodes = doc.DocumentElement.SelectNodes("/foo/bar");
Или обращаемся напрямую к классам XmlDocument
, XmlNode
и тп
Перейти к вопросу →
Сonvention over Сonfiguration — это принцип построения фреймворков и библиотек, призванный сократить количество требуемой конфигурации без потери гибкости. Обычно переводится как «соглашения по конфигурации». В строгой форме этот принцип можно выразить так: аспект программной системы нуждается в конфигурации тогда и только тогда, когда этот аспект НЕ удовлетворяет некоторой спецификации. Принцип работает когда речь идет о меппинге классов на какие-либо ресурсы (таблицы базы данных, события, ресурсы файловой системы). Согласно принципу, если класс соответствует соглашению наименования, тогда он не нуждается в дополнительной конфигурации. В этом контексте название принципа можно перевести как «Соглашение НАД конфигурацией», такой перевод указывает на первостепенность соглашения, а не конфигурации.
Классический пример CoC принципа — Hibernate. В Hibernate правила объектно-реляционного меппинга можно описывать с помощью XML-файлов:
<class name="Tag" table="tag">
<property name="Name" column="name"/>
<property name="Value" column="value"/>
<property name="Value2" column="value2"/>
<property name="Value3" column="value3"/>
</class>
Как видно, здесь имеются повторения свойств класса и колонок таблицы. Если ввести соглашение о том, что по умолчанию колонки таблицы должны назаваться также как свойство, то можно опустить часть конфигурации:
<class name="Tag">
<property name="Name"/>
<property name="Value"/>
<property name="Value2"/>
<property name="Value3"/>
</class>
Однако, если какое-то свойство потребуется сохранить в колонку с отличным именем, это придется указать явно. В этом и состоит суть принципа.
Наибольшее применение принцип CoC находит в среде Ruby on Rails. Это в принципе понятно, если учесть, что ror ориентирована на быструю разработку, а coc позволяет свести конфигурацию к минимуму.
Перейти к вопросу →
Скандально известная фича RenderAction. Это набор extension-методов (файл ChildActionExtensions), позволющих виду «отрисовывать» внутри себя результат работы любого экшена. Выглядит это примерно так:
<%Html.RenderAction("Controller", "Action"); %>
Как уже упоминалось, эта возможность заимствована из Ruby, откуда она была выкинута всилу своей порочности.