Goodbye, ScrewTurn Wiki

June 29, 2012

Earlier this month, Dario announced the end of ScrewTurn wiki. Despite a huge number of downloads (>300.000), the project was not a financial success (read: commercial licenses did not sell well enough).

My interest in ScrewTurn Wiki started when I enabled my database versioning and documentation application dbscript to generate database documentation both into ScrewTurn 2.0 and ScrewTurn 3.0. I even experimented with a Page Storage Provider for STW 2, but dropped it later because static generation performs better than dynamic generation (read: my page provider needed a lot of CPU).

The source code will be kept on Bitbucket, but everything else will be thrown into the memory hole. What a pity.

The comments mention another .Net-based OS wiki, Road Kill, but from a first look, the download numbers are low, and there seems to be a problem storing or displaying Unicode characters in articles. I’m not convinced.

Any other .Net wikis out there?


Thou Shalt Not Update on GET

June 27, 2012

Just ending a bug-fixing session of an ASP.Net project, we came across an interesting issue:

  • The customer wanted to avoid the “post again” message when pressing the browser’s back button (scenario sketched here)
  • The web application used templates file to inject HTML code into the pages as a means to allow localization and customization by the customer
  • Some of the post-back actions should be triggered by links or buttons contained in the template files
  • Posting by mechanisms of the ASP.Net framework and implementing the Post/Redirect/Get design pattern was therefore not possible
  • Manipulation of the web site’s shopping cart had therefore been implemented as links issuing GET requests

As a consequence, when you added a product and hit the Back button to view the product again, you added it once more to the shopping cart. Clearly, this is in violation of the accepted semantics of POST and GET requests:

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered “safe”.

Not good, greetings from The Spider of Doom.

To avoid major reorganization and rewrites of the existing pages, I took a shortcut using Javascript:

function PostAndRedirect(baseurl, params) {
  $.ajax({
    type: "POST",
    url: baseurl + params,
    success: function (xhr) {            // Success
      window.location.href = baseurl;
    },
    // If any AJAX errors, alert them
    error: function (xhr, ajaxOptions, thrownError) { 
      alert(xhr.status);
      alert(thrownError);
    }
  });
}

The function PostAndRedirect takes as parameter the target (most likely current) URL and the parameters to be posted. The POST is executed using the jquery.ajax() method. If the POST is successful, the function redirects to the URL (i.e. using a GET request).

Using this function, the browser never adds the POST request to its history, and therefore would not re-post upon pressing the Back button.

To invoke the Javascript function, simply add a Javascript URL as href value:

<a href="javascript:PostAndRedirect('SomeUrl.aspx', 
    '?cmd=add&productid=SomeProductId');">

Embedding Dynamic CSS in Asp.Net

June 27, 2012

There are many questions on SO on dynamically generating or applying CSS in ASP.Net or ASP.Net MVC.

Today I accidentally found a simple way to embed dynamic CSS in an aspx file:

in the markup, add runat=”server” to the <style> tag

<style type=”text/css”runat=”server”id=”htmlCss”></style>

This will generate a field of type HtmlGenericControl in the page.

In one of the page life-cycle events (Page_Load, Page_Init, etc), assign the literal CSS definition like this:

var css = @"
body
{
  background-color:#b0c4de;
}";
htmlCss.InnerHtml = css;

Handling Exception in DotNetNuke Modules menu

June 27, 2012

For development, I use a couple of DNN 6 installations. Today I tried to import and use a newly created module, when the Modules menu displayed the following error text at the bottom:

An error has occurred.
DotNetNuke.Services.Exceptions.ModuleLoadException: An entry with the same key already exists. ---> System.ArgumentException: An entry with the same key already exists.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value)
   at DotNetNuke.Entities.Modules.DesktopModuleController.GetPortalDesktopModules(Int32 portalID)
   at DotNetNuke.Web.UI.WebControls.DnnModuleComboBox.GetPortalDesktopModules()
   at DotNetNuke.Web.UI.WebControls.DnnModuleComboBox.BindAllPortalDesktopModules()
   at DotNetNuke.UI.ControlPanel.AddModule.LoadModuleList() in c:\projects\dnn060104\admin\ControlPanel\AddModule.ascx.cs:line 395
   at DotNetNuke.UI.ControlPanel.AddModule.LoadAllLists() in c:\projects\dnn060104\admin\ControlPanel\AddModule.ascx.cs:line 327
   at DotNetNuke.UI.ControlPanel.AddModule.OnLoad(EventArgs e) in c:\projects\dnn060104\admin\ControlPanel\AddModule.ascx.cs:line 133
   --- End of inner exception stack trace ---

Digging through the DNN6 source code, I found the DesktopModuleController class in DotNetNuke_Community_06.01.04_Source \Library \Entities \Modules \DesktopModuleController.cs, where the GetPortalDesktopModules(int) method converts the results of GetPortalDesktopModulesByPortalID(int) into a SortedList<string, PortalDesktopModuleInfo>, the Add() method of which raised an exception, because a FriendlyName collision.

To find the offending modules, use SSMS to navigate to your DNN database, right-click the DesktopModules table and select “Edit top (n) records”. Press the SQL toolbar button and modify the SELECT statement to ORDER BY FriendlyName.

SELECT     TOP (200) *
FROM         DesktopModules 
ORDER BY FriendlyName

Rename one of the FriendlyName values causing the problem.

Next, update the web.config to cause DNN to reload its caches.

Problem fixed ;)


Finding Regular Expressions in Visual Studio

June 18, 2012

I needed to locate all GUID constants in a VS solution, and found this regular expression for GUIDs.

Pressing Ctrl+Shift+F, selecting “Use: Regular expression” and pasting the regex, VS would not return any results.

After cutting out the more “exotic” parts of the regex, I finally used the regular expression

([0-9a-fA-F])+-([0-9a-fA-F])+-([0-9a-fA-F])+-([0-9a-fA-F])+-([0-9a-fA-F])+

to retrieve all literal GUID strings in my C# projects.


Akismet has protected your site from 100,000 spam comments already.

June 15, 2012

One of the best inventions since bread was wrapped.

Thanks!


Fatal Error 682 when accessing MS CRM 2011

June 13, 2012

Developing a CRM 2011 application, I unexpectedly received the SqlException

Warning: Fatal error 682 occurred at [date, time]. Note the error and time, and contact your system administrator.

The complete trace entry in the MS CRM log file looks like this:

[2012-06-12 11:40:43.387] Process: w3wp |Organization:00000000-0000-0000-0000-000000000000 |Thread: 15 |Category: Platform.Sql |User: 00000000-0000-0000-0000-000000000000 |Level: Error | DynamicMetadataCacheLoader.LoadMetadataContainerFromDatabase
>Exception while loading Metadata Cache from Database with LoadMasks = All, OData using new connection and new transaction. Exception: System.Data.SqlClient.SqlException (0x80131904): Warnung: Schwerwiegender Fehler 682 um Jun 12 2012 11:40AM. Notieren Sie den Fehler und den Zeitpunkt, und wenden Sie sich an den Systemadministrator.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlDataReader.HasMoreRows()
at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
at Microsoft.Crm.CrmDataReader.Read()
at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadDescriptions(Boolean isSystemDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, TableFillPropertiesMultiOrg properties, CounterList counter)
at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadContainerData(Boolean isSystemDataLoaded, Boolean isSystemLanguageDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, List`1 fillProperties, CounterList counter)
at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.BuildMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, IDbTransaction transaction, Guid organizationId, CounterList counter)
at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, CrmTransaction transaction, Guid organizationId, CounterList counter)
[2012-06-12 11:40:43.398] Process: w3wp |Organization:00000000-0000-0000-0000-000000000000 |Thread: 15 |Category: Platform.Sdk |User: 00000000-0000-0000-0000-000000000000 |Level: Error | ServiceModelTraceRedirector.TraceData
><TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error"><TraceIdentifier>http://msdn.microsoft.com/de-DE/library/System.ServiceModel.Diagnostics.TraceHandledException.aspx</TraceIdentifier><Description>Handling an exception.</Description><AppDomain>/LM/W3SVC/2/ROOT-1-129839675491242152</AppDomain><Exception><ExceptionType>System.Data.SqlClient.SqlException, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Warnung: Schwerwiegender Fehler 682 um Jun 12 2012 11:40AM. Notieren Sie den Fehler und den Zeitpunkt, und wenden Sie sich an den Systemadministrator.</Message><StackTrace> at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
> at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
> at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
> at System.Data.SqlClient.SqlDataReader.HasMoreRows()
> at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
> at Microsoft.Crm.CrmDataReader.Read()
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadDescriptions(Boolean isSystemDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, TableFillPropertiesMultiOrg properties, CounterList counter)
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadContainerData(Boolean isSystemDataLoaded, Boolean isSystemLanguageDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, List`1 fillProperties, CounterList counter)
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.BuildMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, IDbTransaction transaction, Guid organizationId, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, CrmTransaction transaction, Guid organizationId, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadCacheFromDatabaseInternal(LoadMasks masks, CrmDbConnection connection, CrmTransaction transaction, IOrganizationContext context, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadCacheFromDatabase(LoadMasks masks, IOrganizationContext context, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheFactory.LoadMetadataCache(LoadMethod method, CacheType type, IOrganizationContext context)
> at Microsoft.Crm.Metadata.MetadataCache.LoadCache(IOrganizationContext context, Boolean fileOnlyIfExists)
> at Microsoft.Crm.Metadata.MetadataCache.GetInstance(IOrganizationContext context)
> at Microsoft.Crm.BusinessEntities.BusinessEntityMoniker..ctor(Guid id, String entityName, IOrganizationContext orgContext)
> at Microsoft.Crm.Caching.UserDataCacheLoader.LoadCacheData(Guid key, ExecutionContext context)
> at Microsoft.Crm.Caching.ObjectModelCacheLoader`2.LoadCacheData(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Caching.CrmMultiOrgCache`2.CreateEntry(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Caching.CrmMultiOrgCache`2.LookupEntry(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Authentication.UserManagementFactory.UpdateAccessTime(Guid userId, UserAuthenticationAccessType accessType, DateTime accessTime, IOrganizationContext context)
> at Microsoft.Crm.Authentication.UserManagementFactory.UpdateAccessTime(Guid userId, Guid organizationId, UserAuthenticationAccessType accessType, DateTime accessTime)
> at Microsoft.Crm.Authentication.WindowsIdentityAuthorizationManager.Authenticate(OperationContext operationContext)
> at Microsoft.Crm.Authentication.WindowsIdentityAuthorizationManager.CheckAccessCore(OperationContext operationContext)
> at System.ServiceModel.Dispatcher.AuthorizationBehavior.Authorize(MessageRpc&amp;amp; rpc)
> at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp;amp; rpc)
> at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace><ExceptionString>System.Data.SqlClient.SqlException (0x80131904): Warnung: Schwerwiegender Fehler 682 um Jun 12 2012 11:40AM. Notieren Sie den Fehler und den Zeitpunkt, und wenden Sie sich an den Systemadministrator.
> at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
> at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
> at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
> at System.Data.SqlClient.SqlDataReader.HasMoreRows()
> at System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
> at Microsoft.Crm.CrmDataReader.Read()
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadDescriptions(Boolean isSystemDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, TableFillPropertiesMultiOrg properties, CounterList counter)
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.LoadContainerData(Boolean isSystemDataLoaded, Boolean isSystemLanguageDataLoaded, CrmDbConnection connection, IDbTransaction transaction, MetadataContainer systemContainer, MetadataContainer aggregateContainer, List`1 fillProperties, CounterList counter)
> at Microsoft.Crm.Metadata.MultiOrgSharableMetadataCacheLoader.BuildMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, IDbTransaction transaction, Guid organizationId, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadMetadataContainerFromDatabase(LoadMasks masks, CrmDbConnection connection, CrmTransaction transaction, Guid organizationId, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadCacheFromDatabaseInternal(LoadMasks masks, CrmDbConnection connection, CrmTransaction transaction, IOrganizationContext context, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheLoader.LoadCacheFromDatabase(LoadMasks masks, IOrganizationContext context, CounterList counter)
> at Microsoft.Crm.Metadata.DynamicMetadataCacheFactory.LoadMetadataCache(LoadMethod method, CacheType type, IOrganizationContext context)
> at Microsoft.Crm.Metadata.MetadataCache.LoadCache(IOrganizationContext context, Boolean fileOnlyIfExists)
> at Microsoft.Crm.Metadata.MetadataCache.GetInstance(IOrganizationContext context)
> at Microsoft.Crm.BusinessEntities.BusinessEntityMoniker..ctor(Guid id, String entityName, IOrganizationContext orgContext)
> at Microsoft.Crm.Caching.UserDataCacheLoader.LoadCacheData(Guid key, ExecutionContext context)
> at Microsoft.Crm.Caching.ObjectModelCacheLoader`2.LoadCacheData(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Caching.CrmMultiOrgCache`2.CreateEntry(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Caching.CrmMultiOrgCache`2.LookupEntry(TKey key, IOrganizationContext context)
> at Microsoft.Crm.Authentication.UserManagementFactory.UpdateAccessTime(Guid userId, UserAuthenticationAccessType accessType, DateTime accessTime, IOrganizationContext context)
> at Microsoft.Crm.Authentication.UserManagementFactory.UpdateAccessTime(Guid userId, Guid organizationId, UserAuthenticationAccessType accessType, DateTime accessTime)
> at Microsoft.Crm.Authentication.WindowsIdentityAuthorizationManager.Authenticate(OperationContext operationContext)
> at Microsoft.Crm.Authentication.WindowsIdentityAuthorizationManager.CheckAccessCore(OperationContext operationContext)
> at System.ServiceModel.Dispatcher.AuthorizationBehavior.Authorize(MessageRpc&amp;amp; rpc)
> at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp;amp; rpc)
> at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</ExceptionString><DataItems><Data><Key>HelpLink.ProdName</Key><Value>Microsoft SQL Server</Value></Data><Data><Key>HelpLink.EvtSrc</Key><Value>MSSQLServer</Value></Data><Data><Key>HelpLink.EvtID</Key><Value>21</Value></Data><Data><Key>HelpLink.BaseHelpUrl</Key><Value>http://go.microsoft.com/fwlink</Value></Data><Data><Key>HelpLink.LinkId</Key><Value>20476</Value></Data></DataItems></Exception></TraceRecord>

I originally thought that something was wrong with the restored CRM database, when I found a similar bug report. The comments clearly indicated that there was a problem with (another) CRM database, rather than CRM itself.

Go to the Services control panel and stop the services accessing the MSCRM databases

  • Microsoft CRM Async Service (MSCRMAsyncService)
  • Microsoft Dynamics CRM Unzip Service (MSCRMUnzipService)
  • MS CRM Sandbox Service (MSCRMSandboxService)

and the corresponding IIS webs or the IIS service in IIS Manager.

In SSMS, execute the statement

EXEC sp_who

to find out whether there are open connections to the database causing the error.

Next, run

DBCC CHECKDB
WITH NO_INFOMSGS

to check the database for errors and consistency. Some of the results (message codes) I got were (original in German, English versions as found on the internet):

Meldung 8925, Ebene 16, Status 2, Zeile 1
Tabellenfehler: Objektquerverknüpfung: Seite (1:366305), Slot 0, in Objekt-ID 229575856, Index-ID 1, Partitions-ID 72057609057206272, Zuordnungseinheits-ID 72057594044350464 (LOB data-Typ) verweist auf Seite (1:366560), Slot 0, in Objekt-ID 229575856, Index-ID 1, Partitions-ID 2377900618270900224, Zuordnungseinheits-ID 72057594044350464 (LOB data-Typ).

Msg 8925, Level 16, State 1, Line 1
Table error: Cross object linkage: Page (1:5193082), slot 89, in object ID 1575168857, index ID 6, refers to page (1:5193939), slot 0, in object ID 1575168857, index ID 1.

Meldung 8928, Ebene 16, Status 1, Zeile 1
Objekt-ID 162815642, Index-ID 1, Partitions-ID 72057609051242496, Zuordnungseinheits-ID 72057594068992000 (LOB data-Typ): Seite (1:599672) konnte nicht verarbeitet werden. Einzelheiten finden Sie in anderen Fehlermeldungen.

Msg 8928, Level 16, State 1, Line 2 Object ID 645577338, index ID 0: Page (1:168576) could not be processed. See other errors for details.

Meldung 8929, Ebene 16, Status 1, Zeile 1
Objekt-ID 162815642, Index-ID 1, Partitions-ID 72057609051242496, Zuordnungseinheits-ID 72057609471328256 (In-row data-Typ): Es wurden Fehler in Daten außerhalb von Zeilen gefunden mit der ID 1288110080, im Besitz von data, Datensatz identifiziert durch RID = (1:1036135:0).

Msg 8929, Level 16, State 1, Line 1
Object ID 2: Errors found in text ID 852426752 owned by data record identified by RID = (1:110:19) id = 1925581898 and indid = 2.

Meldung 8939, Ebene 16, Status 98, Zeile 1
Tabellenfehler: Objekt-ID 162815642, Index-ID 1, Partitions-ID 72057609051242496, Zuordnungseinheits-ID 72057594068992000 (LOB data-Typ), Seite (1:599672). Fehler bei Test (IS_OFF (BUF_IOERR, pBUF->bstat)). Die Werte sind 12716041 und -4.

Msg 8939, Level 16, State 1, Line 2 Table error: Object ID 1797637899, index ID 0, page (1:168576). Test (m_headerVersion == HEADER_7_0) failed. Values are 0 and 1.

Meldung 8961, Ebene 16, Status 1, Zeile 1
Tabellenfehler: Objekt-ID 229575856, Index-ID 1, Partitions-ID 72057609057206272, Zuordnungseinheits-ID 72057594044350464 (Unknown-Typ). Der Datenknoten außerhalb von Zeilen auf Seite (1:366501), Slot 0, Text-ID 35185262002176 stimmt nicht mit seinem Verweis von Seite (1:366305), Slot 0 überein.

Msg 8961, Level 16, State 1, Line 1
Table error: Object ID 434100587, index ID 1, partition ID 72057594146521088, alloc unit ID 71804568277286912 (type LOB data). The off-row data node at page (1:2487), slot 2, text ID 341442560 does not match its reference from page (1:2487), slot 0.

Meldung 8965, Ebene 16, Status 1, Zeile 1
Tabellenfehler: Objekt-ID 162815642, Index-ID 1, Partitions-ID 72057609051242496, Zuordnungseinheits-ID 72057594068992000 (LOB data-Typ). Auf den Datenknoten außerhalb von Zeilen auf Seite (1:599672), Slot 0, Text-ID 1288110080 wird von Seite (1:1036135), Slot 0 verwiesen, er wurde jedoch im Scan nicht betrachtet.

Msg 8965, Level 16, State 1, Line 1
Table error: Object ID 2. The text, ntext, or image node at page (1:438), slot 3, text ID 852426752 is referenced by page (1:71), slot 4, but was not seen in the scan.

DBCC finished with the message

Von CHECKDB wurden 0 Zuordnungsfehler und 10 Konsistenzfehler in der My_MSCRM-Datenbank gefunden.
repair_allow_data_loss ist die minimale Reparaturstufe für die Fehler, die mit DBCC CHECKDB (My_MSCRM) gefunden wurden.

CHECKDB found 0 allocation errors and 29 consistency errors in database ‘My_MSCRM’.
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (My_MSCRM).

This final message tells you to run DBCC with the REPAIR_ALLOW_DATA_LOSS option. This option can only be applied if the database runs in single-user mode:

ALTER DATABASE MY_MSCRM 
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
DBCC CHECKDB ('MY_MSCRM', REPAIR_ALLOW_DATA_LOSS)
WITH NO_INFOMSGS;

If this command still lists unrecoverable errors, use the REPAIR_REBUILD option:

DBCC CHECKDB ('MY_MSCRM', REPAIR_REBUILD)
WITH NO_INFOMSGS

After completion, reset the database to multi-user mode again:

ALTER DATABASE MY_MSCRM SET MULTI_USER 
WITH ROLLBACK IMMEDIATE

Start the CRM services again, as well as the IIS web sites.


How I survived “S.M.A.R.T. Status: BAD. Backup and Replace”

June 12, 2012

My Windows 7 started to display the “Windows detected a hard disk problem” error message. While I first ignored it, I finally ran chkdsk /f /r on all disks just to make sure erroneous sectors would not cause the error to show again.

Unfortunately, this did not work out, and the error message became more persistent.

A look into the event log presented more and more warnings (Event ID 52, Source Disk)

The driver has detected that device <device> has predicted that it will fail. Immediately back up your data and replace your hard disk drive. A failure may be imminent.

and errors (Event ID 7, Source Disk)

The device, <device>, has a bad block.

(The Events and Errors Message Center does not even know these event IDs exist.)

Restarting the PC would stop the boot process with the message

S.M.A.R.T. Status: BAD. Backup and Replace
Press F1 to continue

I decided to finally bring myself to fix the situation, and asked teh internets how to do it. (I already fixed a dying drive once, but that was Ubuntu, and this is Windows, and it can get ugly.

The dying disk is a Seagate, so I tried the SeaTools (both Windows and DOS) because they might help resolve the errors, but they didn’t.

Fortunately, the new disk is also a Seagate, a different model but the same size as the old one, so I downloaded Seagate DiscWizard on my laptop to create a bootable CD. Unfortunately, DiscWizard setup requires Seagate disks installed in the PC, which the laptop does not have. Back to square one.

In the end, I mounted the new disk in the PC, installed DiscWizard, and started it. The selection of source and destination disks cause adrenaline levels to jump, but the selection dialog (of both disks) always displays the partitions of each selected disk, so the the likelihood of selecting both drives wrong due to poor UI is greatly reduced (see screenshots in the HowTo).

After disk copying completed, I disconnected the old disk and left the new disk connected on the same cable as during copying, booted, and, voilà, logged into my old new Windows 7.


Working around CRM2011 Error Message “Unable to load the plugin type”

June 6, 2012

Working on a CRM 2011 solution during a migration from CRM 4, I tried to upload the solution and watched the green progress bar reach about 80%, when the install routine decided that it’s time to rollback, and decreased the progress bar again.

The upload log showed the error message “Unable to load the plugin type”, as reported by others here and here and everywhere.

Since all my work of the day would have been lost, I tried to track down the cause of the error:

Using the Plugin Registration Tool, I saw that all the steps of one specific plugin assembly where disabled, since the assembly had not yet been upgraded to CRM 2011.

I could remove the plugin assembly from the solution I was working on, but I could not uninstall it. I figured out I had to modify the solution.zip I wanted to upload.

First, I removed the PluginAssemblies directory from the zip file.

Next, I edited solution.xml, and removed all entries starting with

      <RootComponent type="91"

as they refer to the plugin assemblies which are now removed from the zip.

Finally, I edited customization.xml, and removed the sections

  <SolutionPluginAssemblies>
    <PluginAssembly.... >
      ...
    </PluginAssembly>
  </SolutionPluginAssemblies>
  <SdkMessageProcessingSteps>
    <SdkMessageProcessingStep ...>
      ...
    </SdkMessageProcessingStep>
  </SdkMessageProcessingSteps>

After moving the two files to the solution.zip, the upload performed successfully.


Listing all DotNetNuke Pages with Settings and Permissions

June 6, 2012

To document the pages of a DNN installation, we can access the relevant tables in a DNN database:

Tabs Pages
Roles DNN Roles
Permission Permitted action
TabPermission Assignment of role privileges per page

The SQL statement consists of sub-selects to

  • concatenate the permissions for a role and a page
  • concatenate the role permissions in a page
SELECT TabID, TabName, Title, [PageHeadText], TabPath, 
  IsVisible AS InMenu,
  -- IsSecure, Url, (etc. as needed) 
  SkinSrc, ContainerSrc,
  SUBSTRING((  
    SELECT '; ' 
      + ISNULL(r.RoleName, CONVERT(NVARCHAR, tp.RoleID)) + ' [' 
      + SUBSTRING((
          SELECT ', ' + PermissionName 
          FROM TabPermission tpSub 
          INNER JOIN Permission p 
            ON p.PermissionID = tpSub.PermissionID
          WHERE tpSub.TabID = tp.TabID 
            AND tpSub.RoleID = tp.RoleID
          FOR XML PATH('')), 
        3, 1000)
      + ']'
    FROM TabPermission tp
    LEFT OUTER JOIN 
      (SELECT RoleID, RoleName FROM Roles
      UNION ALL SELECT -1, 'All Users'
      UNION ALL SELECT -2, 'Registered'
      UNION ALL SELECT -3, 'Unauthorized') r 
        ON tp.RoleID = r.RoleID

    WHERE tp.TabPermissionID IN
      (SELECT MIN(TabPermissionID) 
      FROM  TabPermission tpMin 
      WHERE tpMin.TabID = Tabs.TabID
      GROUP BY tpMin.RoleID
      )
    ORDER BY tp.RoleID
    FOR XML PATH('')), 3, 1000) AS Permissions
FROM Tabs
WHERE PortalID = 0
AND IsDeleted = 0
--AND Level = 0
ORDER BY TabPath

The negative values for RoleID are from an answer on SO.

The query result looks like this (new installation, Admin pages excluded):

TabName TabPath M. SkinSrc ContainerSrc Permissions
About Us //AboutUs 0 [G]Skins/ DarkKnight/ 2-Column-Right-Mega-Menu.ascx [G]Containers/ DarkKnight/ SubTitle_Grey.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
Collaborate Details //CollaborateDetails 0 [L]Skins/ Collaborate/ Details.ascx [L]Containers/ Collaborate/ Simple.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
Collaborate Home //CollaborateHome 0 [L]Skins/ Collaborate/ Home.ascx [L]Containers/ Collaborate/ Simple.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
Getting Started //GettingStarted 1 [G]Skins/ DarkKnight/ Home-Mega-Menu.ascx [G]Containers/ DarkKnight/ SubTitle_Grey.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
Home //Home 0 [G]Skins/ DarkKnight/ Home-Mega-Menu.ascx [G]Containers/ DarkKnight/ SubTitle_Grey.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
News & Promotions //NewsPromotions 0 [G]Skins/ DarkKnight/ 2-Column-Right-Mega-Menu.ascx [G]Containers/ DarkKnight/ SubTitle_Grey.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]
Our Services //OurServices 0 [G]Skins/ DarkKnight/ 2-Column-Right-Mega-Menu.ascx [G]Containers/ DarkKnight/ SubTitle_Grey.ascx All Users [View Tab]; Administrators [View Tab, Edit Tab]

(Some column are omitted to fit page width)

Add or remove columns and conditions as required for your purpose.


Follow

Get every new post delivered to your Inbox.