Вопрос очень простой, но в основном те решения, которые я встречал сводились к созданию второго сайта. Один был рабочий, а когда его надо было обновить включали второй сайт, а первый тушили. Еще был вариант с модулем, который по ключу в конфиге включался или выключался и показывал соответствующую страницу maintenance mode.
В asp.net 2.0 появился способ сделать это удобно и красивей. Вам нужно просто создать файл с названием app_offline.htm (именно так, по другому работать не будет) и положить его в корень своего сайта, после этого asp.net будет обрубать все новые запросы, а старые нормально отработаю до очередного нового.
Когда вы закончите обновлять сайт, просто переименуйте файл или удалите его и все заработает.
По умолчанию, если размер app_offline файла меньше 512 кб, то IE будет показывать friendly error page.
Очень удобно, удачи.
понедельник, 22 марта 2010 г.
понедельник, 15 марта 2010 г.
Доделал Tomcat F14-A
На днях закончил очередную модель Tomcat F14-A (modelist). Сама модель достаточно хорошо исполнена, глубокие прорези, подгонять детали напильником особо не пришлось. Также хочется отметить качество декалей, не рвутся, накладываются легко. Единственная проблема, это то, что декали которые шли в комплекте не понятно к какой эскадрильи относятся, обычно на килях черепа или пегасы (каталог dragon 2008).
В общем я доволен, даже меняется стреловидность крыла, прикольно :)
среда, 3 марта 2010 г.
Как подружить ASP.NET AJAX Control контекст c функциями jQuery?
Когда вы пишите AJAX Enabled контролы, то в JS классе для обращения к внутренним свойствам, функциям и тп. вы используете 'this'. При использовании jQuery, при вызове метода ставиться контекст элемента, для которого вы вызываете функцию. Например в each если обратится к this, то получите текущий элемент итератора. Также используя jQuery UI, события которые срабатывают в плагинах, вызываются в контексте элемента. В общем обработчик выглядит так (для примера с draggable плагином):
Для решения нам главное пропихнуть контекст AJAX класса. Использую Function.createDelegate мы не выкрутимся, т.к. он заменят контекст вызова, в нашем случае в обработчике this будет не элемент, над которым мы отпускаем мышь, а AJAX класс и мы никак не узнаем куда дропать.
Для того чтоб пропихнуть контекст не заменяя его, нам нужен Function.createCallback. Сигнатура такая же, только смысл другой, мы не заменяем контекст, а передаем параметр не изменяя контекст. Теперь в обработчике будет добавляться параметр, который мы передаем:
$('.accept-siblings,.accept-children').droppable({
accept: 'li.leaf-draggable'
, greedy: true
, tolerance: 'pointer'
, drop: this._onDropHandler
, over: this._onDragOverHandler
, out: this._onDragOutHandler
});
_onDropHandler: function(event, ui) {
// this - будет элемент, над которым мы отпускаем мышь.
// к внутренним членам вашего ajax класса обратиться не получится.
}
Для решения нам главное пропихнуть контекст AJAX класса. Использую Function.createDelegate мы не выкрутимся, т.к. он заменят контекст вызова, в нашем случае в обработчике this будет не элемент, над которым мы отпускаем мышь, а AJAX класс и мы никак не узнаем куда дропать.
Для того чтоб пропихнуть контекст не заменяя его, нам нужен Function.createCallback. Сигнатура такая же, только смысл другой, мы не заменяем контекст, а передаем параметр не изменяя контекст. Теперь в обработчике будет добавляться параметр, который мы передаем:
this._onDropCallback = Function.createCallback(this._onDropHandler, this);
$('.accept-siblings,.accept-children').droppable({
...
, drop: this._onDropCallback
});
_onDropHandler: function(event, ui, context) {
// this - так и остается элементом над которым мы отпускаем мышь
// к членам AJAX класса можно обращаться через context. Например context.get_element();
}
четверг, 25 февраля 2010 г.
Улучшение производительности LINQ запросов. Precompiled LINQ Queries.
Одна из возможностей LINQ to SQL и LINQ to Entities это транслятор запросов, которой из программного кода переводит запрос на язык, понимаемый источником, к которому вы посылаете запрос (если речь идет о БД). Процесс преобразования вашей цепочки вызовов, например, в T-SQL не дешевая операция. Каждый раз когда вы выполняете запрос, строится дерево выражений, операций, по которым ваш провайдер, в данном случае SQLProvider, будет транслировать запрос в T-SQL.
Если у вас есть веб сервисы, который дергаются на клиенте, то хочется чтоб они выполнялись быстро, чтоб продолжить выполнение каких-то операций на клиенте. А если у вас AJAX и Rich UI, то тем более хочется чтоб отклик был как можно быстрей. Конечно, это относится не только к сервисам, а и к приложению в целом.
Если у вас есть запросы, которые выполняются часто, например GetCustomerByName, GetPostsByAuthor и тп, и вы знаете что в запросе не будут добавляться фильтры то их можно оптимизировать. Под оптимизацией я понимаю кэширование процесса построения запроса, а именно скомпилировать запрос. Другими словами вы получаете хранимую процедуру в виде LINQ запроса в которую вы просто передаете параметры.
Рассмотри пример. У вас есть форма, в который вы ищете страну, чтоб показать её на карте или тп., запрос будет выглядеть примерно так:
Компилируется запрос так:
Compile принмиает Func<>, можете передать контекст, дополнительные параметры и возвращаемый результат. Потом по коду можно использовать его так:
Если у вас web приложение можно сохранить запрос в статическую переменную. В другом случае - "шило на мыло".
Если у вас в результате запроса возвращается сложный тип (анонимный), нужно создать его проекцию, например CountryDTO.
С LINQ to SQL есть проблемы: вы не можете догрузить смежные таблицы используя один DataContext. Например у вас есть выборка по постам блога и вы хотите подтянуть авторов и коментарии, это можно сделать через DataLoadOptions. Но LoadOptions можно задать только один раз для одного экземпляра DataContext, в другом случае получите ошибку. Если вы используете DataContext атомарно для запроса, то проблем нет. Но если у вас DataContext создаете на один HttpContext - то провал. Как вариант, конкретно для методов где используется компилированый запрос, вы можете использовать DataContext атомарно.
В LINQ to Entities эта проблема решена с помощью Include, где вы можете прям в запросе указать, какие таблицы вы хотите загрузить сразу, а не по требованию.
Полезные ссылки:
Если у вас есть веб сервисы, который дергаются на клиенте, то хочется чтоб они выполнялись быстро, чтоб продолжить выполнение каких-то операций на клиенте. А если у вас AJAX и Rich UI, то тем более хочется чтоб отклик был как можно быстрей. Конечно, это относится не только к сервисам, а и к приложению в целом.
Если у вас есть запросы, которые выполняются часто, например GetCustomerByName, GetPostsByAuthor и тп, и вы знаете что в запросе не будут добавляться фильтры то их можно оптимизировать. Под оптимизацией я понимаю кэширование процесса построения запроса, а именно скомпилировать запрос. Другими словами вы получаете хранимую процедуру в виде LINQ запроса в которую вы просто передаете параметры.
Рассмотри пример. У вас есть форма, в который вы ищете страну, чтоб показать её на карте или тп., запрос будет выглядеть примерно так:
using (DBContext db = new DBContext())
{
var countries = (from country in db.Countries
where country.Name.ToLower() == key.ToLower()
select country).ToList()
// do actions with result.
}
Компилируется запрос так:
CompiledQuery.Compile<DBContext, string, IQueryable<Country>>(
(db, key) => (from country in db.Countries
where country.Name.ToLower() == key.ToLower()
select country));
Compile принмиает Func<>, можете передать контекст, дополнительные параметры и возвращаемый результат. Потом по коду можно использовать его так:
IQueryable<Country> countries = GetCountryByName.Invoke(db, txtCountry.Text);
Если у вас web приложение можно сохранить запрос в статическую переменную. В другом случае - "шило на мыло".
public Func<DBContext, string, IQueryable<Country>> GetCountryByName =
CompiledQuery.Compile<DBContext, string, IQueryable<Country>>(
(db, key) => (from country in db.Countries
where country.Name.ToLower() == key.ToLower()
select country));
Если у вас есть Repository классы, можно компилировать запрос при первом обращении. Для того чтоб код не "вонял", можно вынести запрос в отдельный класс Queries. При желании можно создать и подклассы, например Queries.Location.GetCountryByName:public static IQueryable<Country> GetCountryByName(int name)
{
if (Queries.Location.GetCountryByName == null)
{
Queries.Location.GetCountryByName =
CompiledQuery.Compile<DBContext, string, IQueryable<Country>>(
(db, key) => (from country in db.Countries
where country.Name.ToLower() == key.ToLower()
select country));
}
return Queries.Location.GetCountryByName.Invoke(_context, name);
}
Если у вас в результате запроса возвращается сложный тип (анонимный), нужно создать его проекцию, например CountryDTO.
С LINQ to SQL есть проблемы: вы не можете догрузить смежные таблицы используя один DataContext. Например у вас есть выборка по постам блога и вы хотите подтянуть авторов и коментарии, это можно сделать через DataLoadOptions. Но LoadOptions можно задать только один раз для одного экземпляра DataContext, в другом случае получите ошибку. Если вы используете DataContext атомарно для запроса, то проблем нет. Но если у вас DataContext создаете на один HttpContext - то провал. Как вариант, конкретно для методов где используется компилированый запрос, вы можете использовать DataContext атомарно.
В LINQ to Entities эта проблема решена с помощью Include, где вы можете прям в запросе указать, какие таблицы вы хотите загрузить сразу, а не по требованию.
Полезные ссылки:
среда, 24 февраля 2010 г.
Как получить параметры строки запроса в веб сервисе
Бывают ситуации, когда вы дергаете сервис с клиентской части и хотите сделать какие то вычисления учитывая параметры строки запроса, но в Request.QueryString всегда пусто.
Допустим у вас есть следующий функционал: вы можете выбрать страницу и добавить на неё какие-то виджеты. Страница будет выглядеть так - Navigation.aspx?PageId=123. На странице будет js функция, которая дергает сервис для добавления выбранного виджета.
Решение находится в строке #8. Чтоб получить строку запроса, её можно получить у страницы, с которой был вызван сервис.
Допустим у вас есть следующий функционал: вы можете выбрать страницу и добавить на неё какие-то виджеты. Страница будет выглядеть так - Navigation.aspx?PageId=123. На странице будет js функция, которая дергает сервис для добавления выбранного виджета.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class WidgetService : WebService
{
[WebMethod]
public int AddWidget(int widgetId)
{
NameValueCollection request = HttpUtility.ParseQueryString(this.Context.Request.UrlReferrer.Query);
int pageId = int.Parse(request["PageId"]);
int widgetInstanceId = AddWidgetInternal(widgetId, pageId);
return widgetInstanceId;
}
}
Решение находится в строке #8. Чтоб получить строку запроса, её можно получить у страницы, с которой был вызван сервис.
Подписаться на:
Сообщения (Atom)
