Saturday, August 8, 2009

A memory problem using the SPListItemCollection - How to avoid it ?

In the last few weeks my main core is tracking down memory leaks in client Sharepoint applications. This issue might not be happening to all of you who using this Object/Class. but it does might have something to do with you if you work on large lists or "future to be" large lists.

Ok, SPListItemCollection is a very strong class. Why ? Only with him you can get in flat way all the files you have in the doclib/list, regardless how deep they are located in the doclib ( in whatsoever folder in it ). I saw people that in order to get all the files which located in the sub folders in their doblibs, they were doing some serious digging ( including inefficient recursive iteration to get all those files ). But I'm sure you say - but if I need to to know in which subfolder this file was in ? Easy, you can track it down with the URL property.

So where the problem begins ? When you need just to do something very simple and very common - Automatically/pragmatically adding files\data into a list.
Let's say I want to add an item for my list, in order to do so I need to get the collection , right ? But what if my collection is huge ? above 2000 items in the list ( Above the recommendation in the whitepapers ) ?
Yes, now you start getting the problem. By calling this huge collection repeatedly Im using a lot of memory, till I might even get "Out of memory" exception.

Some code snippet to make sure you got the scenario -
 

SPWeb web = site.OpenWeb();
SPList list = web.Lists["Shared Documents"];
//Getting all Items in the collection ,even though we dont really need it
SPListItemCollection itemCol = list.Items;
SPListItem listItem = itemCol.Add();
//Working on the listItem we just added
listItem["Field1"] = //adding metadata and so on
listItem.Update();



So what we do just to workaround this scenario ? we get the collection from a certain view, which will be "thinner" version or in other words not as big as the default set of the collection. In fact, we made a special view only for that.

Short example to make sure you got the idea again -

 

SPWeb web = site.OpenWeb();
SPList list = web.Lists["Shared Documents"];
//Getting only the view items - could be empty
SPListItemCollection itemCol = list.GetItems(FakeView);
SPListItem listItem = itemCol.Add();
//Working on the listItem we just added
listItem["Field1"] = //adding metadata again or whatsoever
listItem.Update();



Apparently , This issue is very well known, it's much greater than I thought when I first saw this issue over one of my clients. Even in the MSDN they made a clearafaction about it.

Another disclaimer, one of my colleagues asked me right away, does it mean we added those items to that certain view ? Well, No. Since we still added the data to the list, the view might present those items if they fall in his view criteria. I personally made a "dummy/fake" view so it will always present nothing.

Enjoy.

Tuesday, August 4, 2009

Sharepoint Designer - what did you do ? ACCESS DENIED !

Hey all,
A few weeks ago we created with the SPD ( Sharepoint Designer ) a workflow.
After deploying it in one of our Moss websites, we saw that every time when end users created a list - there was a problem to edit an item.

The weird thing was , that every attempt to edit an item, even with the system account or with our strong privileges users, we got an access denied page.

After doing some research, we narrowed down the issue to occur only in a certain version of Moss. Googling for a while led me to the February hotfix rollup kb961756 & kb961755 - that solve this issue.
But what can I do regarding the lists that already "damaged" ? I got to this code snippet that was published by Microsoft support -







 
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;

namespace CA_TestingHotfix
{
class Program
{
static void Main(string[] args)
{
FixField(args);
}

static void FixField(string[] args)
{
string RenderXMLPattenAttribute = "RenderXMLUsingPattern";

//Console.WriteLine("Please enter the URL of the site: (Press enter after typing):");
string weburl = args[0];

//Console.WriteLine("Please enter the Document Library Name: (Press enter after typing):");
string listName = args[1];
SPSite site = new SPSite(weburl);
SPWeb web = site.OpenWeb();
SPList list = web.Lists[listName];
SPField f = list.Fields.GetFieldByInternalName("PermMask");
string s = f.SchemaXml;
Console.WriteLine("schemaXml before: " + s);
XmlDocument xd = new XmlDocument();
xd.LoadXml(s);
XmlElement xe = xd.DocumentElement;
if (xe.Attributes[RenderXMLPattenAttribute] == null)
{
XmlAttribute attr = xd.CreateAttribute(RenderXMLPattenAttribute);
attr.Value = "TRUE";
xe.Attributes.Append(attr);
}
string strXml = xe.OuterXml;
Console.WriteLine("schemaXml after: " + strXml);
f.SchemaXml = strXml;
}

}
}



This console application just adds to your schema the attribute that is missing. We did some more research in order to understand what really happened. The thing is that somehow we made the list schema be unghosted on that Site Collection, which means that instead of taking the schema.xml for list from the WFE itself, it made a "new" copy of the schema.xml in the DB - literally a simple case of Unghosting.

We wanted to see if we can fix it without deploying SP2 or that hotfix, So in our virtual machine we decided to track that record down.

 

SELECT SiteId, Class,Scope,ContentTypeID,Version,NextChildByte,Definition, Size, ResourceDir,IsFromFeature
FROM ContentTypes
WHERE (ContentTypeId = XXXXXXXXXXXXXXXX)




To sum things up, You can deploy service pack 2 or just run the query above ( NOT SUPPORTED ), and in order to fix the lists that already affected, run the console application.

Hope it helps.

Thursday, July 23, 2009

How to change SQL server name ?

A very common issue, when you make a p2v ( convert in vmare language ) to a physical Server and change the name of the server.

The whole idea is that the database still thinks it's on the pervious database and it damages his functionalty.

Those are the steps to check if you have this issue, and how to fix that.

 
//check the hosting server of the SQL service
sp_helpserver
select @@servername

//if the server name that appears is of the pervious server
// Make sure to run it from the server itself, NO remote execution
sp_dropserver 'old_name'
go
sp_addserver 'new_name','local'
go
// Now restart the SQL service and check the first step again to make sure.


Good luck

Thursday, July 2, 2009

Archive for Sharepoint ? Symantec Enterprise Vault... Round# 2

Well, a while ago I talked about the Enterprise vault product for archiving Sharepoint platform.
Since then, The Moss 2007 is common in every single customre I have. So , now they have new version. I checked. And now I declare.

What did they fix that makes it better than their last version ?

1. It supports Kerberos authentication.

What still makes it not ready ?

1. Doesn't support fedrated shearch AKA you still cant crawl it with your Moss search engine.
2. When you want to edit an item, it's being retrieved back from the repository, but it opens the document in your temporray internet files and NOT in your web site AKA your changes wont be saved/updated ( Cause you didn't save them on your website ).
3. Permission issue. When you copy an item ( the stub ) to anoter new list with diffrent ACL - you wont be able to reach the file if you dont have an access to the source list ( read at least ).

There are more issues, but those are the most critical and I count only till three.

Sorry, But it still not ready. I better submit my customer an email.

Sunday, June 21, 2009

How to Delete specific user from your sharepoint sites

Hey.

Small task I had today, to delete a certain user who left the company. They have a list in which they document all the workers who left, so I had to just check the list every day, see if there is anything new and if so, just delete that user from all SiteCollection - be aware, when you delete a user from the siteCollection it's enough, there is no need to drill down to each and each web site.

 


foreach (SPWebApplication webApp in service.WebApplications)
{
SPSiteCollection colSites = webApp.Sites;
for (int i = 0; i < colSites.Count; i++)
{
using (SPWeb web = colSites[i].OpenWeb())
{
SPUser user = web.SiteUsers[UserName_ToDelete];

try
{
if (!user.IsDomainGroup && !user.IsSiteAdmin)
{
web.SiteUsers.Remove(user.LoginName);
web.Update();
}
}
catch (Exception ex)
{
// user not found
}
}
colSites[i].Dispose();
}

}

Wednesday, May 27, 2009

SP2 is out - But with some "minor" problems...

Be aware for the bug when installing the SP. There is a simple workaround, an hotfix soon to be released.

http://blogs.msdn.com/sharepoint/archive/2009/04/28/announcing-service-pack-2-for-office-sharepoint-server-2007-and-windows-sharepoint-services-3-0.aspx

Sunday, May 17, 2009

SPUserCollection is not including groups ? Or just a Bug in Wss 2.0 Object Model ?

Hey.

I wrote today a small application that need to track down all the administrators of all the websites in my client sharepoint farm ( and write the data into a list with the website url and etc ).

Anyway , just to remind you I was dealing with wss 2.0 ( 2003 ), I was doing very simple stuff as iterating via all web applications->SiteCollections->WebSites.
and then just wanted to get all the users ( including Active directory groups )

 
SPUserCollection colUser = web.AllUsers;
foreach(SPUser user in colUser)
{
// check if admin, update list and blah blah
}


Unfortunately, it gives you back only the regular users, and not the AD groups too. I know you have under the SPWeb object the groups/sitegroups property but both of them are for Sharepoint groups and not for AD group.
Moreover, Under the SPUser object you have the property IsDomainGroup ( like I cant ask for more ) - BUT sorry, it just gives you back regular users all the time, and just "ignore" the AD gorups.

What I did at the end ? Just made a query to the SQL table ( Not so good, cause It's not supported ) - I will try now with WebService, let's hope it work via that.

If you think i'm wrong or you have another idea. Please comment.