Wednesday, June 2, 2010

Fix the SharePoint's discussion board deleting bug

Recently, I ran into a very strange SharePoint Discussion Board bug: if you delete the discussion topic (the thread root message), SharePoint will tell 'Cannot complete this action. Please try again'. However, the topic did get deleted in spite of the error message.

Digging deeper into this, I found out that:
- the bug happens only if the discussion board resides on the sub-site, or the site collection under 'sites' folder. It does not happens on the root site of the root site collection.
- it happens only when you click on a discussion topic to view the thread (Flat or Threaded view) -> then click the root message's 'View Properties' button -> then click 'Delete Item' toolbar button.
- it does not happen if you choose to delete the topic from the context menu; or if you enter 'Properties' screen from 'View Item' context menu.
- it happens only when deleting the discussion root topic. Deleting the relies does not cause trouble.

Checking the URL carefully, I figured out the reason: the problem is because after deleting, it tries to redirect to the thread view (as specified by the 'Source' query string parameter). However, as the topic has been deleted, there's no place to go back. It is a redirecting problem, not a deleting problem.

The solution:
Although at first it seems to be a problem of my specific site, it is a WSS 3.0 bug. As of WSS 3.0 SP2 (or MOSS 2007 SP2), there is no hot fix for that. I did not yet know if this bug exists in the just-released SharePoint 2010. As there seems to be no existing solution on the Internet, I developed a simple JavaScript solution.

Add the following JavaScript snippet into discussion board's DispForm.aspx (if you don't know how to do this, see my post http://thith.blogspot.com/2010/06/how-to-add-javascript-to-sharepoint.html).

<script type="text/javascript">
_spBodyOnLoadFunctionNames.push("ChangeAction");
function ChangeAction() {
  // Topics have titles, replies do not
  if (!HasField("Title")) {
    return;
  }
  var theForm = document.forms['aspnetForm'];
  if (!theForm) {
    theForm = document.aspnetForm;
  }
  
  var oldAction = theForm.action;
  var args = oldAction.split('&');
  if (args.length > 0) {
      theForm.action = args[0];
  }
}
function HasField(internalName) {
  var elements = document.getElementsByName('SPBookmark_' + internalName);
  return (elements.length > 0);
}
</script>

The purpose is simple: if it is a discussion root, cleanup the URL. SharePoint will redirect to the list's default view (often AllItems.aspx) if it does not find the 'Source' query string parameter.

The script assume that 'ID' is the first query string parameter. It works on our environments. If you want a solution which does not depend on the order of the query string parameters, maybe you could try to parse the query string.

How to add JavaScript to SharePoint list form

Ever want to add some javascript to list forms (NewForm.aspx, EditForm.aspx, DispForm.aspx) to show/hide items or something like that? You could try one of following ways (tested on WSS 3.0):
1. Use browser: browse to the form you want to add javascript. Add '&PageView=Shared&ToolPaneView=2' to the end of the URL then hit Enter. Then you could add a Content Editor webpart to the form and put your javascript there.
2. Use SharePoint Designer: open the form, search for MainPlaceHolder and paste the javascript just bellow the <asp:content> opening tag.

Be sure to include <script> and </script> tags with your javascript.

Monday, December 4, 2006

Enable the Registry Editor

Sometimes, my machine is infected by some virus. Almost all viruses change many registry entries and disable the Windows Registry Editor (Regedt32.exe and Regedit.exe) so that I could not change them back. Of course, that is not a problem if you have some other tool to edit the Windows Registry; but I don't have such tool. Creating a .reg file and import into the registry often does not help because Windows could be configured to deny running registry editor in silent mode. Trying to enable the Windows registry editor by using Group Policy (gpedit.msc) might still no help, and even the Group Policy could be disabled. Plus, not everyone knows how to edit the .reg file or using Group Policy. That is why I wrote a small C# tool to enable the registry editor. The source code of the tool is like this:

using Microsoft.Win32;
string path = @"Software\Microsoft\Windows\CurrentVersion\Policies\System";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(path, true))
{
  if (key != null)
  {
    Object o = key.GetValue("DisableRegistryTools");
    if (o != null)
    {
      key.DeleteValue("DisableRegistryTools", false);
    }
  }
}

The snippet above deletes the "DisableRegistryTools". Note that you achieve the same result by updating the value to 0, which is the default value if the entry is not there. "DisableRegistryTools" is a DWORD whose value could be one of the following:

  0   Default. Registry Editor can be started either in interactive mode or in silent mode.
  1   Registry Editor can only be started in silent mode. You can still import an .reg file.
  2   Registry Editor cannot be started at all.

Some viruses also add "DisableRegistryTools" entry to HKEY_USERS\.DEFAULT, so I should also delete it:

using (RegistryKey key = Registry.Users.OpenSubKey(@".DEFAULT\" + path, true))
{
  if (key != null)
  {
    Object o = key.GetValue("DisableRegistryTools");
    if (o != null)
    {
      key.DeleteValue("DisableRegistryTools", false);
    }
  }
}

You may want to start the registry editor right after enabling it:

System.Diagnostics.Process.Start("regedit.exe");

Note that you should first kill every malware process or it will re-disable the tool very soon. Many viruses disable the Windows Task Manager and/or automatically restart the computer when you open it. In that case, you may need a third-party tool, like Process Explorer, to identify and kill malicious processes. However, I also included this functionality in my tool. Just drag a list box (lstProcess) and a button (btnKill) onto the form:

private void Form1_Load(object sender, System.EventArgs e)
{
  lstProcess.Items.AddRange(Process.GetProcesses());
}

private void btnKill_Click(object sender, System.EventArgs e)
{
  Process selectedProcess = lstProcess.SelectedItem as Process;
  if (selectedProcess == null) return; // no item selected

  string exePath = selectedProcess.MainModule.FileName;
  if (DialogResult.OK ==
    MessageBox.Show("Kill: " + exePath, "Confirm kill", MessageBoxButtons.OKCancel))
  {
    selectedProcess.Kill();
  }
}

After starting registry editor, you should check all programs that automatically run when Windows starts and delete malicious entries and their physical files (some versions of Windows include a good tool for this purpose (msconfig.exe), but some malware might still escape so you had better check the registry - see Run and RunOnce Registry Keys to know where to check). Then check and delete malicious scheduled tasks. Also check Windows services (run services.msc). Following are some other registry entries that you should check:

HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr
HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableCMD
HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\NoFolderOptions

Believe it or not, I have cleaned many viruses on my PC just with the help of my tool and the Windows' search functionality to search for recently created files which are likely malware ones.

Wednesday, November 15, 2006

Format code snippets in blogs

When blogging, I frequently have to copy code and paste it to my post. It is nice if I have the snippet formatted like it is in Visual Studio. In the past, if the snippet is short, I would put it in <pre> tag and manually colorize keywords, comments and strings. If the snippet was long, I would copy it from Visual Studio and paste into Word then copy to my post.

Recently, a friend of mine told me about http://www.manoli.net/csharpformat which can do the job for me. Despite the page's URL, it could format C#, VB, JavaScript, HTML, XML, ASPX, and MSH. The nice thing about code formatted by that page is that it makes use of CSS so I can paste the CSS stuff into my Blogger's template. Imagine some day I want to change the color of the keywords, just update the CSS and it will apply to all snippets in the blog. The page also let me download the source code, so I wrote a winform application myself using that DLL and added support for some other languages, like Java. It works nice, although sometimes it hangs with bad input :). I also changed the CSS a little to make the formatted code look more like that inside Visual Studio. I'll re-format every snippet in my blog.

using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

The HTML source the tool generates (the HTML source itself is also colorized by the tool):

<pre class="csharpcode">
<span class="kwrd">using</span> System;

<span class="kwrd">namespace</span> HelloWorld
{
    <span class="kwrd">class</span> Program
    {
        <span class="kwrd">static</span> <span class="kwrd">void</span>Main(<span class="kwrd">string</span>[] args)
        {
            Console.WriteLine(<span class="str">"Hello World!"</span>);
        }
    }
}</pre>

Look nice, doesn't it?

There was one problem: in some browsers, the <pre> tag does not wrap. In many pages (like ones in this blog), long lines would go out of the border of its containing panel and there is no way to see the obscured parts. Fortunately, there is a way out: update CSS to make <pre> wrap as described at http://myy.helia.fi/~karte/pre-wrap-css3-mozilla-opera-ie.html. After I updated the Blogger template, everything was fine.

.csharpcode, .csharpcode pre {
    font-size: small;
    color: black;
    font-family: Consolas, "Courier New", Courier, Monospace;
    background-color: #f4f4f4;
    white-space: pre-wrap;       /* css-3 */
    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
    white-space: -pre-wrap;      /* Opera 4-6 */
    white-space: -o-pre-wrap;    /* Opera 7 */
    word-wrap: break-word;       /* Internet Explorer 5.5+ */
}

Sorry the CSS code is not colorized as the tool does not support CSS yet.

Friday, October 27, 2006

What makes an API good

Today, once again, one of my colleagues called me to his desk and asked why the following code did not work as expected:

Debug.WriteLine("Message received: {0}", receivedMessage);

It should print out something like "Message received: Hello", right?

I've seen someone else have this problem before, and I myself did run into it.

- Look at the infotip. The first param is the message, and the second one is its category.

- Uh oh, category. How could I miss that!

I know why. He, as well as me and many other developers, expect Debug.WriteLine to work the same way as Console.WriteLine; so much that we do not notice the infotip's contents. Because Console.WriteLine is too well-known, I consider the signature of Debug.WriteLine bad design.

Good API is intuitive. The key to that is being consistent with well-known and widely used patterns. It is ideal if developers could code without looking at the documentation. Although computer is getting faster, it still takes some time to load the documentation. That reduces productivity and tests the developer's mentality. Thanks to good modern IDEs, we now less and less have to consult documentation. The usual reason I still have to look at the doc is to check out the Exceptions section. Of course, sometimes I have to consult the other information like thread safety, remarks, examples, etc. - but that is for more complex API when looking at the documentation is necessary.

I always wish that the IDE should somehow let users view exception information, at least for system types, in some form of intellisense dialog. It could do this by parsing the XML comments. The pitfall of this is that it might mislead the developer to trust that exception information which will certainly cause troubles if the method is poorly XML documented (it might still be documented well in some form else, but not XML comments). Exception documentation is just a good practice, not a contract. Java has experimented exception specification, with some benefits and some drawbacks. I am thinking of some solutions, like ExceptionAttribute, but none of them really helps.

Nevertheless, a good API should expose as much useful information as possible, in form of contracts, metadata (attributes), or at least standardized comments/documentation. Consistent style, self-documented names, commonly-used members/features emphasized. Good API + good IDE save developers' lives.

Thursday, October 26, 2006

Why exception so verbose?

I remember, on my first days with VS.NET, I wanted to add some exception classes to my project. I launched the Add New Item dialog trying to find some item like exception. There was no such item (it even did not have an item for interface! - VS2005 fixed this). I had to add a regular class, typed in the code for its standard constructors, then copied and pasted to create other exception classes. Although my application used a bunch of exceptions, none of them contained additional fields or methods - just the standard constructors. The way current languages support exception make exception's type so important and often solely adequate.

Later, I figured out how to add a template into VS.NET and made it appear on the Add New Item dialog. Since then, I did not have to manually type the exception code again (except for the infrequent case when I want to add some extra stuff into the exception).

However, every time I look at the code of a "standard" exception, I keep asking myself why on earth it has to be so verbose? Wouldn't it be neater to be one-line concise like this:

public exception MyException;

or if the exception should have a parent other than System.Exception:

public exception MySpecificException: MyException;

The compiler will compiles it into a "standard" exception. This is essentially the way delegate keyword in C# works.

Then you and me - the code typists - will have some time for a cup of tea.

Wednesday, November 2, 2005

C# Interlocked

Multithread programming, together with unit testing and exception handling, is among the tough and hard-to-do-cleanly things a software developer has to do on virtually every project. When starting learning about threads, a developer usually spend a lot of time to figure out how to create, start, and stop threads, how to make use of the thread pool, how to programming with the asynchronous delegates, etc. However, as I see it, the hardest thing to master is thread synchronization, that is, when and where you need to lock a code block to ensure accuracy and consistency. However, locking is reputed as expensive as it is often used ineffectively and create performance bottlenecks in the application. Effective locking primarily refers to locking at the correct level and correct granularity. Quite often, low level locking becomes useless as higher level code has its own business rules and may requires to lock a chunk of methods-something like "integration locking". Sometimes, two blocks of code are wrongly guarded by the same object which results in unnecessary contention. I am not a fan of lock-free tricks as it is too difficult to understand and might even be proven incorrect some time. However, there are some circumstances in which avoiding locking is just simple and elegant. I guess some of you might have seen code like following:

lock (this)
{
    a++; // or a--, a = b, you name it
}
We all learned that even a simple operation like increment might include several steps: load the variable into a register, increment it, save its value back from the register. So the lock in the code snippet above is necessary to prevent some other thread from intervening those steps (for this to work, the two threads must be guarded by the same lock). The only comment you might make about that snippet is that: avoid locking on this (or any public object if it is not designed for that purpose) since it might be accidentally be locked on by other code for a different purpose, which usually leads to a deadlock or at least execution inefficiency. However, the .NET does provide a brilliant class called System.Threading.Interlocked. This class contains a handful of useful methods such as assignment and increment/decrement, each one is performed as an atomic operation. So the above code could be better rewritten as simple as: Interlocked.Increment(ref a). How nice! "Atomic operation" is sometimes incorrectly interpreted as volatility. Let's take a look at section 5.5 of the C# Language Specification which said: 5.5 Atomicity of variable references Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement. Hmm... atomic again. Does that means in C#, the two following snippets are identical? Variables a, b, c are declared at class level:
int a, b, c;
Snippet 1:
a = 1;
b = c;
Snippet 2:
Interlocked.Exchange(ref a, 1);
b = c;
The answer is no. An atomic operation is indivisible. For example, an atomic write guarantees that no other thread can read while the write operation not yet finished and end up reading a partially updated value. However, for performance reason, the JIT or the hardware may decide to apply some optimizations such as reordering or even eliminating instructions as long as they do not break the logic from a single thread's perspective. For instance, in snippet 1, the processor might decide to fetch the value of c before writing 1 to a. That is OK if the program is single-threaded. However, what if a second thread updates the value of c in the meantime? The first thread then uses a stale value of c. The Interlocked class is just more than atomicity. In fact, each one of its methods uses a memory barrier which prevents any instruction being reordered crossing the barrier. The Interlocked.Exchanged method call in snippet 2 prevents the reading of c from happening before 1 is written to a. Interlocked class is also safe on multiprocessor systems, where, because of caching issues, the sequence of instructions executed on one processor can appear to be different from other processors' perspective. In addition, the specification says C# does not guarantee functions such as increment and decrement to be atomic. The Interlocked class provides two super-handy methods for those purposes: Interlocked.Increment and Interlocked.Decrement. It should be noted that there are overloaded versions of these two methods that accept a long argument. This surprised me at first since it guarantees increment and decrement of a 64-bit number as an atomic operation. However, I soon realized that there is no magic under the scene since MSDN remark section of this method says that "The 64-bit versions of Increment and Decrement are truly atomic only on systems where a System.IntPtr is 64 bits long. On other systems, these methods are atomic with respect to each other, but not with respect to other means of accessing the data.”. Aha, that means on 32-bit systems, they can only be considered atomic only if increment and decrement are the two only operations you ever want to perform on the variable. That behavior could be simulated by letting the two methods acquire a lock on the same static internal object. Besides the methods above, Interlocked class also provides a less-used method: CompareExchange. This method, as its name suggests, carries out a comparison first, and then exchanges the values if that test succeeded. Note that compare and exchange operations are performed as a single atomic operation. The example MSDN provides for this method is very interesting. This method reminds me of the DB optimistic concurrency problem which I had to deal with recently: you should only update a value if it is not been updated by someone else since the last time you queried it. Otherwise, that updated value will be replaced by your value. This method can also be used to implement the Singleton pattern:
Interlocked.CompareExchange(ref singleton,
           new SingletonClass(), null);
However, this approach requires a new instance of SingletonClass to be created even if singleton is not null.

So now if you ever want to lock a block of code which performs only a simple operation on a variable, let’s first see if you can get the same effect with Interlocked class.

Friday, October 28, 2005

A Touch of Japan

October 2005. The first time I visited Japan was also the first time I went abroad. The initial feeling when the plane was about to land at Narita airport was about the peace and tranquility here. It was slightly cold. I got straight to Hitachi Software building and my one-month working onsite here began.

However, everything soon turned to be some kind of frustration. Japanese people seemed to be too shy to start conversation, and it was rare to find someone who can speak English well. It took me some time to get used to the railway system. I wish they used Romaji (the alphabetic representation of Japanese) instead of Kanji and Hiragana letters on their maps.

As having out-sourced for companies in both the US and Japan, I feel tempted to make a comparison of the two. Most Japanese could read English well, but their writing, speaking, and listening are usually limited and insufficient to work with offshore teams in English. Plus, they seem to be too shy about their English and prefer to use Japanese even if they can speak English pretty well. As a result, a lot of effort have to be put in communication, and delaying and misunderstanding often occurs. Another thing is that many Japanese companies still make use of old software technologies, architectures, and processes, even when building new systems. One of the reason is that these systems have to inter-operate with legacy ones. However, as I see it, it is also because of their "legacy way of thinking". Japanese companies often consider that it is safer to use old methods, which are guaranteed to work but not very flexible and reusable. I must say that sketching out the system architecture, analyzing and designing in an object-oriented manner, and refactoring the code are among my favorite stuff. However, with Japanese companies I don’t have much chance to do them. A Japanese company often requires many kinds of reports and metrics, and it takes hours to explain them why a simple item of data does not match their norm.

I am waiting for the weekend when I could go and see something interesting in Tokyo and Yokohama. Geee