Tuesday, November 29, 2011

SharePoint Popup Scroll gone after autoSize

I’m writing this post after not finding anything about this problem in Google.

The issue

When you have a SharePoint 2010 popup dialog, that uses autoSize (like the new item / edit item forms in any SharePoint list), if you call “window.frameElement.autoSize()” second time, there is no scroll in the popup.

Say you have a field control or a web part that changes in height when the user interacts with it. In my case, I was working on a “repeating rows” field type, where the user can add as many rows to the field as he wants – much like in InfoPath.

When the user add new rows, the height of my popup changes, so I have to resize it.

Documentation is pretty clear, call window.frameElement.autoSize() and it should resize your dialog.

Apparently, this works well for the first time you call it, but for some reason if I call it second/third/ninth time – once the popup is too high the vertical scroll is gone.

Another issue is, that even when it does fit to the page – the top of the popup does not move up so you end up having to move the popup to the top of the page yourself.

This caused great frustration for some of our customers, and by extent – our product manager and support – and by extent – me!

The solution

I knew I was alone in this, since not only Google did not have any solution for this issue – I could not even find someone asking about it in any forums / mailing list.

So, since waiting for a Microsoft fix for this, which may or may not come eventually (after all this issue is introduced with custom development and not on OOB scenarios), I had to dig deep and get dirty with Microsoft JavaScript and popup DOM.

It wasn’t pretty, I tell you, but I did find lots of cool stuff, like a function that calculates the width of the scroll bars in the browser :) (yeah, they actually have a function for it!)

Well, it appears that the popup have few divs and iframe behind it to make it look and work so cool (great job on that Microsoft!), I figured the problem was that the height was not calculating correctly on the second call to autoSize. It disregards the maximum size of the parent window, and does not reposition the window vertically.

I had to do it myself.

I came up with this code, now – it is not fail proof, and might not work on some scenarios – but it did work for me, our QA and our customers. I will appreciate if you have any comments or fixes to this code, or if you know of another more “clean” solution to this issue.

//call autoSize
window.frameElement.autoSize();
//Fix scroll bar and positioning. $kw is our alias for jQuery
var bodyHeight = $kw(top.document.body).height();
var dialogMaxHeight = bodyHeight - 60;
//if dialog is too high
if ($kw(window.frameElement).height() > dialogMaxHeight) {
//move dialog to top
top.document.getElementsByClassName('ms-dlgContent')[0].style.top = '8px';
top.document.getElementsByClassName('ms-dlgContent')[0].previousSibling.style.top = '8px';
//resize all dialog divs/frames/whatnot
window.frameElement.style.height = dialogMaxHeight + 'px';
top.document.getElementsByClassName('ms-dlgContent')[0].previousSibling.style.height = dialogMaxHeight + 'px';
top.document.getElementsByClassName('ms-dlgContent')[0].style.height = dialogMaxHeight + 32 + 'px';
top.document.getElementsByClassName('ms-dlgBorder')[0].style.height = dialogMaxHeight + 32 + 'px';
}
//end issue fix




Thanks, Shai.

Thursday, November 24, 2011

Redirect to custom error page from event handler

I’ve seen a lot of posts saying you can’t redirect to a custom error page from a SPItemEventReceiver in SharePoint 2007.

In 2010, you can use Properties.RedirectUrl which will send you to a custom error page, instead of the OOB error page that displays your properties.ErrorMessage. this is simple enough, all you have to do is set properties.Cancel = true – and the custom redirect Url kicks in.

But still, in 2007 this property does not exist, and in 2010 – you might want to have a custom redirect page and not cancel the event.

Good news – it is all possible!

Redirecting

The way to do it, is to add some code to a sync event. Async events can’t help you since they are not guaranteed to run immediately, and they don’t have any user context when they execute…

You can use the SPUtility.Redirect(PageUrl, SPRedirectFlags, HTTPContext); within your ItemAdding, ItemUpdating or ItemDeleting event handler to redirect your user to a custom page.

This redirection kicks in and throws the “ThreadAbortException”, stopping the rest of your code from running and redirecting the user to your custom page.

Few things to know:

1. ThreadAbortException is a “catch me if you can” exception. you can put it in try…catch… block, but this exception will always bubble up and be thrown again and again. essentially, only the catch and finally code blocks will run after this exception is thrown. you can set “SPRedirectFlags.DoNotEndResponse” if you don’t want this exception to be thrown and it should still redirect at the end, but using SPRedirectFlags.Default will throw it.

2. You may notice, that if you try using HTTPContext.Current in your event handler method – you will get a null context. So, the only way to get the HTTPContext.Current is in your event handler class constructor. save it as a member, and use it in your event handlers. DONT SAVE IT AS A STATIC MEMBER! Use any instance member (private/public/protected…) but don’t use a static member as you may run into unexpected trouble.

Cancelling the event

Now, we took care of redirecting, but it is good to remember that this on its own will not cancel the item event and it will still be updated/added/deleted.

If you want to cancel the item event, you still have to do that using properties.Cancel = true.

Since we talked about ThreadAbortException – now you know you have to put the SPUtility.Redirect code in a try block, and set the properties.Cancel in the catch block.

Code Example:

Your code should look like this:

try
{
SPUtility.Redirect("/_layouts/KWizCom/AppError.aspx?ErMsg=" + errMessage, SPRedirectFlags.DoNotEndResponse, currentContext);
}
catch
{
properties.ErrorMessage = errMessage;
properties.Cancel = true;
}

Good luck!

Saturday, October 29, 2011

Developer's Guide: How to enhance your SharePoint performance - Understand Caching

I have just finished my presentation at SharePoint Saturday Twin Cities!

I talked with developers and ITPro on how to enhance their SharePoint and SharePoint customization performance using some of the built in caching features, such as:
- BLOB cache
- Ghost files
- Object cache
- Page output cache
As well as other coding practices, such as:
- Query pagination
- Indexed columns
- Throttling
- Code cache in multi-threaded environment

Here is the complete presentation, download to read comments in each slide:

Thursday, September 15, 2011

Windows 8 Developer Preview!

Finally, My Lenovo tablet, x201, multi touch screen, will be more cool than my iPad!

and that’s saying a lot!

I just installed windows 8 on my hyper V, looks real nice.

First impressions:

Login

First of all, logging in to windows is now done using your live ID login (email and password) and it promises to keep your desktop settings synced across all your PC’s.

Login screen itself reminds me of a welcome screen on a smartphone:

image

Nice, finally some info on the boring lock screen. didn't ask for much, clock and date will defiantly suffice.

The new Start menu

Logging in with my live id, gets me to the new start menu. Yeah – you heard me.
It feels like they took windows 7, build a huge new start menu, and hid windows desktop behind the start menu – and it looks and feels great!

image

Build for wide screen displays, high res, and for touch – obviously!

While in this mode, you work in a table or smartphone look and feel. Every app you open takes up the whole screen, so no more confusing display of many small windows. I guess, for the average user that is pretty good, while for work that might be less useful.

Start menu apps

The new internet explorer looks pretty amazing and works very well. check out this new “tiles” instead of tabs:

image

overall, the new UI with large buttons made for touch.

This build ships with a built-in twitter application called tweet@rama, which might reminds you of something else already out there (pardon the blur, for protecting my info):

image

Start menu UX

Another change you might notice while in this new menu, is that the windows key in your keyboard is now used to switching between you current active application and back to the menu. As mentioned before, you can only have one application opened at a time, and it works in full screen only, which honestly makes more sense to me and is much better user experience especially for non-developer users.

I am sure this new UX will increase adaptability to the new system by the public who is now more and more used to smart phones.

And… Windows Desktop

One of the tiles in the start menu allows you to get to the original windows desktop mode:

image

reminds me of windows 7 so far, but – careful! clicking the start menu will not open a start menu as you know it, but will bring you back to the new start menu with the huge tiles we got on logon.

task manager had a serious face lift as well, with a minimal view:

image

and  advanced views:

imageimageimage

Overall, super excited!

As a long time advocate of touch screens, and the owner of 3(!) windows based multi touch computers (2 laptops and 1 HT TouchSmart) I can safely say I have waited a long time for this, and Microsoft did not disappoint!

To me, this is a huge breakthrough that will finally windows OS to lots of people, who can easily use a smart phone or and iPad but found the mouse-keyboard interaction a bit confusing.

Ok, I know this type of posts is not typical for me, a non technical product eval type of post, but I guess I am just too much excited!

Tuesday, September 6, 2011

Error: “value cannot be null parameter name publickey”

I just had a very strange error message in my visual studio 2010 SharePoint project…

When building the project everything goes well, but when packaging it or deploying it I got this error message:

“value cannot be null parameter name publickey”

Also, trying to open the package editor in visual studio to take a look at the “preview of packaged manifest” showed me the same error:

image

Google did not prove to be useful as I did not find anything close to this error message.

Well, in the interest of saving you time, let me just say that after some search around the project I found that the strong name signing of my project was missing the signature file (SNK), which produced an unsigned DLL, and as such – I guess caused this issue with the package building.

Hope this will at least save some time to anyone else out there,

Happy SharePointing!

Monday, June 27, 2011

Accessing SharePoint Silverlight 4 API from outside of SharePoint

If you are like me, building Silverlight SharePoint components, you probably noticed that debugging Silverlight running from within a SharePoint solution is almost impossible!

There are many settings to take care of, and you have to install and configure your server to allow debugging, honestly I gave up in the middle.

Instead, I though, why not run the Silverlight application locally, and have it connect to the SharePoint API?

Well, try that and you will be in to a little surprise.

Any Microsoft.SharePoint.Client.Silverlight call you make will get you a System.Security.SecurityException: Security error.

Not a lot of info there, but this is easy to fix and not documented well enough anywhere in all the Silverlight SharePoint development guides I looked at.

The cause for this error, is that Silverlight blocks cross domain access by default, preventing applications from one domain to invoke requests from another domain, unless the remove domain explicitly allows it.

To allow that call, Silverlight makes a request to the root of the remote server to read a configuration file named clientaccesspolicy.xml, if this file does not exist – Silverlight checks for a flash configuration policy file instead (but lets focus on pure Silverlight 4 for now.)

In order to allow cross domain requests to be executed, just put this configuration file in the root of your web application (next to the web.config file):

file name: clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>
<
access-policy>
<
cross-domain-access>
<
policy>
<
allow-from http-request-headers="*">
<
domain uri="*"/>
</
allow-from>
<
grant-to>
<
resource path="/" include-subpaths="true"/>
</
grant-to>
</
policy>
</
cross-domain-access>
</
access-policy>


Once you have this file, you should be able to run and debug your Silverlight application from anywhere, making it easy to debug your SharePoint Silverlight applications on either dev, testing or production servers!


Cheers, Shai.

Wednesday, June 1, 2011

Visual Studio 2010 find and replace window too wide

Do you have that problem too?

Every once in a while when you hit Ctrl+f the find and replace dialog is way too wide, growing and growing and does not fit your screen?

Well, you are not alone.

It seems that every time you close and open this window, it grow just a few pixel wider… So slowly and surly it become ridiculously wide forcing you to tame it, yet once again.

This has become quite a familiar game for developers – but no more!

Apparently this is a know issue with a fix available:

http://support.microsoft.com/kb/2268081

good luck!

Monday, May 30, 2011

Web part functional specifications document template

Hi
Following my last session at the Toronto SharePoint Business user group, here's a link to web part functional specifications document template I've mentioned there.
The purpose of this template is to help SharePoint business analysts to make sure they fully cover all functional aspects when designing a custom developed web part.
Please feel free to comment.
Coming soon: SharePoint site functional specifications template.
Cheers
Nimrod

Setting default value to column in document library

Hi,

One question I hear a lot from developers and system designers is “How can I set a default value to a column in a document library”?

The same goes for form libraries in SharePoint, Apparently SharePoint does not support default values for document libraries.

The first thing that comes to mind, as a solution for this predicament, is to build an event handler that will set a default value to the fields you need whenever a new item (document) is added to the library.

An experienced developer will tell you you should use the ItemAdding event, in order to set the default values to the field during the same update that the user initiated, and under his credentials.

To do that, you will have to use the properties.AfterProperties["FieldName"] = “Default Value”; to set your value.

But – you will be surprised that document libraries, although they do support the ItemAdding event, do not support properties.AfterProperties use. This collection is always empty and ignored in document libraries!

So, the only solution to set a default value to a field in a document library is by using the ItemAdded event.

During this event, the SPListItem was already created and is accessible through properties.ListItem property (unlike ItemAdding, that happens before the item was created).

So, setting the field should be rather easy: properties.ListItem[“FieldName”] = “Default value”;

But you will have to update the file manually yourself, since this happens after SharePoint has already processed the update of the item.

Naturally, you will not want to update the modified date/time, modified by user, and also you will not want to create a new version or emails alerts to be sent out.

So, instead of using the properties.ListItem.Update() method, use these lines of code:

base.DisableEventFiring();
properties.ListItem.SystemUpdate(false);
base.EnableEventFiring();



Or the SharePoint 2010 code equivalent:



this.EventFiringEnabled = false;
properties.ListItem.SystemUpdate(false);
this.EventFiringEnabled = true;


This will allow you to use custom code and programmatically set a default value to any SharePoint library column. Note that the same code should also work for SharePoint Lists, but this is supported through the UI or during the ItemAdding event.



For those of you who are not developers, or would rather a 3rd party solution, you can use KWizCom List Forms Extension solution version 2.1.60 or higher, where you can find a settings page that allows you to set advanced default values using this workaround.



Thanks, Shai.

Tuesday, May 24, 2011

Recruiting senior developers

Hi all,

Just an FYI, KWizCom is recruiting senior SharePoint developers to it’s R&D product development team.

We are looking for skilled and experienced developers in the greater Toronto area.

Your experience:

  • At least 3 years of developing on Microsoft SharePoint platforms. 2010 experience is an advantage
  • required skills: C#, ASP.NET, Javascript, jQuery, AJAX, DHTML, Web services, TFS, XML/CAML
  • nice to have: Silverlight, JSON, XSLT, SharePoint Designer, MS Office, workflow foundation, BDC/BCS/BizTalk, Hyper-V

Your responsibilities:

  • Work within tight delivery dates
  • Work in small, highly professional team
  • Be a part of the product lifecycle, attend brainstorming meetings, have a real impact on the product features and UX
  • Work in a highly creative environment

Although there is a work from home option, you will be required to attend meetings at our office, located at Markham Ontario, so we are looking for local candidates.

If you are up to it and would like to come in for an interview, please email me your CV to shai at kwizcom dot com.

Thanks!

Friday, May 20, 2011

Promoting user profile changes into local site user profile

Here is a problem that I faced more then once, with no proper way to resolve it so far…

User changes his email address or display name in his user profile using his mysite’s profile update page, but the changes are not updated in all the site collections where this user is a member of.

Display name, email settings – nothing!

Online doc’s and research says you can use the “STSADM –o sync” command, but it never helped me in those cases where it didn’t work in the first place.

The only other solution I found was to delete the user from the site collection (which removes all his permissions) and add it again. But this is unacceptable for most users.

Recently I stumbled upon this tool in codeplex by Berry Cohen:
http://userprofilesync.codeplex.com/

while his code was for SharePoint 2007, I needed it on my 2010 machine, so I upgraded it to 2010 and shared the new build in the codeplex page.

I have yet to determine if there are any side effects to using this tool, but so far it seems to be working with no problems!

It actually creates the fields in the user profile list for the site collection, which in turn allows me to even edit and modify it directly there.

Only note is, for production farms – use with caution! (and also, for production farms if you have that problem I would investigate it rather than using a workaround).

I was sorry to hear that Berry’s experience with SharePoint was short, and hope to have you back among our lines soon!

Friday, May 6, 2011

PageComponent code example for SharePoint Ribbon

I get a lot of requests lately to share my example for a simple generic PageComponent JavaScript object (class) that can handle ribbon events.

The was it works is simple, I will probably blog about it in more details later on but in a nutshell there are 3 client side objects that are involved with the ribbon work on the page:

1. PageManager

One object that have a collection of all PageComponent objects for the CommandDispatcher to be able to work with them

2. CommandDispatcher

The only object that handles ribbon events. Any action that happens on the ribbon sends the CommandName of the associated event to the CommandDispatcher. In turn, the CommandDispatcher goes to all available PageComponent objects and ask each one of them if the can handle that command, and if they do – it asks them to handle the command, thus invoking their command handlers.

3. Collection of PageComponent objects

PageComponent object are client side script classes that inherit from CUI.Page.PageComponent (yes, JavaScript class that inherits from a base class!). They declare a collection of CommandName strings of commands they know how to handle and are sometimes associated with a control on the page (web part, field control etc), and when ever such a command is invoked the CommandDispatcher asks them if they can currently handle that command, and if yes – it asks them to handle it. There is no limit to the number of PageComponent objects on the page, or to the number of PageComponent that handles a specific commands. You can also handle commands from OOB ribbon controls, and does not have to be the creator of that ribbon control.
Note: If a command has no PageComponent that can handle it, the control associated with it will be disabled (button, group) except for a tab that does not have to have a command associated with it.

Here is an example of a page component that I start from, feel free to take it and use it, it is very similar to the example available on MSDN with a bit more explanations:

//See documentation in page component: http://msdn.microsoft.com/en-us/library/ff407303.aspx
//TODO: choose namespace like you would in .NET applications. Use company name, project name and module name to avoid conflicts
Type.registerNamespace('Company.Project.Ribbon.PageComponent');

//Create the object
Company.Project.Ribbon.PageComponent = function (PageComponentId) {
this._pageComponentId = PageComponentId;//keep record of associated control (web part, field control, etc..) that is active in this current instance of page component.
//Initializes the base type CUI.Page.PageComponent (Base class is associated through Type.registerClass(Type, BaseType)
Company.Project.Ribbon.PageComponent.initializeBase(this);
}

//Declate it's prototype
Company.Project.Ribbon.PageComponent.prototype =
{
//This will be initialized by caller (web part, field control etc)
_pageComponentId: "PageComponentIDHolder",

getId: function () {
return this._pageComponentId;
},
init: function () {
//Create a list of commands that your page component can handle (JSON string array).
//TODO: edit this collection, these are the command names you wish to handle from the ribbon controls you are listening to.
this._myCommandList = ['Company.Project.Ribbon.PageComponent.CMD1',
'Company.Project.Ribbon.PageComponent.CMD2',
'Company.Project.Ribbon.PageComponent.CMD3'];

//Create an array of methods used to handle commands passed to the page component.
//Use Function.createDelegate to keep current class instance (this) when the method is called.
//TODO: add handler per command in this._myCommandList. Later on - you will have to create the actual script handler method.
this._myHandledCommands = {};
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD1'] = Function.createDelegate(this, this.CMD1_Handler);
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD2'] = Function.createDelegate(this, this.NotImplemented);
this._myHandledCommands['Company.Project.Ribbon.PageComponent.CMD3'] = Function.createDelegate(this, this.NotImplemented);
},
getFocusedCommands: function () {
return this._myCommandList; //return supported commands collection
},
getGlobalCommands: function () {
return this._myCommandList; //return supported commands collection
},
canHandleCommand: function (commandId) {
//TODO: In our logic, if there is a handler we can handle the command.
//But you might have more logic here, like: if commandId = DeleteItem - can handle only if there is 1 item selected.
var canHandle = this._myHandledCommands[commandId];

if (canHandle)
return true;
else
return false
;
},
handleCommand: function (commandId, properties, sequence) {
//Handle the command - simply getting the command handler (delegate) form the hash table and invoking it.
return this._myHandledCommands[commandId](commandId, properties, sequence);
},
isFocusable: function () {
return true;
},

//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~ CUSTOM PAGE COMPONENT LOGIC STARTS HERE ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
// This is where you should add your custom script hadler methods.
// TODO: Implement each handler in this._myHandledCommands
//

CMD1_Handler: function (commandId, properties, sequence) {
alert("Handling CMD1_Handler");
},
NotImplemented: function (commandId, properties, sequence) {
alert("This command was not implemented yet");
}

//
//
//
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~ CUSTOM PAGE COMPONENT LOGIC ENDS HERE ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
//=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
}

//This makes our object inherit of CUI.Page.PageComponent
Company.Project.Ribbon.PageComponent.registerClass('Company.Project.Ribbon.PageComponent', CUI.Page.PageComponent)
//Execute pending operations waiting for this script to be loaded.
NotifyScriptLoadedAndExecuteWaitingJobs("Company.Project.Ribbon.PageComponent.js");


So, now that we implemented our PageComponent, all we need is to create an instance and register is with the PageManager using this code that makes sure all JS files were fully loaded:



function init2() {
//All JS files were loaded - create instance and register it.
var instance = new Company.Project.Ribbon.PageComponent("ComponentID");
SP.Ribbon.PageManager.get_instance().addPageComponent(instance);
}

function init1() {
//Wait for ribbon JS to load
ExecuteOrDelayUntilScriptLoaded(init2, 'sp.ribbon.js');
}
//Wait for our JS to load
ExecuteOrDelayUntilScriptLoaded(init1, 'Company.Project.Ribbon.PageComponent.js');


I hope this helps you when you are implementing your custom ribbon solutions, or if you need to handle an existing ribbon command in addition to its OOB logic.



Note: to replace an OOB logic of a ribbon command there are other steps you need to take, I will try blogging about it soon as well.



Thanks, Shai.

Friday, April 8, 2011

A little bit about me…

This is just a little update about my certifications - for those of you who are interested…

On April 1st I have:

1. Renewed my MCT (since 2007)

2. Renewed my MCTS SharePoint to 2010 version (was 2003 before…)

3. Achieved MCPD: SharePoint Developer 2010

4. And I was awarded the MVP: SharePoint Server award!

(Really excited about that last one!)

MVP_FullColor_ForScreen_0.35

Friday, March 25, 2011

FxCop: Properties should not return arrays

Did you run FxCop and it reported a “Performance” issue regarding “Properties should not return arrays”?
http://msdn.microsoft.com/en-us/library/0fss9skc(v=VS.100).aspx
Well, don’t be in a hurry to fix it just yet.
After an online meeting with Microsoft online tech team, I was surprised to hear them claim that this may pose a performance issue, since developers “must return a copy of the array”, which will cause a performance issue when accessing this property excessively (like via an indexer, in a loop).
They went on later to recommend changing this property into a method, to make it clear for the developer who is using it that he is better off calling the method once and storing it in a local member, rather then using the indexer on the property itself, Or change the property type into a collection. There is even an example at the end of the page of converting the array into a collection, which “resolves” this “performance” issue.
Also, from reading the rule page on MSDN, it seems this issue only refers to a possibly problem of breaking the read-only attribute of an array that is returned as a property, which would unintentionally allow modifications to it. Definately not what I was told in that meeting, and besides - when the array is not read only I don't see the problem here. Isn't it up to the architect to decide what to use, and if the array should or should not be read-only?
Let me give you a few points to think about before complying to this rule:
1. Properties do not serve the same purpose as methods. If you need to serialize this class, a property would be serialized while a method would not – resulting in loss of data upon serialization. This is extremely important when talking about web part properties. Even changing the property into a read only collection will not help, as XmlSerializer will throw an exception on that property.
2. An array does not serve the same functionality as a collection. Especially when reflecting it, or serializing it for use later (JSON serialize / SOAP serialize in web service for example).
3. If you have an existing web part that uses an array as property, DONT CHANGE IT! you cannot change it’s type, nor change it into a method! Doing so will break all your existing web parts in all pages and you will have to remove them and re-configure them, page by page. This goes to web parts, but also to any serialized content you have of existing code.
4. Speaking of performance issue, the author assumes that *if* you build the array on every get_Property access this will have negative performance. But – why would you do that? In most you just return a private array member that should not be read-only, which does not affect performance at all.
5. Even more, by implementing the resolution suggested and converting into a collection, performance will have a far worst negative implication! Working with arrays is with no doubt the fastest way of working with a collection in .NET! It is faster than any other collection type, including Generic collections, in every possible way.
Consider a simple “for” loop, using “items[i]” <—an array will beat any collection any time, any place!
So, by suggesting to fix a non-existent “performance” issue, you actually cause a much greater real “performance” issue on your application.
What I don’t understand is, this rule has been there since 2006 with many people posting comments on its validity, Why is it still out there?
The worst thing about it, with Microsoft SharePoint online hosting, they require your to fix all of these warnings on your code. How can this be a requirement if this is clearly a design consideration and not a clear-cut case of issue to be fixed?
I would suggest you take any tool (FxCop or any other automated tool) as suggestion only, and use your own discretion on when or if to apply these rules.

Tuesday, March 1, 2011

Parser Error – SharePoint crash after deployment

Today I run into a strange problem.

I build a new version of a product and installed it – and it crashed my entire SharePoint:

image Now, I want to say that this does not happen often, but I fear it does… :)

The error reads:

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
Parser Error Message: This page has encountered a critical error. Contact your system administrator if this problem persists.

Source Error:

Line 1:  <%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %>
Line 2: <html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"><head>
Line 3: <!--[if gte mso 9]><xml>


Source File: /Pages/Default.aspx    Line: 1


Well, I started investigating this strange error message…


The weird thing was, all my SharePoint sites reported this error except for central administration – which worked just fine!


After a short research I noticed in SharePoint Log this strange message, that my web part DLL was throwing an exception that it could not load a referenced file: Microsoft.SharePoint.ApplicationPages.Administration


Well… this makes sense, since this file only exists in central administration app_bin folder.


Things started to come together. All I had done wrong was to use this dll in my code, since I had some code that was running in central admin (settings page)


Well, as soon as I removed it from my references everything started working again.


Now I have to find another way to create a settings page, since GlobalAdminPageBase base class (for central admin settings pages) is something I cannot use.


Either that or I will have to separate my settings page into another DLL (which I prefer not to do)


Well, if you get this error message – be sure to check SharePoint logs and make sure you are not using this dll!

Wednesday, February 23, 2011

List.DefaultView is null ?

I bet many of you fall for this one… I know I did.

You got a SPList object, you want to get the default view, or the default view name, so you write:

list.DefaultView.Title

You never even bother to check if DefaultView is null or not, right? Because it doesnt make sense…

Well, I had a customer who did something crazy.

He created a redirection page inside a list forms folder, and marked it as the default view for the list using SharePoint Designer 2007.

* You will be glad to hear that in SharePoint Designer 2010 this is not possible anymore :)

Well, from this point on, calling the list.DefaultView object returns null, which made our code fail since we didn’t think of checking if there is a valid default view for the list.

So, a lesson to be learned: never trust anyone in SharePoint!

A quick fix I did for it is to see if list.DefaultView is null, and if so, to loop through all list views and get the first valid view.

Here is the code I used:

internal static SPView GetSafeListDefaultView(SPList list, string hideViews)
{
if (list.DefaultView != null)
return list.DefaultView;
else
{
foreach (SPView view in list.Views)
{
if (
view.Hidden ||
string.IsNullOrEmpty(view.Title.Trim()) ||
//Explorer View or subject view in discussion - allow subject views.
(view.BaseViewID == "3" && view.ContentTypeId.ToString() == "0x") ||
(hideViews.IndexOf(";" + view.Title.ToLower() + ";") >= 0) ||
//reply views in discussion board
(list.BaseTemplate == SPListTemplateType.DiscussionBoard && !view.ContentTypeId.ToString().StartsWith("0x012001"))
)
continue;

return view;
}
}

throw new Exception("Could not get a safe default view for this list: " + list.Title);
}

So from now on,  I will use this method to get the list default view, and never again trust the list.DefaultView property, which may be null.


By the way, the proper way to do what the customer wanted is to change the list.RootFolder.WelcomePage to the redirection page he created. Changing the default view is not the best idea, and I am not sure if it is supported.


Cheers, Shai.

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.

Tuesday, February 15, 2011

Adding print functionality to Data View Web Parts

Hi,
A question I got from a customer today was “How can I add a print button to data view web part which will print all documents in the view?”

Well, we have a product called iMUSH Print that allows you to print selected items/document from out of the box list views, and merge them into one PDF file for easy printing.

But the question remains, how do one connects this print functionality to a data view web part?

Well, lists or libraries, the answer is simple and took me about an hour to create a working POC.
First, lets have a look at out of the box iMUSH print feature in standard library view:
image
One thing to note, is that you can either use the checkboxes to select items for printing or click the print menu and select what you wish to print in the popup:
image
Ok, so obviously, this popup “knows” how to get a list of items for print. We will use this parameter to send the items form the DVWP.
Now, to the DVWP in SharePoint Designer:
2 changes are needed in the DVWP,

1. Add a print button HTML just before the <table> tag of the DVWP items:
<img alt="print" src="/_layouts/KWizCom_iMushFeature/ico_imush_print_16px.png"
onclick="KWizCom_DoDVWPPrint('/iMUSH/_layouts/KWizCom_iMushFeature/KWizComPrintList.aspx',
'567836FC-F9B1-4D48-80AC-D637772703D4', '', this.nextSibling);"/>
you will need to replace the url “/iMUSH/” with your real site URL, and the list id ‘5678…’ with your actual list/library GUID.

2. Locate the <tr> tag inside your DVWP items table, and add an “itemid” attribute to it:
<tr itemid="{@ID}">

That’s it for the DVWP.

Next you will have to add some javascript code to your page, anywhere in the page.
My favourite way about it is just adding a content editor web part.
Just insert this JS code:
<script>
function KWizCom_DoDVWPPrint(pageUrl, listId, viewId, dvwpTable)
{
var url = pageUrl + "?ListId=" + listId + "&View=" + viewId + "&ItemId=";
    //get items from dvwp
var items = "";
    for(var i = 0; i < dvwpTable.rows.length; i++)
  if(dvwpTable.rows[i].itemid != undefined)
        {
    if( items != "" ) items += ",";
            items += dvwpTable.rows[i].itemid;
  }
    url += items;
commonShowModalDialog(url,
'dialogHeight:300px;dialogWidth:180px;scroll:true;toolbar:no;status:no;resizable:yes;',
null, null);
}
</script>

and you are done!

Now, you can click print on the DVWP to print all items that are displayed in the web part, even after filtering but the user:


image


That’s it!

Just remember, this functionality requires a license for iMUSH Print.

Thursday, February 3, 2011

Map folder in SharePoint Root

I am sure many of you needed from time to time to get a local path to a file that was deployed to the SharePoint Root (AKA Hive in 2007 version, AKA “12” folder AKA “14” folder).

For whatever reason you needed to do so, you probably notices that the ASP.NET API (Server.MapPath) or any other ASP.NET method of discovering the local path for a file or folder did not work out as excepted.

Without going into a long explanation on why that did not work, There is a very little documented method that I have used a lot in the past and I have learned not many developer know it.

The SPUtility class contains a static method named “GetGenericSetupPath” that takes one string parameter.

That string parameter can be any folder under the SharePoint Root folder, and the result of the method is the local file system path of that folder.

For example, to get the local path for “Template” folder, use this command:
SPUtility.GetGenericSetupPath("Template");

But to get the “Layouts” folder, you have to use this command:
SPUtility.GetGenericSetupPath("Template\\LAYOUTS");

Now, saying that – you have to keep in mind that although you do have read permissions to these folders while inside a SharePoint APP, other permissions (like create file, or create folders) may be blocked.

Cheers,

Shai.

Tuesday, February 1, 2011

How to identify a Ribbon control ID

A frequent question I get during my “How to develop for the SharePoint Ribbon” session is:

How can I identify and existing ribbon control or group ID?

This is useful when you wish to override, hide a control, or insert new controls into an existing group / new groups into an existing tab.

So, this task is pretty simple once you know this trick:

First, open a page and make your ribbon control visible:

image

Second, use IE developer tool bar to select the ribbon button you want:

image

 

Climb up the HTML to the span container, the span ID will have the ribbon control ID:

image

In my case, for the wiki page “email a link” here is what we get:

Ribbon.WikiPageTab.Share-LargeLarge-0-0

So, the control ID will be:

“Ribbon.WikiPageTab.Share”

And there you go!