SharePoint Comments
Wednesday, April 16, 2014
SharePoint Site Explorer (SPSE)
Sunday, May 3, 2009
Wrong Content Type value displayed for a new document
I troubleshot a problem when a wrong content type value was displayed for a new document in document library with multiple content types. Content type “Electronic Letter” was created a while after content type “Letter” and used the same template MS Word 2007 document. The root of the problem was in the document template itself. It was taken from content type “Letter” and contained this content type metadata and when I tried to use it in other content types it still had the original binding to “Letter”. Microsoft says that this problem happens with Office 2007 document only and recommendation is to keep the master copy of the document template on disk and never take it from SharePoint. In my case the problem was that I did not have the master copy on my disk and could only use the document already loaded to SharePoint and bound to the other content type. And finally I found the way how to detach the document.
Open the document from disk and go to Prepare->Inspect Document menu item.
Check “Document Properties and Personal Information” item and press “Inspect” button.
Press “Remove All” button against “Document Properties and Personal Information” item. This will remove all the content type binding of this document.
Press “Close” button and save the document.
After that you can use this document as a master copy for all the other content types where it is used as a template.
Monday, June 9, 2008
Be careful using non-alphanumeric field names in SharePoint
I found that there are some inconsistency in internal name generating in WSS 3.0. I encountered with it when receiving en error on checking in a file. SharePoint log file did not reveal the problem as usual :) and I used my custom code to troubleshoot. This is the exception description and a stack trace I received:
at Microsoft.SharePoint.SPFieldCollection.GetFieldByInternalName(String strName, Boolean bThrowException) at Microsoft.SharePoint.SPFieldCollection.GetFieldByInternalName(String strName) at Microsoft.SharePoint.SPListItem.get_MissingRequiredFields() at Microsoft.SharePoint.ApplicationPages.Checkin.OnLoad(EventArgs e)
I
started to review code in Reflector and discovered that
SPListItem.MissingRequiredFields
property is checked on page check in. For this
purpose it uses SPFieldLink.Name
from SPListItem.ContentType.FieldLinks
collection to retrieve SPField
object from SPListItem.ParentList.Fields
collection for every field which is SPFieldLink.Required=true
. In order to get
SPField
object SPFieldCollection.GetFieldByInternalName()
method is used and if
SPFieldLink.Name
field value is not found as internal name of any SPField
then
we receive "Value does not fall within the expected range" exception.
In my
case I have a field named "Description of Change/New document" which is
translated to internal name as
"Description_x0020_of_x0020_Change_x002F_New_x0020_Document
" but for some reason
SPFieldLink.Name
field value for this field is
"Description_x0020_of_x0020_Change_x002f_New_x0020_Document
". Feel the
difference in unicode of symbol "/": x002f
(small 'f') and x002F
(capital 'F').
That gives me two different internal names and I have these troubles. I guess
there is inconsistency and there are several functions which generate internal
name and these functions produce different result in some cases.
When I recreated my field the problem was fixed for which I do not have any explanation.
Sunday, July 22, 2007
Convert Java to .NET
Some project required me to port Java source code into .NET environment. I had to import this code into J# project and then compile it. It worked ok if you had entire source code but usually I did not have it or Java project used some third party JARs. Searching for some solution I found IKVM.NET This is a striking solution and it solves 99% of problems of usage Java in .NET. It converts Java byte code into .NET CLR and you do not need to any source code any more. It is amazing and many thanks to its author Jeroen Frijters.
Friday, May 11, 2007
Yet another scripting host - MyScriptHost
Developing for SharePoint I found myself in situation when I had an access the the server (direct or remote desktop) and need to run some ad-hoc code on it but the server did not have Visual Studio or any other development environment installed. I think this is familiar to some of us. These are some possible options:
- install Visual Studio or any other development environment (very unlikely that administrator will allow you to do it for test or production environment)
- develop the code on the other machine and run on the server (good approach but you loose code flexibility especially if you want to write and test your code interactively)
- use SnippetCompiler. This is a very good tool and I would choose it if it supported command line execution of C# files.
- use Windows Scripting Host (WSH) to create and run scripts (good approach but you need to use JScript of VBScript)
- use Dot Net Script (good tool, but it uses its own file format and does not have IDE)
I wanted to have some kind of a combination of SnippetCompiler and Dot Net Script where I could create some scripts and maybe execute them automatically in future.
So meet MyScriptHost.
This is a console application with a windowed code editor. It works with one file at a time which can be executed with or without code editor. It can associate .mysh files to itself (I have taken this idea from Dot Net Script project).
Command line usage:
MyScriptHost.exe <filename> <command>
where <filename> is a name of a file and <command> is one of the following:
/open |
open the file for editing. This is a default behavior if no other command is specified. |
/compile |
compile the file without execution |
/run |
compile and execute the file |
/runandwait |
compile and execute the file and keep the console window open after execution |
Code file should be a C# class containing public static void Main()
as entry point.
The only addition to pure C# code is a metatag <@ Reference Name="assembly name
or path" %>
in order to define external references. Code file can
have any number of these tags at the beginning of the file.
MyScriptHost contains internal static class MyshDebug which has some methods useful for debugging:
static void Watch(params object[] values) |
Opens a watch window for specified values |
static void Print(object obj)
|
Prints object properties to console. It also allows to specify a number of levels to print out. |
Watch window is a modal window and allows you to see and change properties in PropertyGrid. Invoke tab allows you to print property value with a specified level of details.
This is an example of a script I used with MOSS to import news items from xml file to SharePoint document library.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.IO;
using System.Xml;
public class Class1
{
private const string m_destNewsItemsFolder = @"C:\My Projects\Sharepoint Scripts\ImportNews\Items\";
private const string m_destNewsAttachmentsFolder = @"C:\My Projects\Sharepoint Scripts\ImportNews\Attachments\";
private const string m_siteUrl = @"http://localhost:1003/";
private const string m_prefix = "newPage_";
private const string m_pageTemplateName = "page1.aspx";
public static void Main()
{
SPSite site = new SPSite(m_siteUrl);
SPWeb web = site.OpenWeb("News");
//MyshDebug.Watch(web);
SPFolder pages = web.Folders["Pages"];
//MyshDebug.Watch(pages);
SPFile pageTemplate = pages.Files[m_pageTemplateName];
//MyshDebug.Watch(pageTemplate);
// delete old files
Console.WriteLine("Deleting previous files...");
List<SPFile> filesToDelete = new List<SPFile>();
foreach(SPFile file in pages.Files)
{
Console.WriteLine(String.Format("{0}", file.Name));
if(file.Name.StartsWith(m_prefix))
{
filesToDelete.Add(file);
}
}
foreach(SPFile file in filesToDelete)
{
Console.WriteLine("Deleting " + file.Name);
file.Delete();
}
string[] fileNames = Directory.GetFiles(m_destNewsItemsFolder);
// Create new files first
for (int i = 0; i < fileNames.Length; i++)
{
string fileName = Path.GetFileNameWithoutExtension(fileNames[i]);
fileName = m_prefix + fileName;
//MyshDebug.Watch(fileName);
Console.WriteLine("Creating " + fileName);
pageTemplate.CopyTo(pages.Url + "/" + fileName + ".aspx", true);
}
// This is to refresh file list
pages = web.Folders["Pages"];
// Upload news content to already created files
for (int i = 0; i < fileNames.Length; i++)
{
string fileName = Path.GetFileNameWithoutExtension(fileNames[i]);
fileName = m_prefix + fileName;
//MyshDebug.Watch(fileName);
Console.WriteLine("Uploading " + fileName);
XmlDocument doc = new XmlDocument();
doc.Load(fileNames[i]);
string body = GetNodeText(doc, "//body");
string date = GetNodeText(doc, "//date");
string sourceName = GetNodeText(doc, "//sourceName");
string newsType = GetNodeText(doc, "//newsType");
string title = GetNodeText(doc, "//title");
string[] attachments = GetNodeTextArray(doc, "//attachment");
string creator = GetNodeText(doc, "//creator");
string creatorName = GetNodeText(doc, "//creatorName");
string author = GetNodeText(doc, "//author");
string entity = GetNodeText(doc, "//Entity"); //????
SPFile newPage = pages.Files[fileName + ".aspx"];
// adjust body
body = "<p>" + body.Replace("\r\n", "</p><p>") + "</p>";
//MyshDebug.Watch(body);
//break;
newPage.CheckOut();
SPListItem item = newPage.Item;
item["Page Content"] = body;
item["Article Date"] = date;
//item["NewsType"] = newsType;
item["Title"] = title;
item["Contact Name"] = author;
item.Update();
newPage.CheckIn("");
newPage.Publish("");
//newPage.Versions.DeleteAllMinorVersions();
//break;
}
}
private static string GetNodeText(XmlNode root, string xpath)
{
XmlNode node = root.SelectSingleNode(xpath);
if (node == null)
{
return "";
}
return node.InnerText;
}
private static string[] GetNodeTextArray(XmlNode root, string xpath)
{
XmlNodeList nodes = root.SelectNodes(xpath);
List<string> values = new List<string>();
foreach (XmlNode node in nodes)
{
values.Add(node.InnerText);
}
return values.ToArray();
}
}