Blogger

  • This email address is being protected from spambots. You need JavaScript enabled to view it.

    Recent items

Login

Luca Costante

Luca Costante

Thursday, 17 October 2013 17:45

My first Office365 App

Today, I started to develop and deploy my first App for SharePoint online into Office 365.

After the creation of some test files, it would be the time to deploy the app and Visual Studio shows me the first error:

"Error occurred in deployment step 'Install app for SharePoint': Sideloading of apps is not enabled on this site."

After some searches on google, I understand that I need to enable an hidden feature if I want to use the development site. I need to download and install the "SharePoint Online Management Shell".

I've installed it, i've run and I've received another error (now from the SharePoint online powershell):

"Import-Module : Could not load type 'Microsoft.SharePoint.Administration.SiteHealth.SiteHealthStatusType' from assembly 'Microsoft.SharePoint.Client, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'."

At this point, google does not help me.

The solution is to NOT use the SharePoint online shell directly but from the SharePoint 2013 Management Shell and use this script:

Show/Hidden bash code

View source
 
 
 
#CODE STARTS HERE
 
 
$programFiles = [environment]::getfolderpath("programfiles")
 
 
add-type -Path $programFiles'\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
 
 
Write-Host 'To enable SharePoint app sideLoading, enter Site Url, username and password'
 
$siteurl = Read-Host 'Site Url'
 
$username = Read-Host "User Name"
 
$password = Read-Host -AsSecureString 'Password'
 
 $outfilepath = $siteurl -replace ':', '_' -replace '/', '_'
 
try
{
 [Microsoft.SharePoint.Client.ClientContext]$cc = New-Object Microsoft.SharePoint.Client.ClientContext($siteurl)
 
 [Microsoft.SharePoint.Client.SharePointOnlineCredentials]$spocreds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
 
 $cc.Credentials = $spocreds
 
 Write-Host -ForegroundColor Yellow 'SideLoading feature is not enabled on the site:' $siteurl
 
 $site = $cc.Site;
 
 $sideLoadingGuid = new-object System.Guid "AE3A1339-61F5-4f8f-81A7-ABD2DA956A7D"
 
 $site.Features.Add($sideLoadingGuid, $true, [Microsoft.SharePoint.Client.FeatureDefinitionScope]::None);
 
 $cc.ExecuteQuery();
 
 Write-Host -ForegroundColor Green 'SideLoading feature enabled on site' $siteurl
 #Activate the Developer Site feature
}
 
catch
 
{ 
 Write-Host -ForegroundColor Red 'Error encountered when trying to enable SideLoading feature' $siteurl, ':' $Error[0].ToString();
}
 
 
#CODE ENDS HERE
 
 
 

 

 

This is a brief description to how generate an image of a SharePoint aspx page (or part of page).

This is the main class that provide to generate an image starting from the aspx page

Show/Hidden csharp code

View source
 
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using Microsoft.SharePoint;
 
namespace lucacostante.com
{
    public class ASPXToImage
    {
        private Bitmap bitmap;
        private string url;
        private string fileName = string.Empty;
        private string startFromID = string.Empty;
        private Control control = null;
 
 
        public ASPXToImage(string url, string fileName)
        {
            this.url = url;
            this.fileName = fileName;
        }
 
        public Bitmap GenerateFull()
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
               {
                   using (SPSite site = new SPSite(this.url))
                   {
                       using (SPWeb w = site.OpenWeb())
                       {
                           // Thread 
                           var m_thread = new Thread(Generate);
                           m_thread.SetApartmentState(ApartmentState.STA);
                           m_thread.Start();
                           m_thread.Join();
                       }
                   }
               });
            return bitmap;
        }
 
 
 
        public Bitmap GeneratePagePart(string partIdOrClass)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
               {
                   using (SPSite site = new SPSite(this.url))
                   {
                       using (SPWeb w = site.OpenWeb())
                       {
                           this.startFromID = partIdOrClass;
 
                           // Thread 
                           var m_thread = new Thread(GeneratePart);
                           m_thread.SetApartmentState(ApartmentState.STA);
                           m_thread.Start();
                           m_thread.Join();
                       }
                   }
               });
            return bitmap;
 
        }
 
        private void Generate()
        {
            var browser = new WebBrowser { ScrollBarsEnabled = false };
            browser.Navigate(url);
            browser.DocumentCompleted += WebBrowser_FullDocumentCompleted;
 
            while (browser.ReadyState != WebBrowserReadyState.Complete)
            {
                Application.DoEvents();
            }
 
            browser.Dispose();
        }
 
        private void GeneratePart()
        {
            var browser = new WebBrowser { ScrollBarsEnabled = false };
            browser.Navigate(url);
            browser.DocumentCompleted += WebBrowser_PartDocumentCompleted;
 
            while (browser.ReadyState != WebBrowserReadyState.Complete)
            {
                Application.DoEvents();
            }
 
            browser.Dispose();
        }
 
        private void WebBrowser_FullDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            // Capture 
            var browser = (WebBrowser)sender;
            int width = browser.Document.Body.ScrollRectangle.Width;
 
            int height = browser.Document.Body.ScrollRectangle.Bottom;
 
            GenerateImage(browser, width, height);
        }
 
        private void WebBrowser_PartDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            // Capture 
            var browser = (WebBrowser)sender;
 
            HtmlElement found = FindIdOrClass(browser, startFromID);
 
            if (found != null)
            {
                GenerateImage(browser, found);
            }
        }
 
 
        private HtmlElement FindIdOrClass(WebBrowser browser, string startFromID)
        {
            HtmlElement found = null;
 
            found = (from HtmlElement ele in browser.Document.All
                     where ele.Id == startFromID ||
                     ele.GetAttribute("className") == startFromID
                     select ele).FirstOrDefault();
 
 
            return found;
        }
 
        private void GenerateImage(WebBrowser browser, int width, int height)
        {
            browser.ClientSize = new Size(width, height);
            browser.ScrollBarsEnabled = false;
            bitmap = new Bitmap(width, height);
            browser.BringToFront();
 
            browser.DrawToBitmap(bitmap, browser.Bounds);
 
            // Save as file? 
            if (this.fileName.Length > 0)
            {
                // Save 
                bitmap.SaveJPG100(this.fileName);
            }
        }
 
        private void GenerateImage(WebBrowser browser, HtmlElement ele)
        {
            Rectangle rec = ele.OffsetRectangle;
 
            int width = browser.Document.Body.ScrollRectangle.Width;
            int height = browser.Document.Body.ScrollRectangle.Bottom;
 
            CalculateSize(browser.Document.Body, ref width, ref height);
 
            int y = 0;
            int x = 0;
            int previewOffsetX = 0;
            int previewOffsetY = 0;
            HtmlElement parent = ele;
 
 
            while (parent != null)
            {
                if (parent.OffsetRectangle.Top != previewOffsetY)
                    y += parent.OffsetRectangle.Top;
                if (parent.OffsetRectangle.Left != previewOffsetX)
                    x += parent.OffsetRectangle.Left;
 
                previewOffsetX = parent.OffsetRectangle.Left;
                previewOffsetY = parent.OffsetRectangle.Top;
 
                parent = parent.Parent;
 
            }
            Rectangle rect = new Rectangle(x / 2, y, ele.OffsetRectangle.Width, ele.OffsetRectangle.Height);
 
            width = (ele.OffsetRectangle.Width + x > width) ? ele.OffsetRectangle.Width + x : width;
 
            browser.ClientSize = new Size(width, height);
 
            using (Bitmap bitmap = new Bitmap(browser.Width, browser.Height))
            {
                browser.DrawToBitmap(bitmap, new Rectangle(0, 0, browser.Width, browser.Height));
                Bitmap cropped = bitmap.Clone(rect, bitmap.PixelFormat);
                cropped.Save(this.fileName, ImageFormat.Jpeg);
            }
        }
 
        private void CalculateSize(HtmlElement currElement, ref int width, ref int height)
        {
            if (currElement.Children != null && currElement.Children.Count > 0)
            {
                foreach (HtmlElement element in currElement.Children)
                {
                    if (element.ScrollRectangle.Width > width)
                        width = element.ScrollRectangle.Width;
 
                    if (element.ScrollRectangle.Bottom > height)
                        height = element.ScrollRectangle.Bottom;
 
                    CalculateSize(element, ref width, ref height);
                }
            }
        }
 
    }
 
 
    public static class BitmapExtensions
    {
        public static void SaveJPG100(this Bitmap bmp, string filename)
        {
            var encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
        }
 
        public static void SaveJPG100(this Bitmap bmp, Stream stream)
        {
            var encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
        }
 
        public static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            var codecs = ImageCodecInfo.GetImageDecoders();
 
            foreach (var codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
 
            // Return 
            return null;
        }
    }
}
 

In my case, after the page creation, I've uploaded the image into the Image document library and after I've redirect the user to its url.

This is the print screen:

When I click on "Generate Image" ribbon button, The syste create the image taking the information in a div with the id "previewBody".

This is the code to generate, upload and redirect to the generated image

Show/Hidden csharp code

View source
 
 
 
protected void GenerateImage()
        {
            string path = Environment.GetEnvironmentVariable("TEMP") + @"\" + (Guid.NewGuid().ToString("N"));
            ASPXToImage websiteToImage = new ASPXToImage(Request.Url.AbsoluteUri, path);
            websiteToImage.GeneratePagePart("previewBody");
 
            byte[] fileContents;
            SPSecurity.RunWithElevatedPrivileges(delegate()
             {
                  using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                   {
                       using (SPWeb web = site.OpenWeb())
                       {
                           if (System.IO.File.Exists(path))
                           {
                               SPList images = web.Webs["newsletter"].Lists["Images"];
 
                               bool successfully = false;
                               SPFile file;
                               using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
                               {
                                   int length = (int)fileStream.Length;  // get file length
                                   fileContents = new byte[length];            // create buffer
                                   int count;                            // actual number of bytes read
                                   int sum = 0;                          // total number of bytes read
 
 
                                   // read until Read method returns 0 (end of the stream has been reached)
                                   while ((count = fileStream.Read(fileContents, sum, length - sum)) > 0)
                                       sum += count;  // sum is a buffer offset for next reading
 
                                   images.ParentWeb.AllowUnsafeUpdates = true;
 
 
                                   file = images.RootFolder.Files.Add(Guid.NewGuid().ToString("N") + ".jpg", fileContents, true);
 
                                   images.ParentWeb.AllowUnsafeUpdates = false;
 
                                   if (file != null)
                                   {
                                       successfully = true;
                                   }
                               }
                               if (successfully)
                               {
                                   System.IO.File.Delete(path);
                                   Response.Redirect(SPContext.Current.Web.Url + "/" + file.Url);
                               }
                           }
                       }
                 }
             });
        }
 
 
 

This is the result

Note: During the deploy in production, this feature does not work because it need the credentials and the WebBrowser does not allow the NTLM access (infact it loops into while cicle).

To  resolve the problem, there are two possible solution:

  1. Allow Basic authentication and pass the credentials to the WebBrowser object
  2. extend the WebApplication with an anonymous zone. Allow the navigation of this zone only into the current server. put the logic that the image will be generated into the anonymous zone.

 

If you use this field to render a lookup field, the results is an hyperlink to view the related item.

Show/Hidden csharp code

View source
 
 
 
<SharePointWebControls:FieldValue ID="lfYear" FieldName="Year" runat="server"/>
 
 
 


If you want to create a reusable WebControl just to render the Lookup Value, you can copy and paste this code and reproduce these steps:

  • Create the web control. The property FieldName would be used to retreive the date from the SPListItem

Show/Hidden csharp code

View source
 
 
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.Publishing.Internal.WebControls;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI;
using Microsoft.SharePoint;
 
namespace LucaCostante.com.WebControls
{
    public class SimpleLookupView: WebControl
    {
        private string name;
        [Bindable(true), DefaultValue(""), Localizable(false)]
        public string FieldName
        {
            get { return name; }
            set { name = value; }
        }
 
        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                string value = GetLookupValue(FieldName);
                if (SPContext.Current.ListItem.Fields.ContainsFieldWithStaticName(FieldName))
                    value=SPContext.Current.Item[FieldName].ToString();
 
                if (!string.IsNullOrEmpty(value) && value.Contains(";#"))
                    value=value.Split(new string[]{";#"},StringSplitOptions.RemoveEmptyEntries)[1];
                writer.Write(value);
            }
            catch { }
        }
 
        public static string GetLookupValue(string fieldName)
        {
            string value = string.Empty;
            if (SPContext.Current.Item.Fields.ContainsFieldWithStaticName(fieldName))
                value = SPContext.Current.Item[fieldName].ToString();
 
            if (!string.IsNullOrEmpty(value) && value.Contains(";#"))
                value = value.Split(new string[] { ";#" }, StringSplitOptions.RemoveEmptyEntries)[1];
 
            return value;
        }
    }
}
 

  • Register the WebControl into the PageLayout

Show/Hidden csharp code

View source
 
 
 
<%@ Register Tagprefix="LCWebControls" Namespace="LucaCostante.com.WebControls" Assembly="LucaCostante.com, Version=1.0.0.0, Culture=neutral, PublicKeyToken=13f47470cb97767e"%>
 
 
 

  • Use the web control

Show/Hidden csharp code

View source
 
 
 
<LCWebControls:SimpleLookupView ID="lfYear" FieldName="Year" runat="server" />
 
 
 

 

Today I found a problem with the LOOKUPFIELD within a page layout during the edit mode.

This is the field definition

Show/Hidden html5 code

View source
 
 
 
<SharepointWebControls:LookupField FieldName="PL_Model" ID="PL_Model" runat="server" >
 
 
 

As defined with the above code, I have a Lookup fielt to a SharePoint List and when the count is greater than 20 items I'm not able to select any item from the combo box (see the image below).

 

This email address is being protected from spambots. You need JavaScript enabled to view it. helped me to find a solution. He told me that he had the same problem a few months ago. The solution is to add the InDesign = "true" attribute to the field definition into the page layout.

Show/Hidden html5 code

View source
 
 
 
<SharepointWebControls:LookupField FieldName="PL_Model" ID="PL_Model" runat="server" InDesign="true"/>
 
 
 

Now the combo box works fine and I can select my item :)

This email address is being protected from spambots. You need JavaScript enabled to view it. says: "yesterday all work fine, today nothing!".

This is a good good morning. We start our application and this morning we receive this error into the File Picker.

We are working on a custom field, so first of all we start to:

  • Debug a lot: result KO
  • clean our site collection with all customization: result KO
  • IISReset: result KO
  • Restart server: result KO

During the first step, our log says:

"Name=Request (GET:http://test.virtualsp.com:80/_layouts/AssetPortalBrowser.aspx?&AssetUrl=/...."

and

"Error while executing web part: System.NullReferenceException: Object reference not set to an instance of an object.    
 at System.Xml.Xsl.XslCompiledTransform.Load(MethodInfo executeMethod, Byte[] queryData, Type[] earlyBoundTypes)    
 at Microsoft.Xslt.STransform.GetCompiledTransform()    
 at Microsoft.SharePoint.WebPartPages.BaseXsltListWebPart.LoadXslCompiledTransform( WSSXmlUrlResolver someXmlResolver)    
 at Microsoft.SharePoint.WebPartPages.DataFormWebPart.GetXslCompiledTransform()    
 at Microsoft.SharePoint.WebPartPages.DataFormWebPart.PrepareAndPerformTransform(Boolean bDeferExecuteTransform)"

The next step was to start to ask help to Google and we found some indication regard an System Update: the KB2844286 cause this error (released on 11th July 2013). To resolve the problem, they suggest to uninstall the update: From the Control Panel and Installed Updated into the Microsoft Services. After that, if you have a virtual machine, I suggest you to restart the machine, otherwise you can restart SharePoint services and IISReset.

"The ViewFields property contains a string that corresponds to the inner XML of the ViewFields element in Collaborative Application Markup Language (CAML).

The Type attribute is particularly useful for Lookup and User fields. Otherwise, without that attribute, the query may not return the expected results. In some cases, the query may fail completely."


After two days that I and my collegue This email address is being protected from spambots. You need JavaScript enabled to view it. are having an unexpected error, we found an easy solution after that we've read the previous paragraph.

We are reading our list via a WCF and all fields are displayed except the SPUserField values. We tried to put "SPSecurity.RunWithElevatedPrivileges", the impersonate but nothing else (we think plus a rights problems".

After a lot of test, we say: try to define each fields into the ViewFields property of the SPQuery object and et voilà, it works fine.

So, in the future, I think that I'll use always the ViewFields property to not spent a lot of my time to undestand why SharePoint sometimes give me unexpected problems Risatona but everytime I need to specify all Fields Arrabbiato

 

 

Often, the customers asks us to can use the keyword and tags feature into a lists, a document library, etc.

To enable this feature into a list, you may into the list and after from the ribbon, click on List tab, List settings, Enterprise Metadata and Keywords Settings, enable the flag like the picture below.

Now when you are create/edit a new list item, you have the Keyword (and tags) field.

If we need to have this feature already enabled when we deploy and create a custom List, we need to add the settings into the ContentType definition and into the List Definition.

Step 1: First of all, we need to add the the field ref of the fields into the content type

{codecitation}

<ContentType
  ID="0x010100603A64185EFC45C0B8F0274C31CEA0CF"
  Name="KeywordDocument"
  Group="Custom Content Type"
  Description="Custom Content Type with Enterprise Keyword">
 
  <FieldRefs>
    ...
    <FieldRef
      ID="{1390a86a-23da-45f0-8efe-ef36edadfb39}"
      Name="TaxKeywordTaxHTField"
      Hidden="TRUE" />
 
    <FieldRef
      ID="{23f27201-bee3-471e-b2e7-b64fd8b7ca38}"
      Name="TaxKeyword" />
 
    <FieldRef
      ID="{f3b0adf9-c1a2-4b02-920d-943fba4b3611}"
      Name="TaxCatchAll"
      Hidden="TRUE" />

{/codecitation}

Step 2: If you already have the list (and the ListDefinition), you need to add the fields also into the fields tag of the list definition.

{codecitation}

<Fields>

    <Field Type='TaxonomyFieldTypeMulti'
      DisplayName='Enterprise Keywords'
      StaticName='TaxKeyword'
      Name='TaxKeyword'
      ID='{23f27201-bee3-471e-b2e7-b64fd8b7ca38}'
      List="Lists/TaxonomyHiddenList"
      WebId='~sitecollection'
      ShowInViewForms='TRUE'
      DefaultListField='TRUE'
      Required='FALSE'
      Hidden='FALSE'
      ShowField="Term$Resources:core,Language;"
      Mult='TRUE'
      Sortable='FALSE'
      Group="$Resources:osrvcore,field_KeywordsGroupName"
      Description="$Resources:osrvcore,field_KeywordsFieldDesc"
      AllowDeletion='TRUE'>
      <Customization>
        <ArrayOfProperty>
          <Property>
            <Name>SspId</Name>
            <Value
              xmlns:q1='http://www.w3.org/2001/XMLSchema' p4:type='q1:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>GroupId</Name>
          </Property>
          <Property>
            <Name>TermSetId</Name>
            <Value
              xmlns:q2='http://www.w3.org/2001/XMLSchema' p4:type='q2:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>AnchorId</Name>
            <Value
              xmlns:q3='http://www.w3.org/2001/XMLSchema' p4:type='q3:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>00000000-0000-0000-0000-000000000000</Value>
          </Property>
          <Property>
            <Name>UserCreated</Name>
            <Value
              xmlns:q4='http://www.w3.org/2001/XMLSchema' p4:type='q4:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>Open</Name>
            <Value
              xmlns:q5='http://www.w3.org/2001/XMLSchema' p4:type='q5:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>true</Value>
          </Property>
          <Property>
            <Name>TextField</Name>
            <Value
              xmlns:q6='http://www.w3.org/2001/XMLSchema' p4:type='q6:string'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>{1390a86a-23da-45f0-8efe-ef36edadfb39}</Value>
          </Property>
          <Property>
            <Name>IsPathRendered</Name>
            <Value
              xmlns:q7='http://www.w3.org/2001/XMLSchema' p4:type='q7:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>IsKeyword</Name>
            <Value
              xmlns:q8='http://www.w3.org/2001/XMLSchema' p4:type='q8:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>true</Value>
          </Property>
          <Property>
            <Name>TargetTemplate</Name>
          </Property>
          <Property>
            <Name>CreateValuesInEditForm</Name>
            <Value
              xmlns:q9='http://www.w3.org/2001/XMLSchema' p4:type='q9:boolean'
              xmlns:p4='http://www.w3.org/2001/XMLSchema-instance'>false</Value>
          </Property>
          <Property>
            <Name>FilterAssemblyStrongName</Name>
          </Property>
          <Property>
            <Name>FilterClassName</Name>
          </Property>
          <Property>
            <Name>FilterMethodName</Name>
          </Property>
          <Property>
            <Name>FilterJavascriptProperty</Name>
          </Property>
        </ArrayOfProperty>
      </Customization>
    </Field>
    <Field Type="Note"
      DisplayName="TaxKeywordTaxHTField"
      StaticName="TaxKeywordTaxHTField"
      Name="TaxKeywordTaxHTField"
      ID="{1390a86a-23da-45f0-8efe-ef36edadfb39}"
      ShowInViewForms="FALSE"
      Required="FALSE"
      Hidden="TRUE"
      CanToggleHidden="TRUE" />

    <Field Type="LookupMulti"
      DisplayName="Taxonomy Catch All Column"
      StaticName="TaxCatchAll"
      Name="TaxCatchAll"
      ID="{f3b0adf9-c1a2-4b02-920d-943fba4b3611}"
      ShowInViewForms="FALSE"
      Required="FALSE"
      Hidden="TRUE"
      ShowField="CatchAllData"
      Mult="TRUE"
      List="Lists/TaxonomyHiddenList"
      WebId="~sitecollection"
      Sortable="FALSE"
      AllowDeletion="TRUE"
      Sealed="TRUE" />

</Fields>

{/codecitation}


At this point, we are usually done. The columns were added to the list definition and the columns does indeed show up in the list.

Step 3: The keywords added to items in the list does not show up. What is missing is the event receiver that takes care of the keyword synchronization. Add an Event Receiver to the project. Make sure to select the list you just created as the event source when going through the wizard, and any events in the events list (we will replace the code generated, so it does not matter which).

Step 4: Delete the event receiver's code file (.cs file) so you are only left with the Elements.xml file.

Step 5: Open the event receiver's Elements.xml file and replace whatever <Receiver> tags where generated with these:

{codecitation}

<Receiver>
    <Name>TaxonomyItemSynchronousAddedEventReceiver</Name>
    <Synchronization>Synchronous</Synchronization>
    <Type>ItemAdding</Type>
    <SequenceNumber>10000</SequenceNumber>
    <Assembly>Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
    <Class>Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver</Class>
    <Data></Data>
</Receiver>
<Receiver>
    <Name>TaxonomyItemUpdatingEventReceiver</Name>
    <Synchronization>Synchronous</Synchronization>
    <Type>ItemUpdating</Type>
    <SequenceNumber>10000</SequenceNumber>
    <Assembly>Microsoft.SharePoint.Taxonomy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
    <Class>Microsoft.SharePoint.Taxonomy.TaxonomyItemEventReceiver</Class>
    <Data></Data>
</Receiver>
{/codecitation}

Step 6: The important thing to make sure is that the value of the ListTemplateId attribute on the <Receivers ListTemplateId="xxxxx"> ... </Receivers> tag is the same as the value of the Type="xxxxx" attribute on the < ListTemplate ... /> tag. Otherwise the event receivers will not attach to the right list.

In the next section, I show how you can populate the field code behind (for example, imagine that you have an excel file and use it to populate the list al fill also the Enterprise keyword field).

{codecitation}

internal void LoadReports(string excelPath, SPWeb rootWeb)
        {
            try
            {
                SPList repList = rootWeb.GetList("Lists/Reports");

                ListHelper.ClearList(repList);

                if (repList != null)
                {
                    Console.WriteLine("Lists found!");

                    var wb = new XLWorkbook(excelPath);
                    var ws = wb.Worksheet(2);

                    TaxonomyField tf = repList.Fields.GetFieldByInternalName("TaxKeyword") as TaxonomyField;

                    foreach (IXLTable tb in ws.Tables)
                    {
                        for (int i = 2; i < tb.RowCount() + 1; i++)
                        {
                            IXLRangeRow rw = tb.Row(i);

                            try
                            {
                                string value = string.Empty;

                                SPListItem newItem = repList.AddItem();
                                int j = 0;


                                newItem["Title"] = rw.Cell(j).Value != null ? rw.Cell(j).Value.ToString() : string.Empty;
                                j = 1;
                               
                                newItem["PDFReportURL"] = rw.Cell(j).HasHyperlink ?
                                    repList.ParentWeb.Site.Url + rw.Cell(j).Hyperlink.ExternalAddress.AbsolutePath + (rw.Cell(j).Value != null ? ", " + rw.Cell(j).Value.ToString() : string.Empty)
                                    : string.Empty;

                                j = 2;
                                newItem["Description"] = rw.Cell(j).Value != null ? rw.Cell(j).Value.ToString() : string.Empty;

                                j = 3;
                               
                                TaxonomyFieldValueCollection taxFVC = new TaxonomyFieldValueCollection(tf);
                                value = !string.IsNullOrEmpty(rw.Cell(j).ValueCached) ? rw.Cell(j).ValueCached : string.Empty;
                                string[] values = value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                                List<Guid> itemsToAdd = new List<Guid>();

                                //we need to initialize it every time otherwise we have timeout exception and cannot operate
                                TaxonomySession session = new TaxonomySession(repList.ParentWeb.Site);
                                TermStore termStore = session.TermStores[tf.SspId];
                                TermSet termSet = termStore.GetTermSet(tf.TermSetId);

                                foreach (string a in values)
                                {

                                    string val = a.StartsWith(" ") ? a.Substring(1) : a;

                                    while (val.StartsWith(" "))
                                        val = val.StartsWith(" ") ? val.Substring(1) : val;

                                    Term myTerm = null;

                                    try
                                    {
                                        myTerm = termSet.Terms[val];
                                    }
                                    catch (ArgumentOutOfRangeException)
                                    {
                                        myTerm = termSet.CreateTerm(val, 1033);
                                        termStore.CommitAll();
                                    }

                                    if (myTerm != null && !string.IsNullOrEmpty(myTerm.Name))
                                        itemsToAdd.Add(myTerm.Id);

                                }

                                Guid[] ids = itemsToAdd.ToArray();
                                TermCollection oTerms = session.GetTerms(ids);
                                tf.SetFieldValue(newItem, oTerms);

                                newItem.Update();
                                Logger.WriteLog("Item " + i + "added.");

                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(string.Format("Error manipulating line {0}.", i));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }

{/codecitation}

 

Today, during search results test, I found a strange behaviour regards search results. If I did a query with the Administrator user, all results are displayed while when I did a search with others user, the SharePoint Search Corre WebPart returned no search results.

My instructions are supported by KB331951, which states that in order to give accounts read permissions to the tokenGroupsGlobalAndUniversal (TGGAU) attribute you need to add the account to the Windows Authorization Access (WAA) group.

Add an account to the WAA group

Here are the steps you follow to add an account to the WAA group:

  1. Log into the domain controller
  2. Click Start, point to Programs, point to Administrative Tools,
  3. Click Active Directory Users and Computers.
  4. In the Active Directory Users and Computers window, expand DomainName, and then click Users or another appropriate organization unit (OU).
  5. Double-click the SharePoint Services service account you want to modify.
  6. In the Properties dialog box, click the Member Of tab.
  7. On the Member Of tab, click Add.
  8. In the Select Groups dialog box, type Windows Authorization Access Group under Enter the object names to select, and then click OK.
  9. Restart all SharePoint services

Run a Full Crawl the SharePoint Content Source(s)

  1. Browse to Central Administration
  2. Click on Service Applications > SharePoint Search Server
  3. Run a Full Crawl on your content source(s)

Once they are done, your search results will load up just fine.

Today, saturday 06th April 2013, I and my friend This email address is being protected from spambots. You need JavaScript enabled to view it. (Ciccio for friends) are engaged to deploy a SharePoint solution in the Production enviroment. All is going done except a strange behavior of a component in home page.

After some checks into other environments, we are not able to find a solution of the problem. The only one way to find a possible solution is to debug the solution but we are in production environment. So, while Ciccio reassure the customer that we have the control of the problem, I start to collection informations how to remotly Debug the application.

First of all, we need to install into remote server (in our case, we select one front-end web server of production environment) the "Visual Studio 2010 Remote Debugger with Service Pack 1" tool. After configure the server with the Remote Debugger wizard, we are ready to start the dubug (the TCP ports are fortunately open to allow us to comunicate from another server).

After that, we need a server with Visual Studio Professional or Ultimate installed. We need to login with an user that have right permissions to add dlls into GAC of the Remote Server. We opened our solution and made to a build with debug mode. So, into bin folder, we have the .dll and .pdb files.

The next step is to copy the files into into the <dll name> directory stored into the GAC of the server . Actually, the GAC view is the following.

 

We need to change the GAC View to have a folder view. To do that, we must execute the following commands and the result is the next image.

Show/Hidden bash code

View source
 
 
 
start > run > cmd
type : "cd c:\windows\assembly"
type: "attrib -r -h -s desktop.ini"
type: "ren desktop.ini desktop.bak"
 

Now, from the "client" server, we need to navigate into the server GAC_MSIL folder to put the pdb and dll files. The server path is \\<ip address>\$c\windows\assembly\gac_msil\<dll name>\<dll version>.

Whenever we need to update the dll and pdb files, we make this steps:

  • Into the remote server, to unlock the dll, make an "iisreset /stop" command
  • Into the client server, copy the pdb and dll files from the bin folder to the remote dll path into gac_msil
  • Into the remote server, make an "iisreset /start" command.

Now, the last step is to run the Visual Studio debugger tool (into visual studio, click on debugger menu -> attach to process -> into qualifier field, insert the remote server ip address) and attacch to w3p processes of the remote server.

Magically, when we put a breack point, the circle turn red and we can debug the remote dll. We are very happy and with this way, we found the bug.

NOTE: our production environment is composed of one application server and two web front-end servers. All our test are executed on one web FE server. To exclued all request from users, we removed momentarily the FE from the balancer and to reach the FE from the "client server", we modify the hosts file of the "client server" adding an entry with the FE ip address and the application host name..

 

Page 3 of 5