Cannot cache phrase for invariant language – Sitecore 8

When adding dictionary items to the CORE database in Sitecore 8, this error can occur:

Message: Cannot cache phrase for invariant language.
Source: Sitecore.Kernel
at Sitecore.Globalization.Translate.CachePhrase(String key, String phrase, Language language, DictionaryDomain domain)
at Sitecore.Globalization.ItemEventHandler.OnItemSaved(String dictionaryKey, Item item, Boolean reloadDomainCache, Boolean saveToDisk)
at … … … …

The error is related to a cached dictionary file. Sitecore caches all dictionary entries in a dictionary.dat file located in the /temp/ folder.

To solve the issue you should:

  • Delete the /temp/dictionary.dat file
  • Recycle the website

That’s it. Problem solved. Thanks to Sitecore Support for the solution.

Advertisements
Posted in Sitecore 8 | Tagged , | Leave a comment

Sitecore 8 and Engagement Plans

With the introduction of the xDB in Sitecore 7.5, Sitecore also changed the analytics API. The VisitorManager have been replaced by the Tracker.

The Tracker is one of the base API’s for Sitecore the new Sitecore Experience Platform (the new name for Sitecore DMS, which was the new name for Sitecore OMS – do you follow me?) and the API handles the tracking of users in Sitecore.

For automatic engagement plan handling, this means that instead of using the VisitorManager to enroll users in your engagement plan, you use the Tracker and the AutomationStateManager:

using System.Linq;
using Sitecore.Analytics;
using Sitecore.Analytics.Automation.Data;
using Sitecore.Analytics.Automation.MarketingAutomation;
using Sitecore.Data.Items;

public void AddUserToEngagementPlan(string user, Item engagementPlan)
{
  Tracker.Current.Session.Identify(user);
  AutomationStateManager manager = Tracker.Current.Session.CreateAutomationStateManager();
  manager.EnrollInEngagementPlan(engagementPlan.ID, engagementPlan.Children.First().ID);
}

Parameter user is the complete username with domain (for example extranet\bp). The engagementPlan is the engagementPlan item.

The remove a user from an engagement plan you simply call RemoveFromEngagementPlan:

public void RemoveUserFromEngagementPlan(string user, Item engagementPlan)
{
  Tracker.Current.Session.Identify(user);
  AutomationStateManager manager = Tracker.Current.Session.CreateAutomationStateManager();
  manager.RemoveFromEngagementPlan(engagementPlan.ID);
}

Thanks to Alin Parjolea for the code.

MORE TO READ:

Posted in c#, General .NET, Sitecore, Sitecore 8 | Tagged , , , , , | 1 Comment

Sitecore Job Viewer – see what Sitecore is doing in the background

This simple .aspx page has become one of my most used tools when working with Sitecore. It’s a job viewer, displaying which jobs are running and which jobs are finished:

Job Viewer

Sitecore Job Viewer

A Sitecore job is a thread running in the background. Jobs can run in parallel or in sequence: Jobs that share the same name are queued and executed in the order they arrived.

Getting a list of all jobs are pretty simple. This returns the jobs sorted by the time they were added to the queue:

public IEnumerable<Sitecore.Jobs.Job> Jobs
{
  get
  {
    return Sitecore.Jobs.JobManager.GetJobs().OrderBy(job => job.QueueTime);
  }
}

For each job you can extract all information about the job you need. My application lists the most used data, and when you hover the mouse over one line, it displays more info, including who started the job, and all messages added to the job:

Job Details

Job Details

All of this in a simple .aspx page that can be uploaded to the /sitecore modules/shell/ folder on an ad-hoc basis to see what the heck Sitecore is doing.

The code is simple. Copy it from here, paste it into a jobs.aspx page and upload the thing to your Sitecore.

<%@ Page language="c#" EnableEventValidation="false" AutoEventWireup="true" %>

<script runat="server">

  void Page_Load(object sender, System.EventArgs e)
  {
    repJobs.DataBind();
  }

  public IEnumerable<Sitecore.Jobs.Job> Jobs
  {
    get
    {
      if (!cbShowFinished.Checked)
        return Sitecore.Jobs.JobManager.GetJobs().Where(job => job.IsDone == false).OrderBy(job => job.QueueTime);
      return Sitecore.Jobs.JobManager.GetJobs().OrderBy(job => job.QueueTime);
    }
  }

  protected string GetJobText(Sitecore.Jobs.Job job)
  {
    return string.Format("{0}\n\n{1}\n\n{2}", job.Name, job.Category, GetJobMessages(job));
  }

  protected string GetJobMessages(Sitecore.Jobs.Job job)
  {
    System.Text.StringBuilder sb = new StringBuilder();
    if (job.Options.ContextUser != null)
      sb.AppendLine("Context User: " + job.Options.ContextUser.Name);
    sb.AppendLine("Priority: " + job.Options.Priority.ToString());
    sb.AppendLine("Messages:");
    foreach (string s in job.Status.Messages)
      sb.AppendLine(s);
    return sb.ToString();
  }

  protected string GetJobColor(Sitecore.Jobs.Job job)
  {
    if (job.IsDone)
      return "#737373";
    return "#000";
  }

  protected void cbShowFinished_CheckedChanged(object sender, EventArgs e)
  {
    repJobs.DataBind();
  }
</script>  

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
  <head>
    <title>Job Viewer</title>
    <link href="/default.css" rel="stylesheet">
  </head>
  <body style="font-size:14px">
    <form runat="server">

      <div style="padding:10px; background-color:#efefef; border-bottom:solid 1px #aaa; border-top:solid 1px white">
        <div style="float:left; width:200px; padding-top:4px">
          <asp:CheckBox ID="cbShowFinished" runat="server" Text="Show finished jobs" Checked="false" OnCheckedChanged="cbShowFinished_CheckedChanged" AutoPostBack="true" />
        </div>
        <div style="float:right;">
          <asp:Button ID="btnRefresh" runat="server" Text="Refresh" BackColor="Green" ForeColor="White" Width="100px" Height="30px" />
        </div>
        <div style="clear:both;height:1px">&nbsp;</div>
      </div>

      <div style="padding-top:0px">
        <asp:Repeater ID="repJobs" runat="server" DataSource="<%# Jobs %>">
          <HeaderTemplate>
            <table style="width:100%">
              <thead style="background-color:#eaeaea">
                <td>Job</td>
                <td>Category</td>
                <td>Status</td>
                <td>Processed</td>
                <td>QueueTime</td>
              </thead>
          </HeaderTemplate>
          <FooterTemplate>
            </table>
          </FooterTemplate>
          <ItemTemplate>
            <tr style="background-color:beige; color:<%# GetJobColor((Container.DataItem as Sitecore.Jobs.Job)) %>" title="<%# GetJobText((Container.DataItem as Sitecore.Jobs.Job)) %>">
              <td>
                <%# Sitecore.StringUtil.Clip((Container.DataItem as Sitecore.Jobs.Job).Name, 50, true) %>
              </td>
              <td>
                <%# Sitecore.StringUtil.Clip((Container.DataItem as Sitecore.Jobs.Job).Category, 50, true) %>
              </td>
              <td>
                <%# (Container.DataItem as Sitecore.Jobs.Job).Status.State %>
              </td>
              <td>
                <%# (Container.DataItem as Sitecore.Jobs.Job).Status.Processed %> /
                <%# (Container.DataItem as Sitecore.Jobs.Job).Status.Total %>
              </td>
              <td>
                <%# (Container.DataItem as Sitecore.Jobs.Job).QueueTime.ToLocalTime() %>
              </td>
            </tr>
          </ItemTemplate>
        </asp:Repeater>
      </div>

    </form>
  </body>
</html>

MORE TO READ:

Posted in c#, Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8 | Tagged , , , | 5 Comments

Sitecore EventQueue deadlocks – how to solve them and how to avoid them

The Sitecore 7.0+ EventQueue mechanism can in some rare occurrences cause a deadlock to occur.

You will notice that when it happens, your Sitecore Shell will come to a complete halt, the DMS becomes unresponsive, and you experience SQL timeout exceptions. Sitecore resumes when the deadlock is solved.

HOW TO SOLVE THEM

You will need SQL Server admin access to solve them. Open SQL Management Studio, go to the CORE database and run the following:

SELECT
db.name DBName,
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
tl.resource_type,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingTest,
tl.request_mode
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
GO

When the script has run, you will get some output like this:

Deadlocks in EventQueue

Deadlocks in EventQueue

The blocking_session_id is the session id that causes the deadlock. You need to kill the blocking session. Run the kill command in the SQL Management Studio:

kill 205;
kill 62;

Voila, the deadlock is gone.

WHO CAUSED THE DEADLOCK?

Well, lets see. Run the following SQL statement:

SELECT
spid,
status,
loginame=SUBSTRING(loginame,1,40),
hostname=SUBSTRING(hostname,1, 40),
blk = CONVERT(char(3), blocked),
dbname=SUBSTRING(DB_NAME(dbid),1, 40),
cmd,
waittype

FROM master.dbo.sysprocesses
WHERE spid IN (SELECT blocked FROM master.dbo.sysprocesses)

The output reveals the sinner:

Who caused the deadlock?

Who caused the deadlock?

Oops, looks like I am causing the deadlock myself.

HOW CAN I AVOID DEADLOCKS?

Deadlocks have a tendency to occur in multi-server environments (obviously, since the EventQueue is used to communicate between servers). They also have a tendency to occur in multi-developer enenvironmentswhere several developers use the same SQL server.

1) Check the EventQueue size

Deadlocks occur if your EventQueue is too large. Make sure you clean the EventQueue often and keep as little data as possible, preferably below 1000 items. The CleanupEventQueue task will help you:

<agent type="Sitecore.Tasks.CleanupEventQueue, Sitecore.Kernel" method="Run" interval="04:00:00">
    <DaysToKeep>1</DaysToKeep>
</agent>

2) Let your CM server do the publishing

Most of the EventQueue contents is publish information. If possible, your architecture should allow on the CM server to publish. The CD servers should not.

3) Have enough power in the server rack

Deadlocks occur more often on heavily loaded environments, because the insert and select statements will be slower. Make sure you do not constantly run out of CPU or memory on your web and SQL servers.

MORE TO READ:

Posted in Sitecore 7 | Tagged , , | 1 Comment

Measuring Sitecore performance with HighResTimer

The HighResTimer is a Sitecore feature that has been around since Sitecore 4. It’s a simple timer that allows you to very precisely measure time in microseconds by using the underlying OS timers.

It is very easy to use:

public void MyMethod()
{
  // Initialize and start the timer:
  Sitecore.Diagnostics.HighResTimer ht = new Sitecore.Diagnostics.HighResTimer();
  ht.Start();
  try
  {
    // execute the code to be timed.
  }
  finally
  {
    // Dump the elapsed timespan to the log:
    Sitecore.Diagnostics.Log.Info("Time elapsed: " + ht.ElapsedTimeSpan.ToString(), this);
  }
}

The HighResTimer allows you to read the number of milliseconds or as I do in this example, read the time elapsed with a precision of 7 digits. The log line from the above example looks like this:

10112 12:25:28 INFO  Time elapsed: 00:00:00.0073862

More to read:

Posted in General .NET, Sitecore 4, Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8 | Tagged , , | 1 Comment

Sitecore and xDB – Setting up MongoDB on your developer machine

With Sitecore 7.5, Sitecore introduces xDB – the new MongoDB based DMS database. But before you say “oh no, yet another technology I have to deal with”, you should know that working with MongoDB is very easy. In fact it is easier than working with SQL Server.

STEP 1: DOWNLOAD MONGODB

Go to http://www.mongodb.org/downloads and download the 64 bit .zip file. Unzip the files in a directory on your computer.
I installed mine at c:\mongodb

STEP 2: SET UP THE SITECORE CONNECTIONSTRINGS.CONFIG

It is very likely that the Sitecore 7.5 (and Sitecore 8.x) connectionstrings.config are already set up correctly. If not look for the following lines, they need to point to your local machine:

<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
  <!--
    Sitecore connection strings.
    All database connections for Sitecore are configured here.
  -->
  ...
  ...
  ...
  <add name="analytics" connectionString="mongodb://localhost/analytics" />
  <add name="tracking.live" connectionString="mongodb://localhost/tracking_live" />
  <add name="tracking.history" connectionString="mongodb://localhost/tracking_history" />
  ...
</connectionStrings>

STEP 3: CREATE A .BAT FILE TO START UP MONGO

To start up mongo you need to run mongod.exe with a parameter determining where Mongo should put the database files. Create a .bat file with the following contents:

c:\MongoDB\bin\mongod.exe –dbpath “[yourfilepath]”

Replace c:\MongoDB\bin\ with the path to your Mongo files, and [yourfilepath] with the path to the folder where you would like to put your MongoDB databases.

You will need one .bat file for each of your Sitecore projects, as you would like to store a separate set of files per Sitecore.

STEP 4: START SITECORE AND ENJOY LIFE

To start up Sitecore, you run the .bat file and fire up your Sitecore and you are now running Sitecore with xDB on a local instance.

Sitecore 8 technical preview with MongoDB running

Sitecore 8 technical preview with MongoDB running

MORE TO READ:

 

 

Posted in Sitecore 8 | Tagged , , , | 18 Comments

Improve Sitecore Membership provider performance 2-20 times

The Sitecore Membership provider is built on top of the default .NET membership provider. The .NET membership provider is not known to be the fastest provider available. Sure, if you have a few thousand users in your database it performs well, but if you have, say, 50.000 or even 500.000 users, the provider becomes painfully slow.

500.000 users in Sitecore

500.000 users in Sitecore

But before you start rewriting the whole thing, there is a couple of things you can do to dramatically improve performance.

I would like to thank Ulrich Kronvold, Kristian Magius, Sergey Marchenko, Ivan Sheyenko and everyone that have been involved in getting these SQL scripts. None of the scripts are my own, but I think they are too good to keep for myself.

MODIFY STORED PROCEDURE [dbo].[aspnet_Membership_GetAllUsers] 

This script modifies the [dbo].[aspnet_Membership_GetAllUsers] stored procedure to select values based on indexed fields:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER OFF
GO

ALTER PROCEDURE [dbo].[aspnet_Membership_GetAllUsers]
    @ApplicationName       nvarchar(256),
    @PageIndex             int,
    @PageSize              int
AS
BEGIN

    DECLARE @ApplicationId uniqueidentifier
    SELECT  @ApplicationId = NULL
    SELECT  @ApplicationId = ApplicationId FROM dbo.aspnet_Applications WHERE LOWER(@ApplicationName) = LoweredApplicationName
    IF (@ApplicationId IS NULL)
        RETURN 0

    -- Set the page bounds
    DECLARE @PageLowerBound int
    DECLARE @PageUpperBound int
    DECLARE @TotalRecords   int
    SET @PageLowerBound = @PageSize * @PageIndex
    SET @PageUpperBound = @PageSize - 1 + @PageLowerBound

    -- Create a temp table TO store the select results
    /* DSZ
    CREATE TABLE #PageIndexForUsers
    (
        IndexId int IDENTITY (0, 1) NOT NULL,
        UserId uniqueidentifier
    )

    -- Insert into our temp table
    INSERT INTO #PageIndexForUsers (UserId)
    SELECT u.UserId
    FROM   dbo.aspnet_Membership m, dbo.aspnet_Users u
    WHERE  u.ApplicationId = @ApplicationId AND u.UserId = m.UserId
    ORDER BY u.UserName
    */

    SELECT @TotalRecords = COUNT(u.UserId)
    FROM dbo.aspnet_Membership m (NOLOCK), dbo.aspnet_Users u (NOLOCK)
    WHERE u.ApplicationId = @ApplicationId AND u.UserId = m.UserId

    SELECT
                u.UserName,
                m.Email,
                m.PasswordQuestion,
                m.Comment,
                m.IsApproved,
                m.CreateDate,
                m.LastLoginDate,
                u.LastActivityDate,
                m.LastPasswordChangedDate,
                u.UserId,
                m.IsLockedOut,
                m.LastLockoutDate
    FROM
                (SELECT
                        ROW_NUMBER() OVER (ORDER BY u.UserName) AS IndexId,
                        u.UserName
                FROM dbo.aspnet_Membership m (NOLOCK), dbo.aspnet_Users u (NOLOCK)
                        WHERE u.UserId = m.UserId AND u.ApplicationId = @ApplicationId AND m.ApplicationId = @ApplicationId)
                AS p INNER JOIN dbo.aspnet_Users u ON u.UserName = p.UserName INNER JOIN dbo.aspnet_Membership m ON m.UserId = u.UserId
        WHERE
                IndexId &gt;= @PageLowerBound AND IndexId &lt;= @PageUpperBound
    --ORDER BY UserName
    RETURN @TotalRecords
END

MODIFY STORED PROCEDURE [dbo].[aspnet_Membership_GetUserByEmail]

This script modifies the stored procedure [dbo].[aspnet_Membership_GetUserByEmail] to select fields based on indexed values:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[aspnet_Membership_GetUserByEmail]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[aspnet_Membership_GetUserByEmail]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER OFF
GO

CREATE PROCEDURE [dbo].[aspnet_Membership_GetUserByEmail]
    @ApplicationName  nvarchar(256),
    @Email            nvarchar(256)
AS
BEGIN
    IF( @Email IS NULL )
        SELECT  u.UserName
        FROM    dbo.aspnet_Applications a, dbo.aspnet_Users u, dbo.aspnet_Membership m
        WHERE   LOWER(@ApplicationName) = a.LoweredApplicationName AND
                u.ApplicationId = a.ApplicationId    AND
                u.UserId = m.UserId AND
                m.LoweredEmail IS NULL
    ELSE
        SELECT  u.UserName
        FROM    dbo.aspnet_Applications a, dbo.aspnet_Users u, dbo.aspnet_Membership m
        WHERE   LOWER(@ApplicationName) = a.LoweredApplicationName AND
                u.ApplicationId = a.ApplicationId    AND
                u.UserId = m.UserId AND
                LOWER(@Email) = m.LoweredEmail AND u.ApplicationId = m.ApplicationId

    IF (@@rowcount = 0)
        RETURN(1)
    RETURN(0)
END
GO

CREATE NEW INDEX [aspnet_Membership_index]

This script creates a clustered index on fields ApplicationID, LoweredEmail and UserID used by the 2 stored procedures above:

IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[aspnet_Membership]') AND name = N'aspnet_Membership_index')
DROP INDEX [aspnet_Membership_index] ON [dbo].[aspnet_Membership] WITH ( ONLINE = OFF )
GO

CREATE CLUSTERED INDEX [aspnet_Membership_index] ON [dbo].[aspnet_Membership] 
(
	[ApplicationId] ASC,
	[LoweredEmail] ASC,
	[UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NEW INDEX [aspnet_Users_Index]

This script creates a new clustered index on fields ApplicationID, LoweredUserName and UserID used by the 2 stored procedures above:

IF  EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[aspnet_Users]') AND name = N'aspnet_Users_Index')
DROP INDEX [aspnet_Users_Index] ON [dbo].[aspnet_Users] WITH ( ONLINE = OFF )
GO

CREATE UNIQUE CLUSTERED INDEX [aspnet_Users_Index] ON [dbo].[aspnet_Users] 
(
	[ApplicationId] ASC,
	[LoweredUserName] ASC,
	[UserId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

With the changes above I managed to get at least twice the performance. Before the changes, the user manager took about 20 seconds to go to next page. After the change, it took only 2 seconds AND I could start using the search field again.

In general the performance gain was 2-5 times. The scripts does not seem to impact the stability of Sitecore, but use them with caution, as they are not official, not supported by me or Sitecore.

EDIT:

These scripts failed in an installation where I used the “switching” provider as my membership provider. Once I reverted to the default “sitecore” provider, the scripts worked. So be careful if you are using a switching provider, and remember to backup the database, or at least the original indexes and stored procedures.

Posted in Sitecore, Sitecore 6, Sitecore 7 | Tagged , , , | 6 Comments

Add text to asp:ValidationSummary (C#)

This trick is especially useful when you have custom code to be executed after your form have been submitted, and still wishes to communicate an error the same way as you communicate form validation errors.

Imagine the following ValidationSummary:

<asp:ValidationSummary ID="valSummary" 
  runat="server" 
  DisplayMode="BulletList" 
  ValidationGroup="ValGroup" 
/>

Any form error is displayed in this summary. When the user clicks your submit button you process the form:

protected void btnSubmit_Click(object sender, EventArgs e)
{
  Page.Validate();
  if (Page.IsValid)
  {
    // do custom processing of form
  }
}

But is the processing fails, is it too late to pop the validation summary? Not at all.
To do so, add a CustomValidator to your form:

<asp:CustomValidator 
  ID="valCustom" 
  runat="server" 
  ValidationGroup="ValGroup" 
/>

And simply set the error message in the CustomValidator, inside your btnSubmit_Click:

protected void btnSubmit_Click(object sender, EventArgs e)
{
  Page.Validate();
  if (Page.IsValid)
  {
    bool isOK = ProcessTheFormData();
    if (!isOK)
    {
      // Optional: Update the summary with a nice header
      valSummary.HeaderText = "Oops something went wrong";

      // Mandatory: Invalidate the custom validator, and set a error message
      valCustom.IsValid = false;
      valCustom.ErrorMessage = "A clever error message";
    }
  }
}

 

 

 

Posted in c#, General .NET | Tagged , , , | Leave a comment

Disable Sitecore SPEAK dialogs

The new Sitecore SPEAK dialogs introduced with Sitecore 7.x are known to cause difficulties for some. Some of the issues are technical or configuration related, others are related to the fact that many users don’t like their cheese to be moved.

Sitecore SPEAK adds these dialogs by overriding the existing Sitecore dialogs. To revert them, simply disable the override.

Go to the \App_Config\Include\Sitecore.Speak.config file and you can see the overrides at the top of the file:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <overrideXmlControls>
      <override xmlControl="Sitecore.Shell.Applications.Media.MediaBrowser" with="/sitecore/client/applications/Dialogs/SelectMediaDialog" />
    </overrideXmlControls>

    <overrideDialogs>
      <override dialogUrl="/sitecore/shell/Applications/Dialogs/Internal%20link.aspx" with="/sitecore/client/applications/dialogs/InsertLinkViaTreeDialog" />
      <override dialogUrl="/sitecore/shell/Applications/Dialogs/Mail%20link.aspx" with="/sitecore/client/applications/dialogs/InsertEmailDialog" />
      <override dialogUrl="/sitecore/shell/Applications/Dialogs/Anchor%20link.aspx" with="/sitecore/client/applications/dialogs/InsertAnchorDialog" />
      <override dialogUrl="/sitecore/shell/Applications/Item%20browser.aspx" with="/sitecore/client/applications/dialogs/InsertSitecoreItemViaTreeDialog" />
    </overrideDialogs>

    ...
    ...
  </sitecore>
</configuration>

Comment out the SPEAK dialogs you wish to disable, or comment out all of them if you wish to have all SPEAK dialogs to disappear.

MORE TO READ:

Posted in Sitecore 7 | Tagged , | 3 Comments

Sitecore.Web.Authentication.c__DisplayClass5.b__2(Ticket ticket) +52

When logging into the Sitecore client you can run into this exception:

[NullReferenceException: Object reference not set to an instance of an object.]
Sitecore.Web.Authentication.<>c__DisplayClass5.<GetExistingTicket>b__2(Ticket ticket) +52
System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source, Func`2 predicate) +168
Sitecore.Web.Authentication.TicketManager.CreateTicket(String userName, String startUrl, Boolean persist) +75
Sitecore.Pipelines.LoggedIn.Ticket.Process(LoggedInArgs args) +58

Or this exception:

[ArgumentException: Empty strings are not allowed.
Parameter name: value]
Sitecore.Web.Authentication.Ticket.set_StartUrl(String value) +255
Sitecore.Web.Authentication.Ticket.Parse(String ticket) +349
Sitecore.Web.Authentication.TicketManager.GetTickets() +319
Sitecore.Web.Authentication.TicketManager.CreateTicket(String userName, String startUrl, Boolean persist) +62
Sitecore.Pipelines.LoggedIn.Ticket.Process(LoggedInArgs args) +59

Both exception cast from the Sitecore login dialog:

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) +0
System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) +76
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +193
System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) +35
Sitecore.Nexus.Pipelines.NexusPipelineApi.Resume(PipelineArgs args, Pipeline pipeline) +398
Sitecore.Pipelines.Pipeline.Start(PipelineArgs args, Boolean atomic) +327
Sitecore.Pipelines.Pipeline.Start(String pipelineName, PipelineArgs args, Boolean atomic) +197
Sitecore.sitecore.login.LoginPage.Login_LoggedIn(Object sender, EventArgs e) +330
System.Web.UI.WebControls.Login.AttemptLogin() +289
System.Web.UI.WebControls.Login.OnBubbleEvent(Object source, EventArgs e) +105
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +84
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3804

The reason is that the Ticket property in the CORE database of your solution have gone pair-shaped:

Properties table from CORE database

Properties table from CORE database

This can happen if you:

  • Run update scripts (it happened for me when updating from Sitecore 7.1 to 7.2)
  • Have 2 Sitecore installations accessing the same database in:
    • Different .NET versions
    • Different Sitecore versions

To solve it, delete any SC_TICKET properties from the CORE database:

delete from [YourSitecore_Core].[dbo].[Properties]
where [key] = 'SC_TICKET';

Then restart your .NET application, and you should be fine again.

 

Posted in Sitecore 7 | Tagged , | 5 Comments