Гугл говорит, что не только я сталкивался с такой проблемой, но причина к сожалению у каждого разная. Но в результате все видят типо:
и пустой html.
Свою ошибку вы можете посмотреть в Application_Error. У меня была "The resource URL cannot be longer than 1024 characters. If using a CompositeScriptReference, reduce the number of ScriptReferences it contains, or combine them into a single static file and set the Path property to the location of it." Потому, что в в ScripMapanger\CompositeScript было много скриптов. До этого я прогнал все файлы в JSLint, но ошибок не нашел. Вот такое г..вно этот CompositeScript, лучше самому скомбинировать и перезжать на продакшен. Как-нибудь напишу решение.
четверг, 18 ноября 2010 г.
воскресенье, 24 октября 2010 г.
Как заставить браузер принудительно кэшировать картинки
Недавно сталкнулся с проблемой, когда динамически меняешь картинки жаваскриптом, то они мигают при смене первое время. Это из-за того что тратится время на загрузку по требованию. Для решения проблемы надо просто картинки подгрузить раньше на загрузке страницы, выглядит это так:
Затем можно использовать типо onmouseover="changeImage('image1');" onmouseout="changeImage();".
По идее все должно работать, но картинки все равно мигают :/ Firebug показывает, что картинки подгружены. Но тогда я увидел следующее
В запросе идет хедер, что кэшировать не надо, а в ответе нифига. Картинка просто не кэшируется и каждый раз когда я меняю src она запрашивается заново. Осталось включить кэширование картинок и вроде бы должно заработать. Настройку кэширования статического контента в IIS6 можно посмотреть здесь. Ниже показано как настроить тоже самое в IIS7.
Сначала выбираем папку с картинками (тоже самое можно сделать и для css папка), затем открываем "Заголовки ответов HTTP".
Последовательность действий сверху вниз. После нажатия OK у вас будет 3 новых вещи:
1. В папке для которой мы настраивали кеш (Img) появится web.config (его надо включить в solution).
var preloadImages = {}; preloadImages["image1"] = 'Images/image1.png'; preloadImages["image2"] = 'Images/image2.png'; ... preloadImages["image3"] = 'Images/image3.png'; preloadImages["default"] = 'Images/default.png'; function changeImage(key) { if (typeof key != 'undefined') { $('#image').attr('src', preloadImages[key]); } else { $('#image').attr('src', preloadImages["default"]); } }; (function loadImages() { for (key in preloadImages) { var img = new Image(); img.src = preloadImages[key]; } })();
Затем можно использовать типо onmouseover="changeImage('image1');" onmouseout="changeImage();".
По идее все должно работать, но картинки все равно мигают :/ Firebug показывает, что картинки подгружены. Но тогда я увидел следующее
В запросе идет хедер, что кэшировать не надо, а в ответе нифига. Картинка просто не кэшируется и каждый раз когда я меняю src она запрашивается заново. Осталось включить кэширование картинок и вроде бы должно заработать. Настройку кэширования статического контента в IIS6 можно посмотреть здесь. Ниже показано как настроить тоже самое в IIS7.
Сначала выбираем папку с картинками (тоже самое можно сделать и для css папка), затем открываем "Заголовки ответов HTTP".
Последовательность действий сверху вниз. После нажатия OK у вас будет 3 новых вещи:
1. В папке для которой мы настраивали кеш (Img) появится web.config (его надо включить в solution).
2. В заголовке ответа появится хедер Cache-Control, говорящий о том, что картинка кешируется. Даже если следующий раз браузер захочет потянуть картинку, то в firebug вы увидите в ответ на GET запрос не 200 код, а 206. Значит картинка берется из кэша.
3. Ну и 3 это результат, картинки не мигают.
вторник, 18 мая 2010 г.
Как отформатировать сжатый JS файл
Иногда для отладки или для личных нужд вам нужно выровнять сжатый JS файл, который представлен в виде строки, без отступов, пробелов, переносов и тп. Это можно сделать online - вставил, нажал, скопировал обратно (можно выставить размер отступов и тп). И там же есть ссылка на саму утилиту, она open source.
вторник, 11 мая 2010 г.
Как определить к какому пулу относиться w3wp процесс в IIS 7
Если у вас сайт развернут на IIS 7, для того чтоб его отдебажить, надо приэтачиться к процессу w3wp.exe. В одно время у вас может работать несколько сайтов и каждый может принадлежать к своему пулу. Когда вы этачитесь к процессу (рисунок ниже), то начинаем гадать, попал не попал, подсветились брейкпоинты или нет :))
Для того чтоб точно попасть, можно посмотреть, что к чему относится с помощью утилиты для администрирования IIS с командной строки - APPCMD, которая находится по пути '%systemroot%\system32\inetsrv\'. Детально можете разобраться по докам или '/?'. Нам нужно только 'WP администрирование рабочих процессов'. Пример использования и результат ниже. Мы видим ID процесса и пул к которому сайт в этом процессе относится.
Для того чтоб точно попасть, можно посмотреть, что к чему относится с помощью утилиты для администрирования IIS с командной строки - APPCMD, которая находится по пути '%systemroot%\system32\inetsrv\'. Детально можете разобраться по докам или '/?'. Нам нужно только 'WP администрирование рабочих процессов'. Пример использования и результат ниже. Мы видим ID процесса и пул к которому сайт в этом процессе относится.
пятница, 7 мая 2010 г.
Индикация прогресса при длительных операциях в ASP.NET
Я думаю вы сталкивались с ситуацией, когда нужно что-то импортить, например CSV файл с продуктами, кастомерами, синхронизировать базы или работать с каким то тормознутым веб сервисом. Во всех перечисленных и подобных случаях страница "лочится" пока не закончится операция, но нам хотелось бы видеть какой-то прогресс, о чем сегодня и поговорим.
Недавно мне нужно было импортить продукты из индусского сервиса, не важно как, главное что страница лочилась на 1-2 минуты и непонятно, что там происходило и когда оно завершалось.
Существует несколько решений как можно узнать прогресс на длительной операции:
На картинках выше показана индикация прогресса во время импорта продуктов, категорий и брендов из сервиса. Initialization показывает прогресс когда выполняется аутентификация или может создание вспомогательный классов, по вашему желанию. В мое случае я логинился на сервис. А теперь как это делалось. Для этого нам понадобится одна! страница, класс с длительной операцией, интерфейс через который будет уведомляться страница о прогрессе, пару js функций которые будут двигать прогресс бар и немного css для прогресс бара.
Методы интерфейса как я и говорил мы будет дергать из класса, который занимает длительным процессом. Ниже приведен сам класс, он примитивный, просто чтоб показать саму суть.
Клиентский функции, которые двигают прогресс бары и тп.
Вот еще кусок разметки для ясности. Весь приводить не буду, т.к. там тоже самое и немного css.
Вот и все. Основная идея в том, чтоб запустив длительный процесс сразу отдавать ответ в виде js сриптовой инъекции, которая будет обновлять прогресс. Вы можете наделать любых методов в интерфейсе. Они могут быть настолько детальными на сколько вам необходимо. В моем случае я хотел еще справа от прогресс баров добавить лог ошибок и добавил соответсвующий метод в инерфейсе ReportException, оставил для примера.
Буду рад услышать ваши идеи и отзывы.
Недавно мне нужно было импортить продукты из индусского сервиса, не важно как, главное что страница лочилась на 1-2 минуты и непонятно, что там происходило и когда оно завершалось.
Существует несколько решений как можно узнать прогресс на длительной операции:
- Сохранять прогресс в сессию, а на клиенте должен быть таймер, который после запуска длительной операции будет опрашивать страницу с какой-то периодичностью, например каждую секунду или тп. Этот метод описан здесь;
- Создать вспомогательную страницу в iframe, при запуске которой в OnLoad сразу начинается длительная операция. Во время прогресса надо писать в Response вызов JS функции, которая будет вызываться в родительском окне, с которого был запущен iframe. Этот метод описан здесь;
- Сделать страницу асинхронной, через Async или ICallbackEventHandler Interface и опять-таки через таймер опрашивать сервер. Это способ можно отнести как вариация второго.
- Потому, что надо делать вспомогательную страницу. Хоть автор и советует использовать только этот метод, но мне он кажется недоделаным.
- Потому, что както-то по индусски... опрашивать постоянно сервер? может в каком-то случае это и будет лучший вариант, но не сегодня.
- Ограниченные возможности по передаче параметров от клиента к серверу и наоборот. Можно передать, что угодно, но только в одной строке. А дальше думать формат, парсить... ну и + оргументы выше в пункте 2.
На картинках выше показана индикация прогресса во время импорта продуктов, категорий и брендов из сервиса. Initialization показывает прогресс когда выполняется аутентификация или может создание вспомогательный классов, по вашему желанию. В мое случае я логинился на сервис. А теперь как это делалось. Для этого нам понадобится одна! страница, класс с длительной операцией, интерфейс через который будет уведомляться страница о прогрессе, пару js функций которые будут двигать прогресс бар и немного css для прогресс бара.
public interface IProgressReporter { void ReportInitializationFinished(); void ReportCategoriesProgress(int count, int completed); void ReportProductsProgress(int count, int completed); void ReportBrandsProgress(int count, int completed); void ReportException(Exception exception); }
Методы интерфейса как я и говорил мы будет дергать из класса, который занимает длительным процессом. Ниже приведен сам класс, он примитивный, просто чтоб показать саму суть.
public class LongOpperations { public void ProcessCatalog(IProgressReporter progressReporter) { // some initialization, web service authentication, whatever Thread.Sleep(5000); progressReporter.ReportInitializationFinished(); for (int i = 0; i < 100; i++) { Thread.Sleep(100); progressReporter.ReportCategoriesProgress(100, i + 1); } for (int i = 0; i < 20; i++) { Thread.Sleep(200); progressReporter.ReportBrandsProgress(20, i + 1); } for (int i = 0; i < 100; i++) { Thread.Sleep(200); progressReporter.ReportProductsProgress(100, i + 1); } } }Отчетом о прогрессе выступает наша страница, для этого нужно реализовать наш интерфейс. Потом, когда вы будем стартовать длительную процедуру, мы передадим себя, страницу, в наш обработчик. В итоге получаем подобие шаблона Visitor. Самое интересное находится в методе Render. Начало ясное, если мы не нажали кнопку, то просто рендерим страницу как есть. Дальше мы должны отключить буферизацию страницы, в другом случае IE например закеширует первые 256 байт ответа и мы получим не то, что ожидали. Поэтому отключаем. Если мы после этого начнем репортить прогресс, то мы перетрем то, что существует на странице, поэтому ренедрим её как есть, а потом будет дописывать в Response наши ответы. Основная идея заключается в том, чтоб в Response записать вызов клиентской функции и сразу вывести его на страницу через Flush. Как только на странице появится script, он сразу выполнится, тем самым подвинет прогресс бары.
public partial class _Default : Page, IProgressReporter { private bool started; protected override void Render(HtmlTextWriter writer) { if (!started) { base.Render(writer); return; } Response.BufferOutput = false; base.Render(writer); Response.Flush(); ReportInitializationStarted(); new LongOpperations().ProcessCatalog(this); } protected void OnStartClick(object sender, EventArgs e) { started = true; } public void ReportInitializationStarted() { Response.Write("<script>ReportInitializationStarted();</script>"); Response.Flush(); } public void ReportInitializationFinished() { Response.Write("<script>ReportInitializationFinished();</script>"); Response.Flush(); } public void ReportCategoriesProgress(int count, int completed) { ReportProgress(pnlCategoryProgress.ClientID, lblCategory.ClientID, count, completed); } public void ReportProductsProgress(int count, int completed) { ReportProgress(pnlProductProgress.ClientID, lblProduct.ClientID, count, completed); } public void ReportBrandsProgress(int count, int completed) { ReportProgress(pnlBrandProgress.ClientID, lblBrand.ClientID, count, completed); } public void ReportException(Exception exception) { string progressCall = string.Format("<script>ReportException('{0}','{1}');</script>", exception.Message, exception.StackTrace); Response.Write(progressCall); Response.Flush(); } private void ReportProgress(string progressBar, string percentLabel, int count, int completed) { double progress = (count == 0) ? 100 : (100.0 / count) * completed; string progressCall = string.Format("<script>UpdateProgress('{0}','{1}',{2},{3},{4});</script>", progressBar, percentLabel, progress, count, completed); Response.Write(progressCall); Response.Flush(); }
Клиентский функции, которые двигают прогресс бары и тп.
function UpdateProgress(progressBarId, percentLabelId, progress, count, completed) { var progressBar = document.getElementById(progressBarId); var progressLabel = document.getElementById(percentLabelId); progressLabel.innerHTML = (progress == -1) ? '0' : completed + '/' + count; progressBar.style.width = progress + '%'; }; function ReportException(message, stack) { var p = document.createElement('p'); p.innerHTML = 'Message: ' + message + ' Stack: ' + stack; document.getElementById('error').appendChild(p); }; function ReportInitializationFinished() { var pnl = document.getElementById('pnlInitializing'); pnl.className = null; }; function ReportInitializationStarted() { var pnl = document.getElementById('pnlInitializing'); pnl.className = 'progress'; pnl.style.width = '100%' };
Вот еще кусок разметки для ясности. Весь приводить не буду, т.к. там тоже самое и немного css.
Вот и все. Основная идея в том, чтоб запустив длительный процесс сразу отдавать ответ в виде js сриптовой инъекции, которая будет обновлять прогресс. Вы можете наделать любых методов в интерфейсе. Они могут быть настолько детальными на сколько вам необходимо. В моем случае я хотел еще справа от прогресс баров добавить лог ошибок и добавил соответсвующий метод в инерфейсе ReportException, оставил для примера.
Буду рад услышать ваши идеи и отзывы.
понедельник, 22 марта 2010 г.
Способ перевести сайт в maintenance mode
Вопрос очень простой, но в основном те решения, которые я встречал сводились к созданию второго сайта. Один был рабочий, а когда его надо было обновить включали второй сайт, а первый тушили. Еще был вариант с модулем, который по ключу в конфиге включался или выключался и показывал соответствующую страницу maintenance mode.
В asp.net 2.0 появился способ сделать это удобно и красивей. Вам нужно просто создать файл с названием app_offline.htm (именно так, по другому работать не будет) и положить его в корень своего сайта, после этого asp.net будет обрубать все новые запросы, а старые нормально отработаю до очередного нового.
Когда вы закончите обновлять сайт, просто переименуйте файл или удалите его и все заработает.
По умолчанию, если размер app_offline файла меньше 512 кб, то IE будет показывать friendly error page.
Очень удобно, удачи.
В asp.net 2.0 появился способ сделать это удобно и красивей. Вам нужно просто создать файл с названием app_offline.htm (именно так, по другому работать не будет) и положить его в корень своего сайта, после этого asp.net будет обрубать все новые запросы, а старые нормально отработаю до очередного нового.
Когда вы закончите обновлять сайт, просто переименуйте файл или удалите его и все заработает.
По умолчанию, если размер app_offline файла меньше 512 кб, то IE будет показывать friendly error page.
Очень удобно, удачи.
понедельник, 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. Чтоб получить строку запроса, её можно получить у страницы, с которой был вызван сервис.
пятница, 22 января 2010 г.
Проблемы при подключении к удаленному MS SQL 2008 через SQLMS
Я поставил MS SQL 2008 Express (у меня стоит Vista) и столкнулся с проблемой, что не могу посмотреть список баз данных под любой учеткой, хоть под windows authentication, хоть под sql authentication на удаленном сервере, если подключаюсь через Management Studio. Я всегда получаю сообщение The server principal “%.*ls” is not able to access the database “%.*ls” under the current security context. Но если подключаюсь через Visual Studio, то все нормально.
Проблема не в настройке удаленного сервера, а вашего локального. На XP по умолчанию SQL Server устанавливается и запускается от учетки Network Service, которую, как оказалось, Microsoft не рекомендует использовать для запуска SQL Server под Vista. При установке эта опция стоит по умолчанию по старинке – Network Service (не понятно зачем?). Я cтавил SQL Server с дефолтными настройками. В этом и заключается вся проблема.
Решение:
Проблема не в настройке удаленного сервера, а вашего локального. На XP по умолчанию SQL Server устанавливается и запускается от учетки Network Service, которую, как оказалось, Microsoft не рекомендует использовать для запуска SQL Server под Vista. При установке эта опция стоит по умолчанию по старинке – Network Service (не понятно зачем?). Я cтавил SQL Server с дефолтными настройками. В этом и заключается вся проблема.
Решение:
- Если у вас стоит Vista или 7, то устанавливается MS SQL 2008 под учеткой LocalSystem или Build In Domain User. Если вы уже установили сервер, тогда в Sql Server Configuration Manager меняем учетку от которой будет запускаться SQL Server сервис на Local System
- Если у вас стоит XP - NetworkService.
Подписаться на:
Сообщения (Atom)