SharePoint Blog - René Hézser

Anmelden  RSS Feed RSS Feed
Startet die Suche

Archive

Kategorien

Links

Andere Blogs




ITaCS GmbH

May 232012

Site Availability (Update)

Tomorrow (May 24th) I will switch to a new telephone provider.

My website will not be available for a while…

Update:

After completely messing up by not working on the change, my telephone line is working again…


Published: 5/23/2012  10:29 AM | 0  Comments | 0  Links to this post
Tagged as: Sonstiges

May 022012

Error in SharePoint Search

I’ve had the error message “The SharePoint item being crawled returned an error when requesting data from the web service.   (0x80042616)” when I tried to crawl a SharePoint WebApplication. The search crawler account had access to a site by a WebApplication policy. But somehow, that didn’t work.

After removing and re-adding the account policy on the WebApplication, the search crawled my content again.

Hopefully this post can help others as well.


Published: 5/2/2012  12:25 PM | 0  Comments | 0  Links to this post
Tagged as: SharePoint

Apr 282012

Execute code in multiple threads (even with SharePoint)

Since SharePoint 2010 uses .NET 3.5, you can not use the fancy new functions from .NET 4 Sad smile

So if we need e.g. multi-threaded execution of code, we’ll need to write the code ourselves. But, as you can see, this really isn’t so hard. The basic idea behind this solution of executing code parallel in threads, is that you have an IEnumerable<T> of some kind. This can be a List, or any other IEnumerable.

So let us for example take a list of Guids, which are the IDs of all SPWebs in a SiteCollection. Then we are iterating each web, and write the itemCount of all lists to the Console.

class ParallelExecutionTest
{
   private static int _overallItemCount;
   private static readonly object Lock = new object();

   public static void AddItemCount(int itemCount)
   {
      lock (Lock)
      {
         // only let one thread write to the setter 
         _overallItemCount += itemCount;
      }
   }

   public static void CountListitemsInAllWebs(string siteUrl)
   {
      using (var site = new SPSite(siteUrl))
      {
         // perform the method/action on any web in the sitecollection 
         site.AllWebs.Select(w => w.ID).EachParallel(webId =>
         {
            CountListitems(site.ID, webId);
         }, Environment.ProcessorCount);
         Console.WriteLine("Overall Itemcount: " + _overallItemCount);
      }
   }

   private static void CountListitems(Guid siteId, Guid webId)
   {
      // use new instances for each web 
      using (var site = new SPSite(siteId))
      using (var web = site.OpenWeb(webId))
      {
         var itemCount = web.Lists.Cast<SPList>().Sum(list => list.ItemCount);
         Console.WriteLine("Web {0} has {1} items in all lists.", web.Title, itemCount);
         AddItemCount(itemCount);
      }
   }
}

That doesn’t look too complicated, does it? The little method EachParallel is all it takes for running the code in multiple threads. You have to decide if your code can run parallel, and if makes sense!

Note: Remember that SharePoint will most likely not work, if you access the same objects in multiple threads. So to be safe, create new instances of SharePoint objects in each Thread!

The sample above will create as much threads, as your system has CPUs. On my notebook with i7 and HyperThreading in 8 threads. And here comes the point to remember. Think carefully about the pitfalls on running your code parallel. Here are some drawbacks, compared to the sequentiell execution:

  • Overhead for creating new SharePoint objects (calls to the SQL server)
  • Additional load on the SQL server by querying more data simultaneously (think about a 4 processor server board with x cores and HyperThreading)
  • Possibly more load on the local SharePoint server by writing logfiles
  • Exception handling. With sequential code you can abort. Multiple threads keep running

Enough for now. Lets look at the Extension method which makes all this possible.

public static class Extensions
{
   /// <summary> 
   /// Enumerates through each item and start the action in a new thread 
   /// </summary> 
   /// <typeparam name="T"></typeparam> 
   /// <param name="enumerable"></param> 
   /// <param name="action"></param> 
   /// <param name="maxHandles">e.g. Environment.ProcessorCount</param> 
   public static void EachParallel<T>(this IEnumerable<T> enumerable, Action<T> action, int maxHandles)
   {
      // enumerate the passed IEnumerable so it can't change during execution 
      var itemArray = enumerable.ToArray();
      var count = itemArray.Length;

      if (count == 0) return;
      if (count == 1)
      {
         // if there's only one element, just execute 
         action(itemArray.First());
      }
      else
      {
         // maxHandles must not be greatet than the count of actions, or nothing will be done 
         if (maxHandles > count) maxHandles = count;
         var resetEvents = new ManualResetEvent[maxHandles];

         for (var offset = 0; offset <= count / maxHandles; offset++)
         {
            EachAction(action, maxHandles, itemArray, offset, resetEvents);
            // Wait for all threads to execute 
            WaitHandle.WaitAll(resetEvents);
         }
      }
   }

   private static void EachAction<T>(Action<T> action, int maxHandles, IEnumerable<T> itemArray, int offset, ManualResetEvent[] resetEvents)
   {
      int i = 0;
      foreach (var item in itemArray.Skip(offset * maxHandles).Take(maxHandles))
      {
         resetEvents[i] = new ManualResetEvent(false);

         ThreadPool.QueueUserWorkItem(data =>
         {
            var index = (int)((object[])data)[0];
            try
            {
               // Execute the method and pass in the enumerated item 
               action((T)((object[])data)[1]);
            }
            catch (Exception ex)
            {
               // Exception handling 
               Console.WriteLine(ex.ToString());
            }

            // Tell the calling thread that we're done 
            resetEvents[index].Set();
         }, new object[] { i, item });
         i++;
      }
   }
}

All items in the IEnumerable are iterated. If there is free slot, the action will be executed in a new thread. There is no guarantee, that the code is executed in the same order, as the items in your IEnumerable. Here is an examples of IDs in an array, and the execution order:

Order in List Execution order
0 3
1 6
2 7
3 1
4 4
5 0
6 2
7 5

Summary: Depending on your code, and its requirements, multiple threads can be a good way to improve the speed of you code. It even can be a life-saver (thx Christopher!) for very long running operations. Take your time to think about it, before you implement the “little” change to your code to run in multiple threads!

One last word. I mentioned .NET 4 at the beginning. Here is a sample.

var ids = new List<int> { 0, 1, 2, 3, 4, 5 }; 
ids.AsParallel().ForAll(id => { Console.WriteLine("Id: " + id); });

Nice, ain’t it?


Published: 4/28/2012  11:19 AM | 1  Comment | 0  Links to this post
Tagged as: Development, SharePoint

Jan 122012

Major Update to the Fileserveraccess Web Part

In 2008 I’ve released a Web Part, which enables your users to access files on your fileservers through SharePoint. Original post. This Web Part has been downloaded many times. With this new version, I’ve tried to deal with the most asked questions (like Kerberos), which will make the Web Part easier to use. Naturally new features have been implemented, to get you to upgrade to the new version.

With this release, the Web Part requires SharePoint Foundation / Server 2010. For the users who are still using WSS V3, please stick to the old version, or upgrade your farm Smile

First some screenshots, so you know what I am talking about.

image

image image

Features

  • Download files from your fileservers via SharePoint
  • Download a folder with all containing files as zip-file
  • Upload files to a fileserver
  • Delete files from a fileserver
  • View the file properties
  • By default, the fileserver path has to be UNC. Local paths are not allowed, so a user cannot enter C:\ to access e.g. the web.config or other files on the local server
  • Multilanguage

Of coarse the access to the files is security trimmed. Meaning that if your users would not be able to access files with their logon from their client, they won’t be able from the Web Part!

Requirements

For authorization against the fileserver, the credentials of the currently logged on user is used. For SharePoint (and any other application as well), it is necessary to configure the WebApplication which is hosting the Web Part to use Kerberos instead of NTLM. Otherwise a server cannot pass the user credentials forward to a second server. This is called the “Double-Hop problem”. To get a glimpse about the topic, take a look at an article I wrote some time ago. Configuring Kerberos for SharePoint. That post has been written for SharePoint V3! But thereimage are plenty of Kerberos Guides out there for SP 2010. And a whitepaper from Microsoft: Configuring Kerberos Authentication for SharePoint 2010 Products http://technet.microsoft.com/en-us/library/ff829837.aspx

If you do not configure Kerberos for the WebApplication, the Web Part will detect that, and show a notification in the properties section.

A small sidenote: If you are going to use local paths (meaning a folder on your SharePoint server), you can continue using NTLM. 

Another good starting point for Kerberos-Troubleshooting can be found here: http://blogs.msdn.com/b/friis/archive/2009/12/31/things-to-check-when-kerberos-authentication-fails-using-iis-ie.aspx

Configuration

image

To use the WebPart, you’ll need to at least configure a path. Files – and subfolders – from that path will be shown.

Additionally, there are some properties, which modify features of the Web Part.

The Paging size defines, how many files are displayed on one page. With the next three checkboxes, you can allow files to be downloaded as zip, allow files to be uploaded and to be deleted.

I recommend to leave the caching activated. Deactivate only, if you have specific reasons, because there will be more todo for your SharePoint server and fileserver.

Using a local path as source

In case you want to use a local path as source for the Web Part, you have to allow the path to be used. To do so, follow the steps below.

  1. locate the feature.xml file ("C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\FEATURES\FileserverAccess\Feature.xml")
  2. Edit the file in your favorite editor
  3. Look for the property with the key “AllowLocalPaths” and modify the value to correspond to the driveletter you wish to use
    image
    Replace “Driveletter” with e.g. “C”. You can specify more than one drive letters. In that case use a “;” as divider
  4. Save the feature.xml
  5. Restart your IIS (iisreset)

Remember that you’ll need to modify the file on all of your FrontEnd SharePoint Servers! After an upgrade of the Web Part, the file has to be modified again. If you do not allow local drives, the Web Part will show an error.

image

This version is compatible to the old version. So you can simply upgrade the solution and benefit of the new features!

Download the new version for SharePoint 2010 (Foundation and Server): RH.FileserverAccess.wsp

Download the old version for WSS V3 / MOSS 2007: RH.FileserverAccess.wsp

Update March 2012

  • I did not get the Web Part working in my claims based authentication test-environment. Additionally, the Web Part properties will show the current user and authentication method. If you see Negotiate, your environment is set up correctly (for classic authentication).

imageimage

  • Another small update, which prevented the upload from working in Chrome