Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

Wednesday, November 9, 2011

SPFile.Item => "The object specified does not belong to a list"

Today I had an SPException getting SPFile.Item with message "The object specified does not belong to a list". I used the code like this:
var web = site.RootWeb;
var file = web.GetFile("http://site.url/test/pages/page.aspx");
if (file.Exists){
   var item = file.Item;
}
And then the exception was thrown. The fix was very simple:
using (var web = site.OpenWeb("/test/pages/page.aspx", false))
var file = web.GetFile("/test/pages/page.aspx");
...
}
I'm thinking that the original exception appeared because we created SPFile object from the SPWeb which doesn't contain this file. So, seems that SPFile should be explicitly created from corresponding SPWeb.
And one more strange issue:
using (var web = site.OpenWeb("/test/pages/page.aspx", false))
opens web with server relative URL "/test" while
using (var web = site.OpenWeb("http://site.url/test/pages/page.aspx", false))
returns RootWeb :O

Friday, November 4, 2011

List Event Receiver and Feature Scope

Recently my colleague created an event receiver which was going to be instantiated for all picture libraries at the site collection. He created a receiver and bound it like this:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="109">
      <Receiver>
        <Name>PictureLibraryEventReceiverItemUpdating</Name>
        <Type>ItemUpdating</Type>
        <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
        <Class>Company.Features.PictureLibraryEventReceiver</Class>
        <SequenceNumber>10008</SequenceNumber>
      </Receiver>
      <Receiver>
        <Name>PictureLibraryEventReceiverItemDeleting</Name>
        <Type>ItemDeleting</Type>
        <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
        <Class>Company.Features.PictureLibraryEventReceiver</Class>
        <SequenceNumber>10009</SequenceNumber>
      </Receiver>
  </Receivers>
  <Receivers ListTemplateId="851">
    <Receiver>
      <Name>PictureLibraryEventReceiverItemUpdating</Name>
      <Type>ItemUpdating</Type>
      <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
      <Class>Company.Features.PictureLibraryEventReceiver</Class>
      <SequenceNumber>10010</SequenceNumber>
    </Receiver>
    <Receiver>
      <Name>PictureLibraryEventReceiverItemDeleting</Name>
      <Type>ItemDeleting</Type>
      <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
      <Class>Company.Features.PictureLibraryEventReceiver</Class>
      <SequenceNumber>10011</SequenceNumber>
    </Receiver>
  </Receivers>
</Elements>
Unfortunately, it turned out that SharePoint (2010) added this receivers to all lists and libraries ignoring ListTemplateId parameter. I started investigating what's wrong and expected that my colleague made a mistake.

I noticed that feature scope is Site which is kind of logical since we're going to use this receiver in subsites as well. So, here starts an interesting part. I found out that MOSS 2010 uses following behavior:


  1. If feature scope is site
    1. If receiver scope is set to site = provision receiver to all lists of site collection (list template/url is not taken into consideration)!
    2. If receiver scope is set to web = provision receiver to all lists of the particular web (list template/url is not taken into consideration)!
  2. If feature scope is web
    1. If list template and list url are not set = 1.1
    2. List template = provision to all lists of correct type
    3. List url = provision receiver to the particular list




Monday, July 4, 2011

Open the tool pane link from web part in MOSS 2010

In our project our web parts which were not configured yet render simple description and link to open web part properties in following format:
string.Format(@"<a href=\"#\" onclick=\"javascript:MSOTlPn_ShowToolPane2('Edit','{0}');\">open the tool pane</a>", webPart.ID)
It worked fine for MOSS 2007 but in MOSS 2010 when page is not in edit mode such link threw a javascript error.

Thanks to http://kvdlinden.blogspot.com/2010/04/open-tool-pane-javascript-error-in.html issue has been fixed. All you need is to add following control to the master page:
<SharePoint:ScriptLink language="javascript" name="ie55up.js" OnDemand="false" runat="server" />

Sunday, June 26, 2011

Hiding the Ribbon for Anonymous Users

If the SharePoint site is intended to be used as public internet site you might wanna show it only for authenticated users, so regular anonymous users won't ever notice it's a SharePoint site.

I've found a couple of articles describing how to do that:
http://blogs.microsoft.co.il/blogs/itaysk/archive/2010/04/23/hiding-the-ribbon-for-anonymous-users.aspx
http://www.topsharepoint.com/hide-the-ribbon-from-anonymous-users

Basically in all posts how to hide ribbon either ASP .NET LoginView control or SPSecurityTrimmedControl are used. Each of them has it's own issues.

Using ASP .NET LoginView makes page editing not convenient. In order to correctly edit page Editor should click "Edit Page" twice.

Using SPSecurityTrimmedControl requires to set a list of permissions needed to view Ribbon and it's not obvious which security mask should be used.

Also in both cases Front-end guys need to wrap each editor specific control in one of these controls. It means that there might be e.g. 10 LoginView or 10 SPSecurityTrimmedControl controls on the page.

Another solution would be to use 2 master pages - one for the authenticated users, another - for anonymous. It's quite easy to maintain. One master page (auhtoring) should have all SharePoint specific stuff (ribbon, scripts, etc). Another page (runtime) should not have any of that. Important: both master pages should have all ContentPlaceHolder's which are used by page layouts.

Switching between master pages is performed in code. You can decide the place where to put it. You might want create control and put it on both master pages. In my case all our page layouts was inherited from our custom class. Master page switching code should be put in OnPreInit method. It could look like this:
protected override void OnPreInit(EventArgs e)
{
        base.OnPreInit(e);
        SwitchMasterPageIfNeeded();
}
private void SwitchMasterPageIfNeeded()
{
        if (SPContext.Current != null && SPContext.Current.Web.CurrentUser != null)
        {
                MasterPageFile = "CustomAuthoring.master";
        }
}


Of course it's up to you which solution to choose. But it's good to know that now you have one more way to go.

Saturday, June 25, 2011

Ribbon for multilingual sites without changing locale and installing language packs

Recently I've faced with strange Ribbon issue. It works fine for English (United States) sites, however it doesn't display images for e.g. Russian site.

Searching for solution in Google brought me to this post: http://www.martinhatch.com/2011/01/blank-ribbon-check-your-locale-settings.html. And the solution would be to change web locale from actually needed to English. Of course such approach is gonna bring a lot of localization troubles.

Another workaround would be to install language specific language pack. For some reasons that doesn't sound good for me. Consider having site collection with 50 sites with different languages. Downloading ~150 Mb and installing language pack for each of them is not the best solution.

So, initially the issue is that image URL look like this: /_layouts/1049/images/formatmap32x32.png. 1049 - is locale ID for russian language.

Looking at source code using Reflector just confirmed the fact that URL part after "_layouts/" is web's locale ID which is set in "Site Settings" > "Regional Settings".

I was thinking about different solutions how to solve that and finally went with URL Rewriting solution. I have some experience working with IIS URL Rewriter (hopefully will share it in future posts), so it took me 5 minutes to get it working.

You can read more about IIS URL Rewriter and it at http://www.iis.net/download/urlrewrite.

URL Rewriter has user-friendly GUI which allows to manage providers, route maps and rules. This configuration is stored at the application's web.config. So, I'll just share this part of web.config (put it in configuration > system.webServer element):
<rewrite>
    <rules>
        <rule name="HandleRibbonCulture">
            <match url="_layouts/\d{4}/(.+)" />
            <action type="Rewrite" url="_layouts/1033/{R:1}" />
        </rule>
    </rules>
</rewrite>
Each time page will try load Ribbon resource URL e.g.  /_layouts/1049/images/formatmap32x32.png will be rewritten to  /_layouts/1033/images/formatmap32x32.png which is always available. Enjoy!