Thursday, June 19, 2008

IIS + SQLEXPRESS + Forms authentication + App_Data/ASPNETDB.MDF

Что-то долго я тупил пытаясь задеплоить тестовый сайтик с Forms аутенификацией на IIS.
Итак, что запомнилось:

1) если стоит vs2005 + sql server 2005 (NOT EXPRESS), тогда у меня возникала проблема с добавлением файла aspnetdb.mdf в папку app_data. выскакивало сообщение вида:
=========================================================================
Connections to SQL Server files (*.mdf) require SQL Server Express 2005
to function properly. Please verify the installation of the component or
download from the URL:
http://go.microsoft.com/fwlink/?LinkId=49251
=========================================================================

Заставить работать студию через не экспресс сервер у меня не получилось, хотя, слабо верится в то, что это невозможно. Короче решил проблему установкой экспресс сервера, тем более, что многие startup kits расчитаны именно на экспресс. Следущим после установки шагом надо поправить имя сервера в настройках студии Tools->Options->Database Tools->Data Connections->SQL Server Instance Name(blank for default): SQLEXPRESS
Должно помочь.
Еще после установки SSE(SQL Server Express) хорошо бы поменять connectionString в файле windows/microsoft.net/frameworks/v.2.0..../config/mashine.config
заменить старую строку для LocalSqlServer на новую такую:


2) если в студии все замечательно работает, страница login.aspx грузится, login контрол работает, пользователи авторизовываются, но когда переносишь сайт на IIS появляются ошибки, то надо сделать следующее:
а) в свойствах виртуальной директории дать правать на execute всей папке с сайтом + права на write папке app_data
б) дать аналогичные права пользователю aspnet на папку на винте, где лежит сам сайт
в) в web.config в membership provider задать аттрибут applicationName. я задал одно и тоже applicationName во всех провайдерах, в свойствах виртуальной директории и еще в таблице aspnet_Applications в файле ASPNETDB.MDF. Возможно это лишнее, но проверять надобность таких действий сейчас уже лень.

кусочек web.config:

    <membership defaultProvider="AspNetSqlMembershipProvider">
<providers>
<clear/>
<add
name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="LocalSqlServer"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="RemoteDeployment"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression="" />
</providers>
</membership>
<profile defaultProvider="AspNetSqlProfileProvider">
<providers>
<clear/>
<add
name="AspNetSqlProfileProvider"
connectionStringName="LocalSqlServer"
applicationName="RemoteDeployment"
type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</profile>
<roleManager enabled="true" defaultProvider="AspNetSqlRoleProvider">
<providers>
<clear/>
<add
name="AspNetSqlRoleProvider"
connectionStringName="LocalSqlServer"
applicationName="RemoteDeployment"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add
name="AspNetWindowsTokenRoleProvider"
applicationName="RemoteDeployment"
type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>



г) в SSE должен быть добавлен пользователь aspnet.
д) да!!! чуть не забыл: надо отключать базу aspnetdb.mdf в студии, если она открыта, и пытаешься логиниться через iis используя тотже aspnetdb.mdf, что уже открыт в студии. нето все будет валиться с ексепшеном:

System.Data.SqlClient.SqlException: Cannot open user default database. Login failed.
Login failed for user 'NT AUTHORITY\NETWORK SERVICE'.

для iis6 соответственно будет user 'NT AUTHORITY\ASPNET'

вроде все, что вспомнил

Wednesday, June 18, 2008

XmlDocument vs StringBuilder

Потестил перфоманс создания xml через XmlDocument и StringBuilder.
В моем приложении результаты получились такие:

XmlDocument: 0.2151
StringBuilder: 0.3114

В моем случае если записывать в Xml нечего, то надо было вернуть string.Empty. Для этого случая результаты такие:

XmlDocument: 0.00778
StringBuilder: 0.01386

кусочек кода на всякий случай:

        /// <summary>
/// Creates xml with calculated volume share values.
/// </summary>
/// <param name="suppliersData">Collection with calculated values.</param>
/// <param name="startIndex">Position of first supplier to be added into xml.</param>
/// <param name="endIndex">Position of last supplier to be added into xml.</param>
/// <returns>Xml with calculated data || empty string if there is no values to be loaded into db for specifeid portion of suppliers.</returns>
private static string GetVolumeShare(SupplierDataCollection suppliersData, int startIndex, int endIndex)
{
XmlDocument xmlDoc = new XmlDocument();
XmlNode root = xmlDoc.CreateElement("root");
for (int i = startIndex; i <= endIndex; i++)
{
SupplierData supplierData = suppliersData[i];
foreach (SupplierYearData supplierYearData in supplierData.YearVolumes)
{
foreach (SupplierCSData supplierCSData in supplierYearData.CSVolumes)
{
if (supplierCSData.CSVolumeShare > 0)
{
XmlNode child = xmlDoc.CreateElement("vs");
XmlAttribute childAttr = xmlDoc.CreateAttribute("SRMSId");
childAttr.Value = supplierData.SupplierId.ToString();
child.Attributes.Append(childAttr);
childAttr = xmlDoc.CreateAttribute("CS");
childAttr.Value = supplierCSData.CSId.ToString();
child.Attributes.Append(childAttr);
childAttr = xmlDoc.CreateAttribute("year");
childAttr.Value = supplierYearData.Year.ToString();
child.Attributes.Append(childAttr);
childAttr = xmlDoc.CreateAttribute("value");
childAttr.Value = supplierCSData.CSVolumeShare.ToString();
child.Attributes.Append(childAttr);
root.AppendChild(child);
}
}
}
}
if (root.ChildNodes.Count > 0)
xmlDoc.AppendChild(root);
string xmlData = xmlDoc.InnerXml;
return xmlData;
}

private static string GetVolumeShareXml(SupplierDataCollection suppliersData, int startIndex, int endIndex)
{
StringBuilder sbChilds = null;
for (int i = startIndex; i <= endIndex; i++)
{
SupplierData supplierData = suppliersData[i];
foreach (SupplierYearData supplierYearData in supplierData.YearVolumes)
{
foreach (SupplierCSData supplierCSData in supplierYearData.CSVolumes)
{
if (supplierCSData.CSVolumeShare > 0)
{
if (sbChilds == null)
sbChilds = new StringBuilder();
/*
sbChilds.Append(
string.Format("<vs SRMSId=\"{0}\" CS=\"{1}\" year=\"{2}\" value=\"{3}\" />",
supplierData.SupplierId,
supplierCSData.CSId,
supplierYearData.Year,
supplierCSData.CSVolumeShare
)
);
*/
sbChilds.Append("<vs SRMSId=\"");
sbChilds.Append(supplierData.SupplierId);
sbChilds.Append("\" CS=\"");
sbChilds.Append(supplierCSData.CSId);
sbChilds.Append("\" year=\"");
sbChilds.Append(supplierYearData.Year);
sbChilds.Append("\" value=\"");
sbChilds.Append(supplierCSData.CSVolumeShare);
sbChilds.Append("\" />");
}
}
}
}
StringBuilder sbRoot = null;
if (sbChilds != null)
{
sbRoot = new StringBuilder();
sbRoot.Append("<root>");
sbRoot.Append(sbChilds);
sbRoot.Append("</root>");
}
return sbRoot != null ? sbRoot.ToString() : string.Empty;
}



П.С.: замена StringBuilder на string.Format никакого эффекта не дало, как собсно я и ожидал.

AnkhSVN - неплохо, но для маленьких проектов

Опробовал нынче плагин для студии AnkhSVN. Прикольная штука, но только для маленьких проектов. Дома на всяких моих мелочах отлично работает, но вот на работе... проект в 300тыс.строк не тянет. Студия при открытии надолго подвисает. Тормозит дольше чем Resharper.