Показаны сообщения с ярлыком Feature. Показать все сообщения
Показаны сообщения с ярлыком Feature. Показать все сообщения

Возможная проблема с хостингом сервисов

суббота, 25 апреля 2009 г.,

Ситуация: сайт размещен у хостера; сервис протестирован на ASP.NET Development Server'е; подключаем сервис к сайту и ... получаем сообщение об ошибке: "Server Error. An unhandled exception occurred during the execution of the current web request.
IIS specified authentication schemes 'IntegratedWindowsAuthentication, Basic, Anonymous', but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used".
Проблема в том, что доступ к настройкам IIS ограничен.
Пытался найти workaround ... в итоге обратился к своему провайдеру - ORCSWEB, они среагировали практически сразу, несмотря на выходной прислали письмо, цитирую: "Please let me know if you would prefer Basic Authentication over Windows authentication and I will be happy to assist you".

Примечание: Basic Authentication - это аутентификации, при которой имя пользователя и пароль передаются серверу в открытом виде.

Could not load assembly System.Web.Abstractions

пятница, 24 апреля 2009 г.,

При запуске ASP.NET MVC проекта (кажется после установки Code Contracts) получил сообщение:
Server Error in '/' Application. Configuration Error. Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately. Parser Error Message: Could not load file or assembly 'System.Web.Abstractions...'.
В web.config у System.Web.Abstractions обнаружил Version=0.0.0.0, а также System.Web.Mvc не оказалось на месте ... - мистика :)
В итоге, содержимое web.config заменил на взятое из нового проекта, и все заработало.
А еще не помешает: в контекстном меню Solution'а выбрать Clean Solution, и затем Rebuild Solution.

Парсинг HTML'а

понедельник, 20 апреля 2009 г.,

Парсить html, конечно, можно с помощью регулярных выражений (Regex), но ... например, требуется получить содержимое всех тегов, у которых атрибут id начинается с подчеркивания или заканчивается цифрой. При этом веб-сервер возвращает невалидный html, который постоянно меняется:
string html = @"Hello,
      <b id='_name'>World</b>!
      </i>
      <i id='_name'>Value1</i> Value2
      </i>
      <i id='id3'>Value3</i><i id='val'>Value4</i>
      </b>";
В такой ситуации использование регулярных выражений практически невозможно.
Решение: загрузить html в HtmlDocument.
public static IHTMLDocument2 Parse(string html)
{
    HTMLDocumentClass doc = new mshtml.HTMLDocumentClass();
    (doc as IHTMLDocument2).write("");  // чтобы создать body и ...
    MshtmlMarkupServices srv = new MshtmlMarkupServices(doc as IMarkupServicesRaw);
    var res = srv.ParseString(html);
    return res.Document;
}
С его помощью поставленная выше задача решается достаточно просто:
IHTMLDocument2 doc = Parse(html);
var linq = from tag in (doc.body.children as IHTMLElementCollection).Cast<IHTMLElement>()
           where tag.id != null && (tag.id.StartsWith("_") || char.IsDigit(tag.id[tag.id.Length-1]))
           select tag;

foreach (IHTMLElement tag in linq)
    System.Diagnostics.Trace.WriteLine(tag.innerHTML);
Для компиляции к проекту надо подключить сборки, которые входят в состав Microsoft Live Writer:
1) C:\Program Files\Windows Live\Writer\WindowsLive.Writer.Mshtml.dll;
2) C:\Program Files\Windows Live\Writer\WindowsLive.Writer.Interop.Mshtml.dll

Сборка C:\Program Files\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll не используется, потому что метод IMarkupServices.ParseString импортирован таким образом, что лишает возможности передать в него строку.

Особенность CookieContainer'а

воскресенье, 19 апреля 2009 г.,

При первом обращении к веб-сайту, например, test.ru был получен ответ:
HTTP/1.1 200 OK
Date: Thu, 16 Apr 2009 08:39:02 GMT
Set-Cookie: PathDotTest=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=.test.ru
Set-Cookie: PathTest=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=test.ru
Set-Cookie: DotTest=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; domain=.test.ru
Set-Cookie: WwwDotTest=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; domain=www.test.ru
Set-Cookie: Test=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; domain=test.ru
Set-Cookie: Path=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/;
Set-Cookie: Null=value; expires=Tue, 13-Apr-2010 23:43:04 GMT;
Set-Cookie: External=value; expires=Tue, 13-Apr-2010 23:43:04 GMT; domain=external.ru
Location: /homepage
Content-Length: 0



В HttpWebResponse.Cookies, а соответственно и в HttpWebRequest.CookieContainer окажется меньше cookie, чем указано в http-заголовках:
PathDotTest=value; expires=14.04.2010 3:43:04; path=/; domain=.test.ru
PathTest=value; expires=14.04.2010 3:43:04; path=/; domain=test.ru
DotTest=value; expires=14.04.2010 3:43:04; path=/; domain=.test.ru
Test=value; expires=14.04.2010 3:43:04; path=/; domain=test.ru
Path=value; expires=14.04.2010 3:43:04; path=/; domain=test.ru
Null=value; expires=14.04.2010 3:43:04; path=/; domain=test.ru
Два cookie: WwwDotTest и External - "пропали", т.е. не попали в контейнер. С External - понятно, это сторонний домен. А при повторном обращении к сайту:
  • адрес: http://test.ru; отправлены cookie: Path и Null.
  • адрес: http://www.test.ru; отправлены cookie: PathDotTest, PathTest, DotTest, Test
Вот такая особенность есть у CookieContainer'а, которая противоречит правилам сайтов:
  • если в cookie указан domain=test.ru, то верни cookie при запросе http://test.ru;
  • если в cookie указан domain=mail.test.ru, то верни cookie при запросе http://mail.test.ru;
  • если в cookie указан domain=.test.ru, то верни cookie при запросе http://test.ru и любого поддомена, например, http://www.test.ru или http://mail.test.ru;
  • если domain не указан, то это эквивалентно http://test.ru;

Т.е. иногда лучше самому обрабатывать http-заголовки.

Особенность HttpWebResponse.Headers

суббота, 18 апреля 2009 г.,

HTTP-ответ - это обычный текст, в котором первая строка называется строкой состояния. Под ней могут быть указаны заголовки - строки с двоеточием. Оно делит строку на две части: слева - имя заголовка, а справа - его значение.
Тело сообщения отделяется от заголовков пустой строкой. Пример HTTP-ответа:
HTTP/1.1 200 OK
Date: Thu, 16 Apr 2009 08:39:02 GMT
Set-Cookie: cname=5; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru
Set-Cookie: cvalue=5; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru
Content-Length: 9
Content-Type: text/html; charset=windows-1251

hello
Для доступа к заголовкам используется свойство HttpWebResponse.Headers типа WebHeaderCollection. Так как WebHeaderCollection наследует NameValueCollection, то можно предположить, что поведение HttpWebResponse.Headers будет соответствующим.
// пример использования NameValueCollection
NameValueCollection col1 = new NameValueCollection();
col1.Add("key1", "value1.1");
col1.Add("key2", "value2");
col1.Add("key1", "value1.2");
// в коллекции два ключа: key1 и key2
CollectionAssert.AreEquivalent(col1.AllKeys, new[] { "key1", "key2" });
// совпадают значения, возвращаемые .GetValues(int) и .GetValues(string)
var key1values = new[] { "value1.1", "value1.2" };
CollectionAssert.AreEquivalent(col1.GetValues(0), key1values);
CollectionAssert.AreEquivalent(col1.GetValues("key1"), key1values);
Но, оказывается метод HttpWebResponse.Headers.GetValue(string) работает иначе.
int index = Array.IndexOf(res.Headers.AllKeys, "Set-Cookie");
var values1 = res.Headers.GetValues(index);
//    [0]: "cname=5; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru"
//    [1]: "cvalue=5; expires=Tue, 13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru"
var values2 = res.Headers.GetValues("Set-Cookie");
//    [0]: "cname=5; expires=Tue"
//    [1]: "13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru"
//    [2]: "cvalue=5; expires=Tue"
//    [3]: "13-Apr-2010 23:43:04 GMT; path=/; domain=.getvaluetest.ru"
Причина находится в методе WebHeaderCollection.GetValue(string), где происходит нарезка строки на части по каждой запятой. Поэтому получается неожиданный результат.