Showing posts with label Undocumented. Show all posts
Showing posts with label Undocumented. Show all posts

Wednesday, September 17, 2014

properties.AfterProperties[“Title”] always null in document libraries

Like the title says,

If you are writing an event handler for document libraries / lists, properties.AfterProperties is usually a good way for you to get the new values that the user modified.

Now, we all know the fact that in lists you have to use internal name and in libraries you have to use display name, right?

So, it appears it is not the only trick up their sleeve…

If you ever tried getting the title or name columns in a document library you will quickly notice AfterProperties and BeforeProperties will always return null.

Now, I came across this technet discussion: http://social.technet.microsoft.com/Forums/sharepoint/en-US/ef6e1b63-c821-4c6c-b05f-0b1e32ebf073/beforeproperties-and-afterproperties-returns-null-value-in-itemupdating-itemupdated-event?forum=sharepointdevelopmentprevious

And at the very bottom, there is an answer by Helm Ifort that I found very interesting.

It appears the title column value is available in AfterProperties, only you have to use the “vti_title” name for it! (STS 2001 anyone?)

In my book, this is a bug, and an undocumented one at the very least… I hope someone fixes it soon, but for now it is one of those things seasoned SharePoint sharks need to remember.

Hope this helps

Friday, November 8, 2013

SPFieldMultiLineText.RichText = true does not update

Interesting thing happened to me today, and I guess I’ve seen it happening at least 10 times in the past but I keep forgetting what the solution was every time I see it again.

Say you create a multiple lines of text field in a list (Note field type of class SPFieldMultiLineText).

Now, you want to make sure it supports HTML but you want to do it via code.

The simple thing to do appears to be:

SPFieldMultiLineText myField = …;
myField.RichText = true;
myField.RichTextMode = FullHtml;
myField.Update();

Right? Wrong!

Run that code again, you will find that the RichText and RichTextMode properties were not modified.

Even calling list.Update() doesn’t help.

Apparently, the simple solution is to edit and set the myField.SchemaXml property directly, without calling myField.Update() after. Simple, yet annoying.

Here is an example of a working code:

XDocument xSchema = XDocument.Parse(field.SchemaXml);
var xField = xSchema.Root;
bool needUpdate = false;
var xRichText = xField.Attribute("RichText");
if (xRichText == null)
{
    needUpdate = true;
    xField.SetAttributeValue("RichText", "TRUE");
}
else if(xRichText.Value != "TRUE")
{
    needUpdate = true;
    xRichText.SetValue("TRUE");
}
var xRichTextMode = xField.Attribute("RichTextMode");
if (xRichTextMode == null)
{
    needUpdate = true;
    xField.SetAttributeValue("RichTextMode", "FullHtml");
}
else if (xRichTextMode.Value != "FullHtml")
{
    needUpdate = true;
    xRichTextMode.SetValue("FullHtml");
}
                                                                        
if( needUpdate )
    field.SchemaXml = xSchema.ToString();

Tuesday, May 14, 2013

One solution to rule them all

My prezi is ready for SharePoint Saturday LA!
This session will be heavy on the visual studio live demo, hope that part goes well :)
But for the first part of the talk I thought I could use prezi to explain the challenge in building a solution that can be deployed on both SharePoint 2010 and 2013, without doubling the R&D efforts, QA efforts and overall maintenance.
We had a very long discussion about this in house, and we are still not entirely convinced this is the best solution to this problem, but it is the best we’ve got so far.
In the past we used to have 2 different solutions for each version of the product. This forced us to constantly sync code between the two versions, having to fix and retest every issue on both versions, which of course wasn’t done perfectly so we ended up with bugs that were fixed in one version only, features that were missing from the other version and basically it was very hard to maintain them.
Now, with the introduction of versioned root folders in SharePoint 2013 this have become a bit more challenging since the code would be different and target different folders in 2010 and 2013. While in server code its rather simple to test the version and use the right path, doing it in config xml files (like web part gallery icon, feature icon for example) is not something we can change in runtime.
This is why we came up with a set of tools that allows us to keep working on one solution, and producing 2 packages from the same source code in one build. One for SharePoint 2010 and the other for SharePoint 2013.
It didn’t take a long time before we then learned about the challenges in trying to debug this code on the SharePoint 2013 machine. Since it wasn’t build on that machine, and didn’t target the .NET framework 4 – this proved to be a bit more complex than what we expected.
To find out more on how we got everything working – come see my session!

Please feel free to leave a comment here if you want more info, or if you been to my session and would like me to add or change something.
Code sample:
http://sdrv.ms/14kRdt3

More info on deferred site collection upgrade:
http://kwizcom.blogspot.ca/2014/03/sharepoint-2010-deferred-site.html

Since I get asked a lot during this session, "are FTC solutions dead?"
Here is a short presentation with points to consider:


Tuesday, October 2, 2012

Traps in SharePoint 2013 API

So, SharePoint 2013 has almost full API backward compatibility? Sure. That’s great!

I mean, Microsoft did a great job making our lives easy in upgrades.

But I did find some traps while upgrading to 2013 I want to share with your guys,

I am sure these things won’t be documented anywhere – which is why I call them “traps”…

I’ll try to collect more info and add it here as I move forward.

Note: these issues are found on a pre release version and might change before production is released.

Trap #1:

We run a query on tasks list, using the default all tasks view from that list. Thing is, we got “Object not set to an instance” error coming from our query parser.

Digging in code, I found SPListView.Query used to be an empty string in 2007/2010. In some lists in 2013 this changed to null now… So, any code using or parsing the query should now check if the view query is null before accessing it, like so:

string query = listview.Query ?? “”; //Takes listview.Query if not null, otherwise takes empty string.
… work and parse query as you would before

Trap #2:

We had some code that allows the user to select a list template and aggregate all items from that list type (in our list aggregator web part). So, I set it up to run on tasks lists, after fixing Trap #1, there was no error but still no items were returned.

Reason: I added a tasks “App” in 2013, which I assumed was the same as a tasks list. but to my surprise, tasks list type is 107, while the tasks App creates a list that uses type 151 (TasksWithTimelineAndHierarchy)

In our code, I collected all available list templates on the current site, but I had a code that prevented duplicate items from being added. I checked the SPListTemplate.Name and only added the first.

It appears, that in SharePoint 2013, both list types (107 and 151) have the same name “Tasks”! So, my code was only adding the first one, 107.

I had to modify my code to take the SPListTemplate.Type.ToString() in case of a duplicate entry, which seems to do the trick, Only added a space before every capital letter so it would be formatted nicer for the user.

 

Comment if you found more interesting upgrade traps!

Tuesday, February 22, 2011

Assembly redirection in OWSTimer

You may have read my older post on how to add BindingRedirect for assemblies into web.config in SharePoint, which allows you to change the DLL version number of your SharePoint customizations.

One thing I did not mention was, what if you need to use one of these redirected DLL’s in an SPTimerJob?

You will notice that assembly BindingRedirect does not apply to OWSTimer.exe, and it will throw errors such as “Could not load file or assembly 'AssmeblyName, Version=1.2.60.0, Culture=neutral, PublicKeyToken=xxxxxxxxx' or one of its dependencies. The system cannot find the file specified”, while you alraedy have a newer version deployed.

So, how do I make OWSTimer.exe aware of the new version and have my SPTimerJobs running with the latest version every time?

First, we need to understand why this doesn’t work.

Timer jobs run from OWSTimer.exe file, which is not effected by the web.config settings, so our BindingRedirect in web.config file will not help our code to find the correct assembly when running of the OWSTimer.exe file.

Now, for the solution

The bad news are that although a WSP natively allows you to add BindingRedirect to your web.config, it does not allow the same for other config files.

So, we need to do this manually.

Not to fear though! There is a rather simple way of doing that, still within the WSP with no need to come out of the WSP deployment.

It is a little know fact, that a farm feature event handler, with the “FeatureInstalled” event will have 2 special effects:

1. It will run for each web front end server, and not only on one of them

2. It will allow sufficient access to add files to the SharePoint Root.

Just make sure you do not edit / remove any of the out of the box files!

Well, taking this into consideration makes our problem a very simple one to solve.

We just need to create a config file for OWSTimer.exe and add our BindingRedirect statements there, and that’s it – the OWSTimer will know which version of our DLL to look for.

Here is a code example on how to add or update 2 BindingRedirect nodes in that config file, the same method can apply to any other config file during WSP deployment stage:

public void UpdateOWSTimerBindingRedirect()
{
try
{
string configFile = SPUtility.GetGenericSetupPath("TEMPLATE").ToLower().Replace("\\template", "\\bin") + "\\OWSTIMER.EXE.CONFIG";
//string XMLData = System.IO.File.ReadAllText(configFile, Encoding.UTF8);
XmlDocument config = new XmlDocument();
config.Load(configFile);

//ensure assemblyBinding exists
XmlNode assemblyBinding = config.SelectSingleNode("configuration/runtime/*[local-name()='assemblyBinding' and namespace-uri()='urn:schemas-microsoft-com:asm.v1']");

if (assemblyBinding == null)
{
assemblyBinding = config.CreateNode(XmlNodeType.Element, "assemblyBinding", "urn:schemas-microsoft-com:asm.v1");
config.SelectSingleNode("configuration/runtime").AppendChild(assemblyBinding);
}

//Delete old entrees if exist
XmlElement current = assemblyBinding.FirstChild as XmlElement;
while (current != null)
{
XmlElement elmToRemove = null;
if (current.FirstChild != null)
{
var asmIdn = (current.FirstChild as XmlElement);
if (asmIdn.GetAttribute("name").ToLower().Equals("kwizcom.sharepoint.foundation") ||
asmIdn.GetAttribute("name").ToLower().Equals("kwizcom.foundation"))
elmToRemove = current;
}

current = current.NextSibling as XmlElement;

if (elmToRemove != null)
assemblyBinding.RemoveChild(elmToRemove);
}

XmlElement dependentAssembly = null;
if (dependentAssembly == null)//create it
{
dependentAssembly = config.CreateElement("dependentAssembly");
dependentAssembly.InnerXml = "<assemblyIdentity name=\"KWizCom.SharePoint.Foundation\" publicKeyToken=\"30fb4ddbec95ff8f\" culture=\"neutral\" />"+
"<bindingRedirect oldVersion=\"1.0.0.0-20.0.0.00\" newVersion=\"13.2.62.0\" />";
assemblyBinding.AppendChild(dependentAssembly);
}

dependentAssembly = null;
if (dependentAssembly == null)//create it
{
dependentAssembly = config.CreateElement("dependentAssembly");
dependentAssembly.InnerXml = "<assemblyIdentity name=\"KWizCom.Foundation\" publicKeyToken=\"30fb4ddbec95ff8f\" culture=\"neutral\" />" +
"<bindingRedirect oldVersion=\"1.0.0.0-20.0.0.00\" newVersion=\"13.2.62.0\" />";
assemblyBinding.AppendChild(dependentAssembly);
}

config.LoadXml(config.OuterXml.Replace("xmlns=\"\"",""));
config.Save(configFile);
}
catch { }
}

Simply call this method during the FeatureInstalled event and update the code with your DLL name and version number, and you are done.

Hope this helps you with file versioning on SharePoint, which can be a rather difficult task sometimes.


Thanks, Shai.

Monday, November 8, 2010

Using jQuery in SharePoint 2010? Here is something you didnt expect!

If you are planning or using jQuery JS library in SharePoint 2010, there is one thing you didn't plan - for sure.
The $ sign from jQuery library is conflicted with the $ sign used in SharePoint JS - only in picture library "thumbnails" view.
Meaning, your code will not work if it has a picture library thumbnail view web part.
A wrong solution would be to append your JS to the end of the page - do this and your code will work, but the thumbnail view will stop working!
The solution for this is rather simple and annoying,
All you have to do is rename the $ sign into something else, like myJQ.
To do this - add this simple line of code at the end of your jQuery JS file:
var $jq = jQuery.noConflict();
and use $jq instead of $.
Note: you should use your own unique key instead of $jq.

Friday, November 5, 2010

Custom List Ribbon Button dont show up on home page

Today I found a strange behaviour,
My custom list and library ribbon buttons were working find within the list page, but as soon as I added a list view web part to the home page or any other web part page - the custom buttons were gone!
Only the OOB buttons were available.

After some fishing aroun the code I learned that the list view property "Show Toolbar" had something to do with that. Once I changed it to "Full toolbar" my custom buttons were available!

Strange though, since the other OOB ribbon buttons appear all the time... well, what can you do?

Cheers

Tuesday, August 3, 2010

Assembly redirection in WSP

Recently I have started upgrading our utilities to the new SharePoint 2010 version,

One of my main goals there was to get rid of the MSI installer we had to use on our products for SharePoint 2007, and go with a "cleaner" installation process of using the SharePoint WSP package alone.

One of the challenges was that as an ISV we have no control over our customer's server, setup or versions installed. Which means, any customer may have any mix of products and versions at the same time.

For example: say we have 2 products - ProductA and ProductB (both at version 1.0.0.00) that were build using our shared utilities DLL: utilities.dll version 1.0.0.01

A month later, we add a new feature in our utilities.dll that is used on ProductB, so now we have upgraded our utilities to version 1.0.0.02 and our ProductB to version 2.0.0.00 and we publish that to the Internet.

Now our customer upgrades his copy of ProductB only.
We had 2 options here:
1. keep both utilities version
2. upgrade and keep only version 1.0.0.02

The first option was no good, since for example our utilities declare a feature called FeatureA. if 2 different packages declare that same feature, and one of them is retracted later on - the feature will be uninstalled with it (There are some other issues like this one, but this is not the scope of this article).

So, sticking with the second option was pretty simple: just install the latest version of utilities with no other older versions of it anywhere.
The only issue was, How will it "tell" all other older products (ProductA) to start using utilities.dll version 1.0.0.02?!

I have looked everywhere for a solution that was just under my nose.

Apparently in VS2010 and SharePoint 2010 there is a new XML node in the package XML definition, right next to the assembly "SafeControls" node.

This new XML node is called "BindingRedirect", and it allows you to specify in the solution package itself any Assembly version redirection you might need!

Problem is - the package designer does not expose this property, so you have to enter it in the Package.Template.Xml directly.

here is how my package.template.xml file looks like:

The end result is:

And this simple produces the following entree in the web.config:

Now, as far as I tested:
  1. Retracting solution cleans this entree up with no problem!
  2. Deploying a new version upgrades this entree and does not create duplicate entrees!
  3. It is safe (like in my example) to give a wide version range in the oldVersion property - even for future versions that do not exist yet. it will simply allow you not to update this every time you build a new version.
So far, this solution had worked out perfect for me, and it is by far the easiest and most simple way to do it in SharePoint than any other way I found on the web - so hope this helps any of you.

Cheers, Shai.

Monday, July 5, 2010

Enable or Disable buttons in SharePoint Ribbon

A few days ago I was doing some reading on the web and I ran across Chris O'Brien post on the ribbon:
http://www.sharepointnutsandbolts.com/2010/01/customizing-ribbon-part-1-creating-tabs.html

(very good post, recommended to everyone if you want to get to know the ribbon better!)

In the first part of this post there is a sample ribbon tab with 4 buttons dependent on one another.

Meaning: clicking one button should enable or disable other buttons on the ribbon (Same tab, different groups).



This was supposed to be easy to achieve using the "EnabledScript" attribute on the CommandUIHandler associated with the buttons needed to be changed.

In my RTM machine, clicking one button did not change the status of the other buttons. After a little research I learned that other examples of enabling a button based on selected list items do work.

I then figured out that were was some update or refresh code running when selecting a list item that was not running during a click on my ribbon button.
This led me to find that in Chris's example, if I select an item after changing the flag - the buttons get enabled as they should!

To keep it short, there is a Javascript method called "RefreshCommandUI" that gets called after certain events in SharePoint (Like selecting an item in a list view) which is responsible to handle all updates of the ribbon.
These updates include:
1. Showing or hiding a contextual tab based on context
2, Enabling or Disabling buttons in the current active tab

Note, that this command does not run on buttons that are not active, but as soon as your tab will become active it will trigger the "EnabledScript" so not to worry!

Anyway, Thanks Chris for the great post, I hope this little fix here will make your ribbonizing experience even more smooth and worth while!

Shai Petel.

Thursday, March 11, 2010

How to get SharePoint KPI value in C#

It's been a while since I had anything smart to say, and then I had to go and play with KPIs...

KPIs in SharePoint 2007 are pretty cool, they allow you to work in several ways basically: Either you enter the KPI info manually, or you connect it to some sort of a data source like a list, excel file or other providers.

in the end you find your self with a nice list item that has some KPI fields to hold the goal, warning and value levels (in C#: double).

the problem is that when you try to access these fields in code you find that only the manual KPI actually holds the information for you to display:

value = (double)item[list.Fields.GetFieldByInternalName(MobileConstants.KPIHelper.Field_Value).Id];
goal = (double)item[list.Fields.GetFieldByInternalName(MobileConstants.KPIHelper.Field_Goal).Id];
warning = (double)item[list.Fields.GetFieldByInternalName(MobileConstants.KPIHelper.Field_Warning).Id];


Meaning, if you have a KPI that loads from a SharePoint list or an excel file... don't hope to get anything from these fields...

Well, after hours of diggin into SharePoint dll's, I have found the solution finally.

It appears that the entire KPI API ( :) ) is either internal or private to these DLL's, which means of course - reflection!

So I dug in and found some cool examples in MS code that loads KPIs and display them, which in turn exposed some key classes and methods that would save the day.

First one - is the KpiFactory. This guy will in turn get us a Kpi object based on a KPI list item (yes, simple SPList.Item object).

Once we got the Kpi - it is safe to call GetKpiData with no parametes to get another object named KpiData, which finally holds a Value, Goal and Warning properties!

So the final code should look like so:
Assembly asm = System.Reflection.Assembly.Load("Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
Type t = asm.GetType("Microsoft.SharePoint.Portal.WebControls.KpiFactory");
MethodInfo mi = t.GetMethod("GetKpi", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, new Type[] { item.GetType() }, null);
object kpi = mi.Invoke(null, new object[] { item });
mi = kpi.GetType().GetMethod("GetKpiData", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null);
object kpidata = mi.Invoke(kpi, new object[] { });

value = (double)ReflectionUtility.GetPropertyValue(kpidata, "Value");//double
warning = (double)ReflectionUtility.GetPropertyValue(kpidata, "Warning");//double
goal = (double)ReflectionUtility.GetPropertyValue(kpidata, "Goal");//double


Of course there are some unclear parameters that have to do with filter and other things, I will update as soon as i figure out what they are for... no idea for now - but at least our mobile solution will have nice KPI's to show after all!

Tuesday, September 15, 2009

Performance issue using SPUtility.GetFullNameFromLogin

Recently we had a strange support call regarding our rating solution.

The customer experienced very bad performance using our rating field type, when opening the comments page for an item.

everything else was working very fast, pages loaded within a blink of an eye, only opening the popup that displays the comments and ratings from other users took anywhere from 10 to 40 seconds...

So, we created a debug version that prints out the time stamp of every stage of the page.
What the page does is basically, load all comments and ratings into a list and binds them into a repeater control.

So, we found out that while loading the comments we get the user login name, and since we want to show the user display name we use this SharePoint API method to get the display name from the login name:
SPUtility.GetFullNameFromLogin(site, "domain\\user_login");

well, to keep it simple, calling the method above to get the user display name took 8 seconds every time we called it, so for every comment on the item the page load time would take 8 more seconds!!!

The customer opened a support call to microsoft while we were investigating other alternatives for getting the user display name.

The answer the customer got from microsoft team was simple and did resolve the issue.
Simply instead of using SPUtility.GetFullNameFromLogin, they recommend using:

web.EnsureUser("domain\\user_login").Name;

so, the web.EnsureUser method works much faster and the performance problem was resolved!

Since I did not see any post about this on the web I thought I might as well write one myself - hope this helps some of you in the future.

Shai Petel.

Thursday, May 14, 2009

Creating a field in a List and getting the error: "Index was outside the bounds of the array"

Today, while I was code reviewing a new release of our rating field type I got a weird error message...

We added a new feature that adds 2 read only fields with the total number of ratings and number of comments.

Code example for addnig new fields was simple:
if (!list.Fields.ContainsField(ratingField.FieldName_NumOfCommentsInternalName))
{
list.Fields.Add(ratingField.FieldName_NumOfCommentsDecodedName, SPFieldType.Number, false);
//Some more logic here
}


Pretty simple, only when this code runs this time (3rd unit testing sessions before release to customer review) suddenly I get the error message above "Index was outside the bounds of the array".

Well... I ran it in debug few time, scratching my head few times more, but nothing - same error every time!

OK, time for drilling into SharePoint code I guess...
The exception stack trace was as following:
at Microsoft.SharePoint.Utilities.SPStringUtility.EscapedCodeToLower(String str)
at Microsoft.SharePoint.SPFieldCollection.FixFieldV3Attrs(XmlDocument xd, XmlElement xe, Guid& fid, String& name)
at Microsoft.SharePoint.SPFieldCollection.TranslateFieldSchema(String schemaXml, Guid& fid, String& strDisp, String& strStaticNew)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXmlInternal(String schemaXml, Boolean addToDefaultView, SPAddFieldOptions op)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXml(String schemaXml, Boolean addToDefaultView, SPAddFieldOptions op)
at Microsoft.SharePoint.SPFieldCollection.AddFieldAsXml(String strXml)
at Microsoft.SharePoint.SPFieldCollection.AddInternal(String strDisplayName, SPFieldType type, Boolean bRequired, Boolean bCompactName, Guid lookupListId, Guid lookupWebId, StringCollection choices)
at Microsoft.SharePoint.SPFieldCollection.Add(String strDisplayName, SPFieldType type, Boolean bRequired, Boolean bCompactName, StringCollection choices)
at Microsoft.SharePoint.SPFieldCollection.Add(String strDisplayName, SPFieldType type, Boolean bRequired)
at KWizCom.SharePoint.Rating.ListRatingUtilities.CreateRatingCountFieldsInList(SPWeb web, SPList list, RatingField ratingField)


Revealing that the exception was raised from a method called:
Microsoft.SharePoint.Utilities.SPStringUtility.EscapedCodeToLower(String str)

So far - makes sense... string parsing is always the number one cause for index bound exceptions, right?

So, I wanted to check what was wrong with the field name I was trying to create...
ratingField.FieldName_NumOfCommentsDecodedName "2Rating Site Column_x" string


See that my field name ends with "_x"...

The code I extracted from "EscapedCodeToLower" had the following line in it:
if (((str[i] == '_') && (i < (str.Length - 1))) && (str[i + 1] == 'x'))


Well, now everything was clear to me.

Microsoft uses "XmlConvert.EncodeName" in order to encode fields internal names in SharePoint. This encoding method replaces illegal characters with "_x0020_" for example. Apparently this method looks up every "_" that was followed by "x" and assumes it is a token it needs to decode... But what happens if my text ends with "_x"?

Aha! You get your "Index was outside the bounds of the array" exception!

So, I guess now I have to add a check to my code. I Doubt anyone would notice it or bother to fix it.

Well, I googled that error message regarding SPList.Fields.Add and got nothing - hopefully this will help someone in need in the future...

Shai.

Friday, November 21, 2008

Want to know how to change MOSS search results sort order?

Hi,

Some of you may have seen my post on how to add rating field to MOSS search results,

Since than I have had several customers that wanted to allow their users to sort the search resutls by that rating field, and not by the relevance / date (Even though I explained that this will break the MOSS search relevance mechanism).

Be that as it may, after searching the web - I managed to locate several "free tools" that does that, but I was determined to find a more simple solution that did not involve downloading/executing any out side code on my server.

Finally, I found that this can be done by a very simple change to the XSL of the main search results body web part (the same one we modified in the previouse post).

Simply replace this statement in the XSL:
<xsl:apply-templates />

With this one:
<xsl:apply-templates>
<xsl:sort select="rating"/>
</xsl:apply-templates>


Note:
You might want to allow the user to sort by relevance / date and rating, and not only rating. In that case you should use the actions web part above the main search resutls web part and add a new option there to specify when it should sort by rating and not do it hard-coded in the results XSL web part.


Hope this helps,
Shai Petel,
VP R&D

Monday, October 6, 2008

CRM Error: Generic SQL Error Code: 0x80044150

So, I have seen and checked very proposed solution to this error on the web.

The only problem associated with this issue I did not see any record of is of course the error I had with a customer recently...

The issue is complicated-simple issue...

Simple explanation would be:
Once you export and entity, add a new attribute with the same name as an existing one (not case sensitive - meaning 1= new_myattribute 2=New_myattribute) you will get this error.

Simple, Right?

Now, for the complicated way of getting this error...

Normally, the CRM will lower-case all letters in the attribute and add the "new_" prefix for you.

So - when looking for a property to check if it exists I used to have a lower-case case sensitive XML XPath search for it, and if I did not find it - I knew it was safe to add it...

Only that apparently the CRM 3.0 and CRM 4.0 has some inconsistency with the prefix of custom attributes...

One adds new_ while the other adds New_, this means that one of our customers who used the CRM SharePoint connector in CRM 3.0, upgraded the solution to CRM 4.0, and run our solution again - ended up with this error message since he had the old field from the upgrade and we were trying to add it as duplicated in the new version since we could not find it...

Well - complicated enough?

I will keep the conclusion short -
1: Be sure not to add duplicate attributes, or import will fail.
2: When looking for attributes - don't use case-sensitive comparison (although tempting in XML)!
3: Email the CRM developer guys and request nicely for better error messages ( don't tell them I sent you :) )

Well, Please feel free to post here any other problems / solutions related to this very generic error code.

Just for the record - the error code mostly refers to trying to assign data into a field that is too long... so if you didn't check that first - this would be a good time to do so... :)

Error using web part connection in list item form

Ever go this error when using a connection?
"Web Part Error: This page has exceeded its data fetch limit for connected Web Parts. Try disconnecting one or more Web Parts to correct the problem."

Well, it is known that the filter connections sometimes invoke this, and there are ways to fix it... but - I just found a "fluke" in the SharePoint connections infrastructure that is not caused by bad-coding at all.

As a matter of fact - I can reproduce it using only out of the box web parts and no custom code at all!

We wanted to have in our customers list, when a user go in to the display form of a customer, to get a list of contacts associated with this customer from the contact list.

So - we added the List View web part of Contacts list into the DispForm.aspx of the Customer list.

Than we used Custom Item Property (more information on www.kwizcom.com) that gets the current customer's title and sends it as a filter to the List View web part...

Sounds simple, only to find out that using List View web part on a display form, with a filter connection - is apparently (and unspoken) not supported!!!

It will always give an error "Web Part Error: This page has exceeded its data fetch limit for connected Web Parts. Try disconnecting one or more Web Parts to correct the problem.".

This has nothing to do with my code ( I found out couple of hours later ) since if I try it using the Query string filter web part - I get the same result every time.

Ok, after a while, I started looking for other creative solutions and found a work-around for this issue.

Converting the List View web part to a Data View web part will solve this issue and will allow you to add a filtered view of related information!!!

(Sorry for the !!!, just excited that it is not my code that caused the issue :) )

(* hint: to convert list view into data view - open the page in SharePoint Designer, right click on the list view and select the "convert to data view" option... )

Well, hope this helps save some lives, keep me posted if you have additions / questions,

Shai Petel,
VP Professional Services
KWizCom

Friday, August 1, 2008

STSADM Restore Error - Version does not match

Another thig you learn the hard way -

When you are using STSADM -o export
You should use STSADM -o import

So far so good... buy when the time in the night gets late - and you try to use STSADM -o restore... that can take a while to figure out :)

So - wierd thing is you will get an error saying the backup is from a newer SharePoint version and you need to update your installation... Naturally - I wasted a good hour making sure I have latest version intalled.

Goggle did not help on this one... Finally I noticed I am using the wrong command - So if you googled this in the same situation - make sure you are using the correct command!

Backup - Restore
Export - Import

:)

Good luck!

Thursday, July 31, 2008

How to add Source parameter to SharePoint links automatically?

Hi,

You know when you click a link to view item in SharePoint list and when you click Close it goes back to the page you came from?
Or when you edit an item - clicking OK returns you the page you original came from?

Well, you may have noticed SharePoint does that by adding the "Source=" url query string parameter to the address, and uses it to knwo where to go after we user is done.

So, basically - you can use that to redirect the user anywhere you want after he finishes with the form you sent him to, but - what if you want it to automatically be set to the current page's address?
Of course you can hard code the page's address, but what about additional query string parameters, of multiple addresses to the same page (different host headers)?

There is an easier way - the way SharePoint adds the "Source" parameter -
simply add this bit to your a link in HTML:
ONCLICK="GoToLink(this);return false;"

so that your link will look like:
<a href="/Docs/Lists/Announcements/DispForm.aspx?ID=1" ONCLICK="GoToLink(this);return false;">view item</a>

The GoToLink will automatically add thye current page's address before navigating to the HREF you entered!

Shai Petel

Thursday, July 3, 2008

Creating a view for birthday


Well, I struggled with this for an hour or so until I finally found a solution...

Scenario:
our customer has a list of users with a date field with their Birthday.
He wishes to see the upcoming birthdays for users in the upcoming week.

Problem:
The birthdate field holds the actual birthday of the user (i.e. July 24 1980), but he wants to see it as July 24 2008... July 24 2009... and so on.

Well, since we cannot use the [Today] field in calculated column (all tricks wont work - the field won't update!), I have conjured this solution that only asks for a yearly update to the column:

First, we have to create a calculated column that results in the current year birthdate
(from July 24 1980 to July 24 2008)

1 - create a date column to hold real birthday (named: BDay) or type date.
2 - create a calculate column to hold this year's BDay (named: YBDay).
3 - set the output type of the calculated value to "Date and Time"
4 - use this formula to generate its value:
=DATE(2008,MONTH(BDay),DAY(BDay))


Now, the rest is easy:
You create a view and set filter to 2 conditions:
where [this year birthday] >= [Today]
And
where [this year birthday] <= [Today] + 7


Now, you see all birthdays for the upcoming week!

Just remember - next year you will have to update the formula of the calculated field.

Hope this helps you - sure did saved me :)

Tuesday, June 24, 2008

Unable to add selected web part(s).

You know this error?

You just developed a new web part, all excited and ready to test it and wham!

Unable to add selected web part(s).
[Web Part Title]: One of the properties of the Web Part has an incorrect format. Windows SharePoint Services cannot deserialize the Web Part. Check the format of the properties and try again.

Well, this keeps happening to me (not the first time, and definitly not the last) so I thought I'd share one of the reasons for this message to appear.

This meesage can apear in various situations - so feel free to comment with your own "check list" for this error.

Reason 1:
Check your class definitions. In most cases - if you forget to mark it as "public class" you will get this error.

Reason 2:
Check your properties definitions. Could it be that custom logic in get/set throws and exception?

Reason 3:
Check your DWP/Webpart file. It may point to a property that does not exist (removed / spelling mistake), or the assembly is not registered correctly. Best way to troubleshoot this is: Go to your site collection settings, to web parts gallery, click "new" and add your web part to the gallery. Try the new DWP/Webpart file created - does it work?

Reason 4:
For Bin installations - make sure your DLL is in the bin folder of the current web application. Make sure it is registered as safe control in the web.config with no spelling mistakes.

Reason 5:
For GAC installations - make sure your DLL is in the GAC, if you changed it recently try an IISRESET. Also - Make sure it is registered as safe control in the web.config for each web application with no spelling mistaked.

Ok, this is what I can come up with now... Share your experience, this error can get pretty annoying!

Hope I helped save lifes on this (or at least, made the world a better place with less developers screaming in the middle of the night).

Brought to you as a public service by Shai, KWizCom :)

Tuesday, January 8, 2008

Working with sub folders in list

Hi all,

As you all know, in 2007 SharePoint introduced a new feature to lists - creating items in sub folders. But apparently the API was not modified in an easy way to support working with this feature...

In my last project I had to create sub-folders in lists and list items in these folders from code, and found that it is not so simple.

We are doing a rating solution for SharePoint items (coming soon on our web site, for more information contact sales@kwizcom.com), and wanted to create a new "item rating" list to store all ratings for all items on the same site.
For performence issues we wanted to create a sub folder for each list in the site and a second level folder for each item and create all ratings and comments in that folder.

The outcome of that project was 3 utilities methods that manages all that I need for working with folders and I thought it would be nice to publish them here - mainly because when I googled for it I didn’t find any good posts for that.

Here is how to use the utilities methods in your project:

SPList list = GetOrCreateList(web);//create your own...
//Create subfolder named "first level"
SPListItem folder = GetOrCreateFolderInList(list, list.RootFolder, "first level");
//Create subfolder named "second level"
folder = GetOrCreateFolderInList(list, folder.Folder, "second level");
//Create item in "second level" folder
SPListItem item = AddListItemInFolder(folder);
//Update meta data of new item
item["Rating"] = 5;
item["Comments"] = "";
item["ListID"] = list.ID.ToString("N");
item["ItemID"] = "ITEM_ID";
item["UserName"] = "shai...";
item.Update();


Here is the code for the utilities:

private SPListItem AddListItemInFolder(SPListItem parentFolder)
{
return parentFolder.ListItems.Add(parentFolder.Folder.ServerRelativeUrl, SPFileSystemObjectType.File);
}
private SPListItem GetOrCreateFolderInList(SPList parentList, SPFolder parentFolder, string folderName)
{
folderName = folderName.ToLower();
string parentFolderUrl = parentFolder == null ? "":parentFolder.ServerRelativeUrl.ToLower();
//Look in existing folders
foreach (SPListItem f in parentList.Folders)
if (f.Folder.ServerRelativeUrl.ToLower() == parentFolderUrl + "/" + folderName)
return f;//Found! return it!

//not exists - create
SPListItem folder = parentList.Items.Add(parentFolderUrl, SPFileSystemObjectType.Folder, folderName);
folder.Update();
return folder;
}


Well, hope this helps you - it sure did help me :)
Shai Petel,