Martin Bodocky

No less, no more. Just live between code.

Category Archives: Tips

Wrap Web Part Title in SharePoint 2013

Dear reader,

you probably know how it is spend a lot of time on one design issue and then you find solution.

Do not confuse yourself with google with SharePoint 2007/2010 stuff like:

.ms-WPTitle nobr { white-space: normal !important; }
or
.ms-WPHeaderTD nobr { word-wrap: break-word !important; white-space: wrap !important; }

The SharePoint 2013 working version:

.ms-webpart-titleText nobr span {white-space:normal !important;}

I hope it helps!

Having a great patience with SharePoint 2013 :)

KeywordQuery doesn’t work or confusion between search namespaces

Hello all,

Today I have survived the huge confusion, I wanted create a simple server side functionality for search on SharePoint 2013. Please look on following code which was mentioned not working with exception:

Your search cannot be completed because no Search service is available. Contact your administrator for more information.

p33

I thought what is that? What can I do? I have checked central admin, all seem to be right, I have tried google, someone said in case of SharePoint 2010, it’s broken. Ok I have recreated search service application, and it was still there.

In the first time I saw that KeywordQuery is marked as obsolete with nice message “This class is obsolete now. It will be totally removed in O16 codebase and should not be used in new applications.”. I thought fine this is not version O16, they just try to scare us, but no this object doesn’t work at all!

After more digging and searching I found the solution, I have used all time this wrong assembly. The updated class for using search functionality is Microsoft.Office.Search.Query, they removed word Office from product but still is heavily using in API.(as you can see my previous post about client side query there is used KeywordQuery from Microsoft.SharePoint.Client.Search.Query which was even more questionable).

The solution is just replace these assemblies and be careful which assembly you are going to reference to your solution:

using System;
using System.Data;
using System.Linq;
using Microsoft.Office.Server.Search.Query;
using Microsoft.SharePoint;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (SPSite siteCollection = new SPSite("http://siteUrl/"))
            {
                KeywordQuery keywordQuery = new KeywordQuery(siteCollection);
                keywordQuery.QueryText = "PopulateNewFields";
                SearchExecutor searchExecutor = new SearchExecutor();

                ResultTableCollection resultTableCollection = 
                    searchExecutor.ExecuteQuery(keywordQuery);
                var resultTables = resultTableCollection.Filter("TableType", 
                    KnownTableTypes.RelevantResults);
                var resultTable = resultTables.FirstOrDefault();

                DataTable dataTable = resultTable.Table;

                foreach (DataRow resultRow in dataTable.Rows)
                {
                    Console.WriteLine("{0}", resultRow["Title"]);
                }
            }
            Console.ReadLine();
        }
    }
}

I hope it helps, if you have any queries just let me know.

Happy coding!

JavaScript – How magic can keyword ‘this’ be?

The Introduction

This article will hopefully save your day. If you are JavaScript beginner, by having read this article, you might find it enlightening and might help you removing confusion which I was going through when registering events on my HTML elements.

The Problem

One of the most powerful JavaScript keyword is ‘this’. Unfortunately it is hard to use it if you don’t exactly know how it works.

The Solution

Here we will be going via more approaches how to deal with ‘this’ keyword and where all that confusion comes up.

Owner

What does ‘this’ refer to in the function doSomething()?

function doSomething() {
this.style.color = '#cc0000';
}

In JavaScript ‘this’ always refers to the owner of the function we are executing, or rather, to the object that a function is a method of. When we define our faithful function doSomething() in a page, its owner is the page, or rather, the window object(or global object) of JavaScript. An onclick property though, is owned by the HTML element it belongs to.

‘this’ in onclick() function looks at HTML element
‘this’ in unattended function looks at page

Coping

So if we want to use ‘this’ to its full extent we have to take care that the function that uses it is owned by the correct HTML element. In other words, we have to copy the function to our onclick property. For this purpose we are using event registration model.

element.onclick = doSomething;

The function is copied in its entirely to the onclick property which now becomes a method. So if the event handler is executed ‘this’ referes to the HTML element and its colour has changed.

Referring

However, If you use inline event registration

<element onclick="doSomething()">

You do not copy the function! Instead, you refer to it, and the difference is crucial. The onclick property does not contain the actual function, but merely a functional call:

doSomething();

So it says ‘go to doSomething()’ and execute it. When we arrive at doSomething() the ‘this’ keyword once again refers to the global window object and the function returns error messages.

Combination

If you want to use ‘this’ for accessing the HTML element that is handling the event, you must make sure that the ‘this’ keyword is actually written into the onclick property. Only in that case does it refer to the HTML element the event handler is registered to. When you write

element.onclick = doSomething;

you get

function doSomething(){
this.style.colr='#cc0000';
}

and when you write

<element onclick="doSomething()">

you get

function onclick(){
doSomething();
}

When using inline event registration you can also send ‘this’ to the function so that you can still use it:

<element onclick="doSomething(this)">

function doSomething(obj) {
//this is present in the event handler and is sent to the function
//obj now refers to the HTML element, so we can do
obj.style.color='#cc0000';
}

The Conclusion

Finally just keep on your mind two questions:

  • How do I register my function to event property? Event registration model or inline?
  • How do I call my function which working with ‘this’ keyword? Is your function unattended?

I hope this helps you to understand the problem and avoid that with smile:)

When TreeView_SelectNode() doesn’t work

Hello all,

Today I have spent  a large amount of time to solve this issue. Let me describe my solution in points:

  • I have just server code, no aspx control
  • I have created treenodes dynamically
  • I have registered javascript in onPreRender  method
  • I have set ShowCheckBoxes to TreeNodeTypes.Leaf
  • Other settings are default, which mean i don not set populateondemand
  • I have set just SelectionAction on root to Expand

I have tried to apply this approach:

window.onload = function(){
     var treeview = document.getElementById("<%=Tree1.ClientID %>");
      var treeLinks = treeview.getElementsByTagName("a");
      for(i=0;i<treeLinks.length;i++)
      {
           if(treeLinks[i].firstChild.tagName != "IMG")
           {
             treeLinks[i].setAttribute("href","javascript:void(0);");
             treeLinks[i].onclick =function(){
             TreeView_SelectNode(<%=Tree1.ClientID %>_Data,this,this.id.toString());
             }          
          }
       }
}

Gathering information from this forum.

My solution is below:

        protected override void OnPreRender(EventArgs e)
        {
            ClientScriptManager csm = this.Page.ClientScript;

            string clientScript = @"
            window.onload = function(){
              var treeview = document.getElementById('" + treeView.ClientID + @"');
              var treeLinks = treeview.getElementsByTagName('a');
              for(i=0;i<treeLinks.length;i++)
              {
                   if(treeLinks[i].firstChild.tagName != 'IMG')
                   {
                     treeLinks[i].setAttribute('href','javascript:void(0);');
                     treeLinks[i].onclick =function(){
                     var parent = this.parentNode;
                     var input = parent.getElementsByTagName('input')[0];
                     var isChecked = input.getAttribute('checked');
                     if(isChecked == '') {
                        input.setAttribute('checked','checked');
                     }
                     else {
                        input.removeAttribute('checked');
                     }
                     }
                  }
               }
         }
";
            csm.RegisterStartupScript(this.GetType(), this.ID, clientScript, true);
            base.OnPreRender(e);
        }

I hope it helps !

Get dll library into GAC within Visual Studio

Are you using for SharePoint 2010 development CKS:DEV ? With bigger projects when create additional class libraries we must open command line and manually add your assembly to GAC.

We can show up similar way to create simple external command in Visual Studio:

Tools -> External Tools.. -> Click on “Add”.

We set these parameters:

  • Title : “Get to GAC” (It’s up to you)
  • Command: “C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe”
  • Arguments: “-i $(TargetPath) -f”
  • Use Output window : “checked”

According this picture:

Select class library and execute tool Tools-> Get to GAC :

p14

Happy SharePointing :)

Display list on different site collection

Hi Guys,

This topic how is the best way to display some piece of information to another site collection, sometimes to another web application.

As first we start with motivation, why we want such solution, which functionality we expect from solution.

  • Why? Connection data source in SharePoint is supported functionality for collaboration in among teams, it also can create whole image about gathering data (for example, internal home page of company, department, client site)
  • Expected functionality can be various, starting for using the same settings and permission as original source or create custom filtering, trimming and logic for present or display data.

From my point of view,  I choose the simplest custom solution,that’s a creating Web Part.

I won’t describe some random solution for creating custom solution, I’m just show you a really useful control called “ListViewByQuery“.

The based concerns about this control:

  • You must set “List” and “Query” properties
  • You will get a “missing list” exception or something similar like that if you don’t set “View Fields” property for the Query property
  • SPQuery should be instantiated with a View, otherwise you will get a blank page (If you instantiate SPQuery with a view you do not need to specify “ViewFields” property which are in particular view)

Here is my example custom web part, defined according inputs:

  • SiteUrl – If the list is in different site collection, set site collection URL
  • ViewName – List Viewm Name to be used
  • SourceList – Display name of source list to query

I have created blank solution in Visual Studio 2010 and add (no-Visual) Web part. Whole functionality is based on ListViewByQuery control and extended properties on our web part. In overridden  CreateChildControl methods applying conditions. For whole picture I added try-catch clause to avoid mistakes and letting knows user about that. Source code is bellow:

viewByQuery = new ListViewByQuery();
        //checking site url property if it's current web or not
        if (!string.IsNullOrEmpty(this.SiteUrl))
        {
            site = new SPSite(this.SiteUrl);
            web = site.OpenWeb();
            disposeObjects = true;
        }
        else
        {
            site = SPContext.Current.Site;
            web = SPContext.Current.Web;
        }
        //checking existence of source list
        SPList sourceList = web.Lists.TryGetList(this.SourceList);
        if (sourceList == null)
            throw new ApplicationException("List doesn't exist, please check your configuration");
        viewByQuery.List = sourceList;
        
        //setting our properties on view control
        viewByQuery.DisableFilter = this.DisableFilter;
        viewByQuery.DisableSort = this.DisableSort;
        viewByQuery.Query = new SPQuery();

        //we excpected see whole structure of items in source list
        viewByQuery.Query.ViewAttributes = "Scope=\"Recursive\"";
        if (string.IsNullOrEmpty(this.ViewName))
        {
            //use default view if it is not set up
            viewByQuery.Query.ViewXml = sourceList.DefaultView.GetViewXml();
            this.Controls.Add(viewByQuery);
        }
        else if (CheckViewName(sourceList))
        {
            //use the view specified in webpart property
            viewByQuery.Query.ViewXml = sourceList.Views[this.ViewName].GetViewXml();
            this.Controls.Add(viewByQuery);
        }
        else
        {
            //use default view if it is not correct and let users know that
            viewByQuery.Query.ViewXml = sourceList.DefaultView.GetViewXml();
            this.Controls.Add(viewByQuery);
            throw new ApplicationException("The name of view of source list are not configured correctly.");
        }

Whole Visual Studio project is here.

Happy SharePointing! :)

Task locked by Running Workflow and Cannot be Edited

For developer work is this error surely known. So, what is going on here?

Well, the first thing to note is that the error is absolutely correct. The task is locked, but why is it locked, and was it not unlocked appropriately?

How workflow tasks are locked

The first thing to realize is that when SharePoint workflows alter tasks there needs to be some sort of locking behaviour on tasks so that you will not accidentally create race conditions and update a task simultaneously, the one update overwriting the other. Typically database level locks are used but for SharePoint Workflow tasks however a more simple, business-layer type lock suffices. Since SharePoint workflow is about humans and not about maximum near real-time performance the chance of collisions is low enough not to be worried about this. The workflow runtime in SharePoint locks tasks by setting a field and persisting that to the database. It then checks on the field value to determine whether is locked. You can actually see the code that does this. The SPWinOEItemEventReceiver implements the ItemUpdating and ItemUpdated events. In the ItemUpdating you can find code similar to the following pseudo code:

If WorkflowVersion for item not equal to 1

Throw locked error

Else

Place lock (set WorkflowVersion on item to value not equal to 1)

Running into the locking issue

So, the issue is that the lock is still there even though it should have been released in the ItemUpdated event. Clearly, the ItemUpdated event is where the issue lies, and like all bugs in life, you did it, and not the framework! (I hope you are not shocked) There is only one aspect of the locking that you can control, and that is the persistence and hydration of your workflow to and from the database. This is exactly what is causing the bugs. When the ItemUpdated event fires and tries to de-serialize your workflow there might be an exception during the hydration of your workflow object. This error is difficult to see since it is happening in non-user code based on an asynchronous event. When that error occurs, the task unlocking code doesn’t run!

The general flow of events to create this issue goes something like this:

  • Developer designs a workflow which creates a task.
  • Developer tests the workflow, and runs it up to the task change activity, meaning that the workflow is now serialized in the database waiting for a task change to occur.
  • Developer spots a bug, and updates the workflow in such a way that de-serialization breaks.
  • Developer updates the task through the browser to continue the workflow.
  • Runtime bumps into the de-serialization error, and cannot continue, hence the task unlocking code does not run, and the task is locked for all eternity.

Preventing the locking issue

Now that we have a clear understanding of the issue, there are many things you can about it. On development I’d go for re-running the entire workflow.

On Production, it is even easier:

DO NOT UPGRADE UNTIL ALL RUNNING WORKFLOWS ARE COMPLETE

You should quiesce a workflow and when all running workflows have completed. Or, when you need to have the business logic available during the quiescing, you can only create a new workflow.

How to fix affected workflow tasks

As first thought which I have had that return WorkflowVersion to value 1, and it’s right. Example code can look like that:

public void UpdateTaskItem(SPList taskList, int identifier)
    {
        taskItem = taskList.GetItemById(identifier);

        Guid workflowInstanceId = new Guid(taskItem[Microsoft.SharePoint.SPBuiltInFieldId.WorkflowInstanceID].ToString());
        SPWorkflow workflow = taskItem.Workflows[workflowInstanceId];
        if (workflow != null && !workflow.IsLocked)
        {
            taskItem[Microsoft.SharePoint.SPBuiltInFieldId.WorkflowVersion] = 1;
        }
        taskItem.Update();
    }

Here we can see how to fix this situation. I have created one feature for finding this secret issues. It was really handy for our team.

The application has these parts:

  • Found the corrupt task items
  • Fix them

The first thought to find all these corrupt task items based on CAML query, but field “WorkflowVersion”  is hidden what means it’s not reachable for search. My peace of code:

string siteUrl = SPContext.Current.Site.Url;
        List<LockedTask> lockedTasks = new List<LockedTask>();
        SPSecurity.RunWithElevatedPrivileges(() =>
        {
            using (SPSite site = new SPSite(siteUrl))
            {
                foreach (SPWeb web in site.AllWebs)
                {
                    using (web)
                    {
                        foreach (SPList list in web.Lists)
                        {
                            //we're looking for task list with workflow features
                            if (list.BaseTemplate == SPListTemplateType.Tasks && list.Fields.Contains(Microsoft.SharePoint.SPBuiltInFieldId.WorkflowVersion))
                            {
                                //we do not expect any subfolders or another type of items
                                SPQuery spQry = new SPQuery();
                                spQry.RowLimit = 300;
                                do
                                {
                                    SPListItemCollection items = list.GetItems(spQry);
                                    foreach (SPListItem item in items)
                                    {
                                        int version = (int)item[Microsoft.SharePoint.SPBuiltInFieldId.WorkflowVersion];
                                        // tick item which has not WorkflowVersion value 1
                                        if (version == 1) continue;
                                        XDocument xDoc = XDocument.Parse(item.Xml);
                                        lockedTasks.Add(new LockedTask
                                        {
                                            LinkToDocument = xDoc.Root.Attribute("ows_WorkflowLink").Value.ToString(),
                                            WorkflowName = xDoc.Root.Attribute("ows_WorkflowName").Value.ToString(),
                                            AssignedTo = xDoc.Root.Attribute("ows_AssignedTo").Value.ToString(),
                                            Name = item.Title,
                                            TaskID = item.UniqueId,
                                            ListID = list.ID,
                                            WebID = web.ID,
                                            WorkflowVersion = (int)item[Microsoft.SharePoint.SPBuiltInFieldId.WorkflowVersion]
                                        });
                                    }
                                    spQry.ListItemCollectionPosition = items.ListItemCollectionPosition;
                                } while (spQry.ListItemCollectionPosition != null);
                            }
                        }
                        site.RootWeb.AllowUnsafeUpdates = true;
                        site.RootWeb.Properties.AddProperty(this.rootSitePropertyBag, lockedTasks);
                    }
                }
            }
        });

        pnTasks.Controls.Clear();
        lockedTasks.ForEach(a =>
        {
            CheckBox ch = new CheckBox();
            ch.EnableViewState = true;
            ch.Text = a.ToString();
            pnTasks.Controls.Add(ch);
            pnTasks.Controls.Add(new LiteralControl("<br />"));
        });

I display all corrupt task item in list with checkbox where you can pick up them and execute fixing function looks as below:

string siteUrl = SPContext.Current.Site.Url;
        SPSecurity.RunWithElevatedPrivileges(() =>
        {
            using (SPSite site = new SPSite(siteUrl))
            {
                site.AllowUnsafeUpdates = true;
                List<LockedTask> list = site.RootWeb.Properties.ReadProperty<List<LockedTask>>(this.rootSitePropertyBag);
                // seek all check boxes
                foreach (Control cc in pnTasks.Controls)
                    if (cc is CheckBox && (cc as CheckBox).Checked)
                    {
                        LockedTask task = LockedTask.GetTask((cc as CheckBox).Text, list);
                        using (SPWeb web = site.OpenWeb(task.WebID))
                        {
                            web.AllowUnsafeUpdates = true;
                            SPList taskList = web.Lists[task.ListID];
                            SPListItem taskItem = taskList.GetItemByUniqueId(task.TaskID);
                            //unlocking task by setting 1 on Workflow version
                            taskItem[Microsoft.SharePoint.SPBuiltInFieldId.WorkflowVersion] = 1;
                            taskItem.Update();
                        }
                    }
            }
        });

I hope that helps to understand why SharePoint is locking your workflow tasks. Here is attached source code of my solution.

Happy SharePointing!

Such a great idea “All-In-One Code Framework”

Hi guys!

Maybe I’m totally delayed, but I never see this solution for search MSDN sample codes.


I recommend having a look at http://1code.codeplex.com/.

Happy searching!

Run the SPDisposeCheck in the PowerShell

Hi All,

I have made these days some deployments and I wanted test all my source code in one way.  Making script in PowerShell is my outcome.  Script contains recursive getting files with “.dll” extension, yes I can do the same with extension “.wsp” and unzip package and I decided it might be as simple as possible. Later on, it creates folder in your current location and all output are written there.

Have a look :)

function global:Get-SPDisposeCheck

 {

Write-Host “Recursive check current location …”

$path = $PWD.Path 

#checking actual location recursively 

$Dir = get-childitem $path -recurse 

#all files with dll extension 

$List = $Dir | where {$_.extension -eq“.dll”

#made new folder for results 

$export = $path+ “\” “SPCheck_$((get-date).toString(‘yyyyMMdd-hhmmss’))”

$dir = md $export 

#on every file execute SPDisposeCheck 

$List | ForEach-Object

Write-Host$_.Name “is beeing checked…” 

$report = $export + “\” + $_.Name + “.spdisposecheck.txt” 

#in some point, you can use the same dll files, it will be overridden 

& “C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe”$_.fullname | Out-File $report -Force }

#open result folder to review 

explorer $export 

}

Execute in PowerShell and see output:

Happy SharePointing guys :)

SharePoint Document Set with Custom View inside

Hi All,

Today I have been solving one task, starting with question “Martin, How can we apply different view inside our document set?”. In first place I was surprised because if you edit document set page, its doesn’t content classical list view web part, but “Document Set Contents”. It was really odd, but afterwards all gave me more sense, if I looked at document set’s settings on the bottom.

Warning - doesn’t exist in Document Set Settings via Site Content Type menu!

You must go through associated document library settings like that:

Through Document Set Settings:

Scroll at the bottom of that page:

All are solved nicely:)

Happy SharePointing guys!

Follow

Get every new post delivered to your Inbox.