Friday, November 14, 2008

Can't access Account Settings in Outlook 2007

If you are using Outlook 2007 and have some controlling system administrators they may have locked you out of Account Settings in Outlook 2007. You will know they have locked you out because you will get a message like the following when you go to Outlook 2007 | Tools | Account Settings. This feature has been disabled by your system administrator. For more information, contact your system administrator. This is unfortunate because this is an easy place to add RSS Feeds, etc. To temporarily (until the next Group Policy refresh most likely) enable your access again there is a very easy registry change you can do. In fact, you can put the registry change in a file and just double click it to make the change. Once the change is applied you should be able to open up Outlook 2007 and go to Tools | Account Settings. The registry key you need to change is the following:
HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup\ModifyAccounts

You need to set it to 0 to enable access, and 1 to block access.

If you want to be able to just double-click a file to make the change do the following.

  1. Open notepad
  2. Copy and paste the following into notepad Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Setup] "ModifyAccounts"=dword:00000000
  3. Save file with a .reg file extension. For example: unlockOutlook.reg
Keep in mind this is a group policy so you will likely need to make the change (or double-click the file you created) each time you want to access the Account Settings. For more great Outlook hacks check out: http://wiki.yobi.be/wiki/Outlook#All_in_one_registry_file

Monday, November 10, 2008

Release the memory after using a SPWeb object

It is important to clean up after you are done with a SPWeb. Below is a snippet of code that connects to the top level site of SharePoint and loops through all the webs (recursively). The important thing to note here is that after we do whatever we want to do with the web, we call the Dispose() method on the SPWeb. If you don't do this and your site if big, you will run out of memory. Since this code needs to run on your SharePoint server, it is definitely not a good thing to use up all your memory. :)

using (SPSite site = new SPSite("http://sharepointserver"))
{

   SPWebCollection webs = site.AllWebs;
   foreach (SPWeb web in webs)
   {
       DoSomethingWithWeb(web);
       web.Dispose();
   }
}

Wednesday, October 1, 2008

ERROR: Cannot resolve the collation conflict between SQL_Latin1_General_CP1_CI_AS and Latin1_General_CI_AS_KS_WS in the equal to operation

If you get the following SQL Server error message:

Msg 468, Level 16, State 9, Line 1
Cannot resolve the collation conflict between SQL_Latin1_General_CP1_CI_AS and Latin1_General_CI_AS_KS_WS in the equal to operation.


It is because of Collation settings on two columns you are joining on (or maybe something similar. There are permanent fixes, but are not simple and mostly assume you can change table definitions, etc.

I prefer the simple fix.  

The first step is to figure out what are two collations that are conflicting. Assuming that the collation has not been set at the column level and is instead at the database level, here s what you need to do.

Execute the following two statements (after you put your two database names in the statements).

select DATABASEPROPERTYEX ( 'DB1', N'Collation' )
select DATABASEPROPERTYEX ( 'DB2', N'Collation' )

If you are on SharePoint you will likely get Latin1_General_CI_AS_KS_WS. If you are on most any other database and use the default settigs you may get: SQL_Latin1_General_CP1_CI_AS.

Now that you know what you are dealing with you just need to do something similar to a CAST, but for Collation. It is called Collate. Here is an example of a query that joins on two columns that have different collations.

select * from DB1.dbo.User u
join DB2.dbo.UserMap m
on (u.email = m.email COLLATE SQL_Latin1_General_CP1_CI_AS)


For your query you will should choose the Collation of one of the columns.

If you want to understand more about this, I suggest checking this link:
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/07/12/883.aspx

The database schema is too old to perform this operation in this SharePoint cluster.

Have you ever received the following error while trying to reconnect or restore a SQL Server database in SharePoint? The database schema is too old to perform this operation in this SharePoint cluster. This is a little mis-leading in my opinion. It is talking about a version mismatch between SharePoint Configuration database and the database you are trying to restore or reconnect to SharePoint. This should apply to both Windows SharePoint Services v2 (WSS) and SharePoint Portal Server 2003 (SPS), though the names of the databases may be different. Let's assume your content database is called xxx_SITE where xxx is the name of your SharePoint site if you are using SPS. If you are using WSS you are looking for your Content database. If you open up SQL Server Management Studio 2005 or Query Analyzer you can run the following two queries. You will see that there is a mismatch on the version numbers. select Version from xxx_SITE.dbo.SystemVersion select SchemaVersion from SPS01_Config_db.dbo.Globals What this means is that you have a different version of SharePoint installed than the version that was installed when SharePoint was backed up. I have found on the web documentation that says it has to be the same service pack level, but my experiences has told me that the patches have the be the same as well. Here if you look under the comments for one by Andrew Woodward you'll see he also had the same experience. This site seems to have a good list of what the different versions are in relation to patches. Once you have the same version of SharePoint installed again everything should restore fine. If you are not sure what the previous version was you can get it from the content database (xxx_SITE in this example) using the above query.

Friday, September 19, 2008

Alternate syntax for order by in SQL Server

The order by clause is very flexible in SQL Server. You can pass it nearly anything and it will work.

In this section I show how to sort a results based on a runtime value. This works well for a stored procedure that is used for sorting and the user interface has the ability to sort by different columns. Instead of using Dynamic SQL, creating multiple stored procedures, or have a long list of if-else and then copy and pasting the same basic code (just changing the order by column), this solution is simple and easily maintainable.

Declare @Orderby as varchar(20)
Set @Orderby = 'CREATED DESC'
SELECT [NAME] as FullName, SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY -- add columns to sort by here
 CASE @Orderby WHEN 'NAME DESC' THEN [NAME] END DESC,
 CASE @Orderby WHEN 'NAME ASC' THEN [NAME] END ASC,
 CASE @Orderby WHEN 'SEARCH_CODE DESC' THEN SEARCH_CODE END DESC,
 CASE @Orderby WHEN 'SEARCH_CODE ASC' THEN SEARCH_CODE END ASC,
 CASE @Orderby WHEN 'CREATED DESC' THEN CREATED END DESC,
 CASE @Orderby WHEN 'CREATED ASC' THEN CREATED END ASC

You can refer to columns by number instead of column name. This can make columns that have complex subqueries easier to reference in the order by.

SELECT [NAME] as FullName, SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY 3 DESC, 1 ASC

Instead of column name or column number, you can use the column alias

SELECT [NAME] as FullName, SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY FullName ASC

Here are some variations on the previous example

SELECT [NAME] as 'FullName', SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY FullName ASC

SELECT [NAME] as 'FullName', SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY 'FullName' ASC

SELECT [NAME] 'FullName', SEARCH_CODE, CREATED
 FROM ALL_PERSON e
ORDER BY 'FullName' ASC

Wednesday, September 10, 2008

Override any CSS style (even inline styles) no matter where it is defined

Cascading Style Sheets (CSS) are very nice for formatting HTML. In general, I think it is a very bad idea for an ASP.NET control to emit inline styles because it prevents the developer from overriding the formatting. This is of course unless there is a corresponding property or programmatic way provided of changing it.

The ASP.NET GridView is a great example of this. It emits the following inline style for the table tag it emits.

style="border-collapse:collapse"

If I want to change that *they* provide no way to do so.

However, CSS does provide a way to that I recently found here http://home.tampabay.rr.com/bmerkey/cheatsheet.htm.

So, all I have to do is create a CSS class called something like GridViewStyle by including the following between the head tags on the .aspx page.

<style>
.GridViewStyle { border-collapse:separate ! important; }
</style>

This is the key to this entire solution. Notice the ! important; This means that border-collapse will be set to separate even if the inline style says differently. This is *very* powerful.

To apply this CSS class to the table tag that is emitted by the GridView all we have to do is set the CssClass property of the GridView to GridViewStyle.

Add TBody and THead to GridView

If you want to play nice with standard (for many reasons), you will notice that GridView does a fair job. However, it does not use tbody, thead, or tfoot tags for the table that is generated when rendered in the browser.

This technique for this entry was learned from this article. However, I found that it was really correct or functional in all cases. For example, if you click on a column i the GridView to sort or do anything else on the page to cause the GridView to do its databinding again the html is regenerated. Which means that after DataBind() is called (implicitly using ObjectDataSource or SqlDataSource) you need to make the changes again. You could technically do this in the PageLoad event, but you would also have to do it in the other places that cause the data binding to fire again. The easiest way I no to have the code in one place is to do it in the PreRender event of the GridView.

L
uckily, there is a simple fix

protected void GridView1_PreRender(object sender, EventArgs e)
{

   // You only need the following 2 lines of code if you are not 
   // using an ObjectDataSource of SqlDataSource

   GridView1.DataSource = Sample.GetData();
   GridView1.DataBind();

   
if (GridView1.Rows.Count > 0)
   
{
      //This replaces <td> with <th> and adds the scope attribute
      GridView1.UseAccessibleHeader = true;

      
//This will add the <thead> and <tbody> elements
      GridView1.HeaderRow.TableSection = TableRowSection.TableHeader;

      
//This adds the <tfoot> element. 
      //Remove if you don't have a footer row

      GridView1.FooterRow.TableSection = TableRowSection.TableFooter;
   }

}

The easiest way to wire up this event is to in the Designer, get properites on the GridView, and then click the Events icon (lightning icon) to get the list of events. Now, double-click the PreRender space. This will create a method calle something like the one above. Copy the above code and you are ready to go.

Or

If you prefer the no GUI way. Just add it to your GridView tag. That would look something like this:


<asp:GridView ID="GridView1" runat="server" 
    OnPreRender="GridView1_PreRender">
</asp:GridView>