среда, января 25, 2006

Обработка обращения к IIS по "неправильному" порту.

Сильно похоже, что до web-сервера запросы вида http://server:port в случае, когда обработка такого порта на самом сервере не предусмотрена, просто не доходят.
Сообщение типа The page you are looking for is currently unavailable (вариант английского IE) формирует сам браузер. Например, русский Firefox в таких случаях сообщает: Попытка соединения не удалась. Firefox не может установить соединение с сервером server:port. У IE такая же реакция наблюдается и при обращении к заведомо несуществующему серверу (http://nonexistserver). FF при этом пытается организовать поиск при помощи Google.
 
Поэтому сделать некий универсальный обработчик таких обращений невозможно. Можно лишь сделать обработку ставших недействительными существовавших ранее обращений путём организации виртуального сервера, обрабатывающего запросы с использованием "неверного порта". При обработке можно как перенаправлять запросы, так и формировать какие-либо сообщения.
 

четверг, января 19, 2006

Очередной прикол от Sharepoint

При реализации "Удаления" записей списка в "корзину" добавил к списку поле _deleted_ типа Boolean, в который ставил признак "удаления".
Но не всё так просто, MS лёгких путей не ищет:
конструкция list.Items.GetDataTable(); иногда возвращает в этом поле DBNull, иногда и правильные значения.
В итоге пришлось сделать поле целого типа и проверять на == 1.
 
Блин.

Application settings in C# 2.0 continued

Обнаружилась засада - не может засады не быть!
 
Для проекта типа "Class Library" можно задать настройки ровно так же, как и для проекта "Application". Разница небольшая - при загрузке сборки чтения конфига не происходит. Даже принудительное перечитывание при помощи settings.Reload(); ничего не прибавляет. Модуль работает с теми значениями настроек, которые были записаны в качестве default'ных.
 
Пришлось написать процедуру считывания значений настроек.

void LoadSettings(ref object settings) {
    PropertyInfo[] props = settings.GetType().GetProperties();
   
string path = this.GetType().Assembly.Location;
   
string cfgpath=path+".config";
   
if (! File.Exists(cfgpath)) return;
   
XmlDocument cfg = new XmlDocument();
   
try {
        cfg.Load(cfgpath);
    }
catch (Exception err) {
        ....
       
return;
    }
   
foreach (PropertyInfo prop in props) {
       
if (!prop.CanWrite) continue;
       
XmlNode setting = cfg.SelectSingleNode("//setting[@name = '" + prop.Name + "']" );
       
object value = "";
        if (setting != null) {
            
try {
                value = setting.SelectSingleNode(
"value").InnerText;
               
prop.SetValue(settings, value, null);
           
} catch { }
        }
    }
}

Использование:

object osettings = new Settings();
LoadSettings(
ref osettings);
settings = (
Settings)osettings;

Примечание. При настройке параметров в VS 2005 область действия (Scope) следует установить User (иначе будет сгенерён класс Settings с readonly свойствами).

вторник, января 17, 2006

«Секретная» страница

Соорудил aspx-страницу с авторизацией.
Для каждого юзера выдаётся список предназначенных для него файлов, которые можно сгрузить.
Регулируется вот таким конфигом:

<?xml version="1.0" encoding="utf-8" ?>
<users>
<user dirs="adir" pwd="ap" name="anton">
<user dirs="*" pwd="dp" name="DkmS">
</users>


Вполне даже симпатично получилось. Заодно кой-чему научился.

воскресенье, января 15, 2006

Settins & Versions

Хорошая вещь Properties.Settings, но не до конца продуманная.
Засада - в хранении пользовательских настроек. Без всяких споров/разговоров сохраняются в файле %USERPROFILE%\Local Settings\Application Data\<Company Name>\<appdomainname>_<eid>_<hash>\<verison>\user.config .
И вот из-за этой <verison> и всё горе - используется значение атрибута assembly:AssemblyVersion , которое у меня обычно выставляется автоматом наподобие "1.0.0.*", что довольно удобно при протоколировании . Но при отладке всё, естественно, корёжится.
Пришлось начать использовать атрибут assembly:AssemblyFileVersionAttribute, который студия (Express, по меньшей мере) автоматом менять не умеет. Для получения версии исполняемого файла пользуюсь процедурой
public static string AnyVersion( Assembly assembly) {
object[] attrs=null;
try{
    attrs=assembly.GetCustomAttributes(
typeof(AssemblyFileVersionAttribute ),false);
}
catch{}
if (attrs != null && attrs.Length > 0) {
   
return ((AssemblyFileVersionAttribute)attrs[0]).Version;
}
return assembly.GetName().Version.ToString(4);
}
 
Использование - AnyVersion(Assembly.GetExecutingAssembly()) или ещё как...

четверг, января 12, 2006

Application settings in C# 2.0

Использование новых возможностей по конфигурированию приложений в VS 2005 применительно к VB.NET описано вот тут.

В C# настройка средствами VS (в т.ч. Express Edition) выполняется точно так же. Отличается, ввиду отсутствия в C# конструкции My.Settings, способ использования этих средств.

В модуле, где необходимо использовать настройки, нужно подключить пространство имён Properties:

using MyProgram.Properties;

В соответствующем классе объявить член класса:

private Settings settings = new Settings();

Поля этого класса уже можно использовать по назначению:

this.Size = settings.MainFormSize;

Замечание.

Такую же операцию следует выполнить во всех использующих настройки модулях (классах, формах и т.п.).


среда, декабря 28, 2005

Из Writely

Из C# Express через Word: с заменой абзаца на разрыв строки

/// <summary>
///
Description for XmlView.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:XmlView runat=server></{0}:XmlView>"),
XmlRoot(Namespace="XMLviewer")]
public class XmlView : Microsoft.SharePoint.WebPartPages.WebPart {
private const string defaultText = "XmlView";
private string text = defaultText;
private string xml = "";
private string xmllink = "";
private string xsl = "";
private string xsllink = "";
private Evidence evidence=null;
}


XmlWebPart & XmlView continued

Заказчику потребовалось использовать в xslt-преобразователе конструкцию <xsl:apply-templates select="document(file)..."/>
В стандартном XmlWebPart - работает. В моём XmlView - ни в какую.
При раскопках выяснилось, что загружать xsl нужно не конструкцией, которая сама напрашивается

XmlDocument xsl = new XmlDocument();
xsl.
LoadXml(xslScript); //в строке - текст xsl
XslTransform xslt =new XslTransform();
xslt.Load (new XmlNodeReader(xsl));
а немного поширше:

XmlDocument xsl = new XmlDocument();
xsl.
LoadXml(xslScript); //в строке - текст xsl
XslTransform xslt= new XslTransform();
XmlUrlResolver resolver=new XmlUrlResolver();
xslt. Load(new XmlNodeReader(xsl), resolver, XmlSecureResolver .CreateEvidenceForUrl(XslLink));
В .NET 2.0 опять по-другому:

XmlDocument xsl = new XmlDocument();
xsl.Load(
http://...test.xsl
);
XmlUrlResolver resolver=new XmlUrlResolver
();
resolver.Credentials =
CredentialCache
.DefaultNetworkCredentials;
XslCompiledTransform xslt= new XslCompiledTransform();
XsltSettings settings = new XsltSettings
();
settings.EnableDocumentFunction =
true
;
settings.EnableScript =
true
;
xslt.Load(
new XmlNodeReader
(xsl),settings,resolver);

вторник, декабря 13, 2005

Очередной прикол от Sharepoint

Фрагменты
SPList list = web.Lists[ListName];
SPListItem WholeItem = list.Items[0];
WholeItem["Viewers"] = text;
WholeItem.Update();

и

SPList list = web.Lists[ListName];
list.Items[0]["Viewers"] = text;
list.Items[0].Update();


имеют совершенно разный эффект - второй ничего никуда не пишет!

вторник, ноября 29, 2005

WSS & SPS Administrator

Утилита для курочить Шарепойнт - копирование, редактирование, добавление всяких разных элементов.

Более подробно - здесь

пятница, ноября 18, 2005

Microsoft.SharePoint.WebPartPages.XmlWebPart

Ну и штуковина! Долго пытался выяснить, что же и как она делает - полный облом. Похоже, и никто не ухитрился её в деле использовать :-(.

А всего-то и надо было - прочитать из файла xml, преобразовать его через xsl и выдать юзеру. В итоге пришлось изобретать свой аналог, который даже и работает.


четверг, ноября 17, 2005

Sharepoint Portal & .NET 2.0 continued

История не заканчивается.

Установил релиз FW .NET 2.0 (описанное ранее было с beta2) - приключения с атрибутом enableEventValidation закончились.
Обнаружилась бяка хуже - перестала работать как следует функция создания узла в портале. Сам узел создаётся, но до формирования по шаблону дело не доходит - заедает на второй странице " Добавление ссылки на узел".
В итоге в области "Узлы" ссылки на новый узел нет, при первом обращении к узлу по адресу сначала выползает форма выбора шаблонов узла.
Попробовал варианты переключения версии .net на установленном узле портала и установки на сервер с включённым вторым дотнетом - один фиг. Мелочь, но противно.

Правда, у некоторых гладко проходит - Matthew Cosier's Blog: WSS and SPS on .NET 2.0

Но у некоторых - тоже не проходит: Steven Van de Craen's Blog

суббота, ноября 05, 2005

Sharepoint notes 4.

Очередной капкан.
 
При добавлении SPFieldLookup-полей к списку list в примерах рекомендуют нечто вроде:
 
list.Fields.AddLookup(fieldName, lookupListID, fieldRequired);
SPFieldLookup newfield = list.Fields[fieldName] as SPFieldLookup
;
newfield.LookupField = lookupFieldName;
 
Всё это проходит на примерах, где поле называется Title.
 
На самом деле, приходится использовать такой код:

AddLookup(list, fieldName, lookupListID, fieldRequired, lookupFieldName);
SPFieldLookup newfield = list.Fields[fieldName] as SPFieldLookup;
 
...
 
string AddLookup(SPList list, string FieldName, Guid LookupListID, bool FieldRequired, string LookupFieldName) {
XmlDocument fxml = new XmlDocument
();
XmlElement xf = fxml.CreateElement("Field"
);
xf.SetAttribute(
"DisplayName"
, FieldName);
xf.SetAttribute(
"Type", "Lookup"
);
xf.SetAttribute(
"Required"
, FieldRequired.ToString ());
xf.SetAttribute(
"List", LookupListID.ToString("B"
));
xf.SetAttribute(
"ColName", "int1"
);
xf.SetAttribute(
"ShowField"
, LookupFieldName);

return  list.Fields.AddFieldAsXml(xf.OuterXml);

}

Sharepoint notes 3.

Опять обманули...

The Delete method of the SPFieldCollection class deletes the field with the specified display name from the collection.

public void Delete(
   string strName
);

Parameters
strName   A string that specifies the display name of the field
 
На самом деле
strName   must be InnerName.

Sharepoint notes 3.

Опять обманули...

The Delete method of the SPFieldCollection class deletes the field with the specified display name from the collection.

public void Delete(
string strName
);

Parameters
strName A string that specifies the display name of the field
На самом деле
strName must be InnerName.

пятница, ноября 04, 2005

Sharepoint notes 2.

Опять обманули...

The Add method of the SPFieldCollection class creates a field in the collection.

public string Add(
   string strDisplayName,
   Microsoft.SharePoint.SPFieldType type,
   bool bRequired
);

Return Value
A string that contains the display name of the new field.
 
На самом деле
возвращает InnerName для нового поля.

вторник, ноября 01, 2005

Sharepoint notes 1.

При добавлении пользователя в роль пытался сделать так:

role.AddUser(user);

В SDK никаких оговорок по поводу этой конструкции не видно. Исполняется молча, но ничего не добавляет :-( Работает только такая конструкция:

role.AddUser( user.LoginName, user.Email, user.Name, user.Notes + "(added by Wss Admin)");

Мелочь, но время потрачено приличное.

.NET 2.0 release

Начал какие-то исследования по использованию релиза.

Установил на втором компьютере релиз и SDK.
Попробовал собрать на нём при помощи MsBuild проект от 2005-й Студии beta 2. Собирается, и даже работает.

Скомпилил своего Wss Admin'а На 2005-й Студии. Работает как под второй бетой, так и под релизом на "сервере".
Осталось уговорить заказчика перейти на вторую версию (пусть и без Sharepoint'а пока).