RBS is really ‘all or nothing’. No options for application logic :(

RBS is implemented in SQL Server and is application agnostic. That’s to say, if you turn RBS on then all BLOB objects from any SQL Server-based application will be externalized. If that’s what you want to happen then that’s great but if you need to be able to apply business logic to what is externalized and whence it goes then you are severely restricted.

http://nevertalkwhenyoucannod.typepad.com/nevertalk/2009/02/the-truth-behind-rbsis-it-really-all-or-nothing.html

Binary Content and SharePoint Performance

It looks like not only count of SharePoint objects (count of rows in the SharePoint SQL tables) affects SharePoint performance. The amount of binary contents also influences SharePoint performance based on article below.

Source: http://technet.microsoft.com/en-us/magazine/2009.06.insidesharepoint.aspx

By default, SharePoint stores BLOB data in the Content column of the AllDocStreams table in the content database. The obvious advantage of this approach is straightforward transactional consistency between relational data and the associated non-relational file contents. For example, it’s not complicated to insert the metadata of a Word document along with the unstructured content into a content database, nor is it complicated to associate metadata with the corresponding unstructured content in select, update, or delete operations. However, the most obvious disadvantage of the default approach is an inefficient use of storage resources. Despite an I/O subsystem optimized for high performance, the SQL Server storage engine is not exactly a file-server replacement.

A SQL Server database consists of transaction log and data files, as illustrated in Figure 1. In order to ensure reliable transactional behavior, SQL Server first writes all transaction records to the log file before it flushes the corresponding data in 8KB pages to the data file on disk. Depending on the selected recovery model, this requires more than twice the BLOB size in storage capacity until you perform a backup and purge the transaction log. Moreover, SQL Server does not store unstructured SharePoint content directly in data pages. Instead, SQL Server uses a separate collection of text/image pages and only stores a 16-byte text pointer to the BLOB’s root node in the data row. Text/image pages are organized in a balanced tree, yet there is only one collection of text/image pages for each table. For the AllDocStreams table, this means that the content of all files is spread across the same text/image page collection. A single text/image page can hold data fragments from multiple BLOBs, or it may hold intermediate nodes for BLOBs larger than 32KB in size.

By default, SharePoint stores BLOB data in the Content column of the AllDocStreams table in the content database. The obvious advantage of this approach is straightforward transactional consistency between relational data and the associated non-relational file contents. For example, it’s not complicated to insert the metadata of a Word document along with the unstructured content into a content database, nor is it complicated to associate metadata with the corresponding unstructured content in select, update, or delete operations. However, the most obvious disadvantage of the default approach is an inefficient use of storage resources. Despite an I/O subsystem optimized for high performance, the SQL Server storage engine is not exactly a file-server replacement.

A SQL Server database consists of transaction log and data files, as illustrated in Figure 1. In order to ensure reliable transactional behavior, SQL Server first writes all transaction records to the log file before it flushes the corresponding data in 8KB pages to the data file on disk. Depending on the selected recovery model, this requires more than twice the BLOB size in storage capacity until you perform a backup and purge the transaction log. Moreover, SQL Server does not store unstructured SharePoint content directly in data pages. Instead, SQL Server uses a separate collection of text/image pages and only stores a 16-byte text pointer to the BLOB’s root node in the data row. Text/image pages are organized in a balanced tree, yet there is only one collection of text/image pages for each table. For the AllDocStreams table, this means that the content of all files is spread across the same text/image page collection. A single text/image page can hold data fragments from multiple BLOBs, or it may hold intermediate nodes for BLOBs larger than 32KB in size.

image001

Figure 1 Default SharePoint BLOB storage in SQL Server

Let’s not dive too deeply into SQL Server internals, though. The point is that when reading unstructured content, SQL Server must go through the data row to get the text pointer and then through the BLOB’s root node and possibly additional intermediate nodes to locate all data fragments spread across any number of text/image pages that SQL Server must load into memory in full to get all data blocks. This is because SQL Server performs I/O operations at the page level. These complexities impair file-streaming performance in comparison to direct access through the file system.

Error message when you install the .NET Framework 3.5 SP1 on a computer that is running Windows SharePoint Services 2.0

Error message when you install the .NET Framework 3.5 SP1 on a computer that is running Windows SharePoint Services 2.0: "A Web Part or Web Form Control on this Web Part Page cannot be displayed or imported"

The solution from this KB http://support.microsoft.com/kb/957254 is funny. Maybe Microsoft had developed a patch for this issue since the August 29, 2008.

Common setup mistake (please do not remove generated content on upgrade)

By default, Windows Installer never deletes files it doesn’t know of (user files, generated by setup custom action files).

There are big temptation to write uninstall custom action which deletes all files to make directory clear after product deletion.

Please think about upgrade even you working on the first version of your product.

<Custom Action=”REMOVEDIRS” Before=” InstallFinalize”>REMOVE=”ALL”</Custom> – Incorrect (the product customization will be deleted on uninstall and upgrade)

<Custom Action=”REMOVEDIRS” Before=” InstallFinalize”>REMOVE=”ALL” AND NOT UPGRADINGPRODUCTCODE</Custom> – Correct (the product customization will be deleted on uninstall only. The user files and generated files will be available after upgrade).

Автоматическая генерация GUID

English: Wix Generate a GUID

В Wix есть возможность сказать компилятору, чтобы он автоматически генерил GUID для таких обьектов, как <Component>, <Package>, <Patch>,  <Product>. Я раньше думал, что для Component-а при каждой сборке будет генерится новый GUID.  Почитал на днях внимательно Wix help и обнаружил, что генерация ID Component-а базируется на значениях install directory и имени ключевого файла этой компоненты. Т.е. если эти параметры не меняются – ID будет сохраняться. Так что можно смело использовать <Component ID=”*”…./>.

Google Chrome OS

Google предлагает новый взгляд на операционную систему (OS) – не разделять понятия OS и Web. Google Chrome OS это “очень легкая” open source OS, которую, пока что, позиционируют для netbook-ов. В основе Google Chrome OS лежат три приципа: скорость, простота и security. И, важное замечание, Google Chrome OS это не Android.

based on

Как получить значение свойства в Deferred Custom Action

English: How to Transfer Properties to Deferred Custom Action
Мы можем найти следующую информацию в MSDN. Где в последнем абзаце находим простое решение. Если его перевести на Wix-код, получим следующее (синим цветом выделено решение):

—–begin of test.wxs

<?xml version='1.0'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' >
 <Product Id='{00A86C83-0000-0000-0000-2FDF0595B100}'
  Name='Property to deffered custom action'
  Language='1033'
  Version='1.0.0.0' Manufacturer='Vlasenko'
  UpgradeCode='{00E9017B-0000-0000-0000-DDDF83756800}'>
  <Package Description="Property to a deffered custom action"
   Comments="http://vlasenko.org"
   InstallerVersion="300"
   Compressed="yes"/>
  <Media Id="1"
   Cabinet="_62E9A39FD9CC4E7436F7263EBE6CDCF4"
   EmbedCab="yes" />
  <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLDIR" Name="Property to deffered custom action">
     <Component Id="first" Guid="*">
      <File Id="test" DiskId="1"
       Name="test.wxs" Source="test.wxs" KeyPath="yes" />
     </Component>
    </Directory>
   </Directory>
  </Directory>
  <Feature Id='Main' Title='Property to deffered custom action' Level='1'>
   <ComponentRef Id="first" />
  </Feature>
    
  <CustomAction Id="ShowInstallDir.SetProperty"
   Property="ShowInstallDir" Value="[INSTALLDIR]" />
  <CustomAction Id="ShowInstallDir"
   Script="vbscript" Execute="deferred">
   <![CDATA[
   Dim property
   property = Session.Property("CustomActionData")
   MsgBox property
   ]]>
  </CustomAction>
  <InstallExecuteSequence>
   <Custom Action="ShowInstallDir.SetProperty"
    Before="InstallInitialize">NOT REMOVE="ALL"</Custom>
   <Custom Action="ShowInstallDir"
    Before="InstallFinalize">NOT REMOVE="ALL"</Custom>
  </InstallExecuteSequence>
   </Product>
</Wix>

end of test.wxs—–

To get msi-file:

  1. Download and install Wix.
  2. Save code to test.wxs
  3. Execute command candle test .wxs
  4. Execute command light -out test.msi test.wixobj

В следующий раз выложу код с реальным использованием этого решения (установка Apache httpd сервиса и генерация конфигурационного файла httpd.conf во-время инсталяции).