Site column messing up Document Information Panel (DIP)

by Martin 4. januar 2011 12:54

I've been doing a project which requires custom site columns (who hasn't!?). These site columns where then added to document libraries. But the site columns didn't show in the Document Information Panel in Word 2010... Frown And it messed up all subsequent columns added after my custom columns (the columns added afterwards wasn't displayed either) They did show in the document properties in the SharePoint UI though...
The trouble seemed to be in the CAML for my site columns: I've forgotten that the StaticName-property doesn't allow spacings... Embarassed Correcting the spacings by either removing them (making the staticname-prop camel-cased) or replacing with _x0020_ did the trick! Now my custom columns show in the DIP! Laughing

Strange that the column works except for in the DIP... If somebody has an explanation, please comment on this post

Tags: ,

.NET

Custom site provisioning and navigation

by Martin 25. november 2010 15:13

I've been doing a project for a client requiring a custom site definition template.

This template included various custom lists to be instantiated along with the site definition. This worked like a charm. The lists had <data> elements inside the <list>-elements (in short: had folders created when provisioned, great article here: http://geekswithblogs.net/kit/archive/2008/08/25/124679.aspx ). This also worked fine until I found out that is was also a requirement to have links in the navigation on the left-hans side to the lists.

This is NOT easily accomplished!

Because if you set the OnQuickLaunch-property of a ListTemplate-element at best it adds it under a "Libraries"-heading in the navigation. I wanted it to be a link in the "root" of the navigation. A had to do this with a featurereceiver. Easily accomplished in it self but not in practice.

I added a feature-element to my CAML in onet.xml activating my feature when the site was provisioned. Problem was just that the lists wasn't created at this point, so I couldn't get a reference to them (I didn't want to hard code the URL's). In short: feature leveraging featurereceiver was activated before lists were instantiated. OK I thought: instead I'll just move the list instatiation to a separate feature, activate the feature instanting the lists in the CAML of my onet.xml. This led to a plethora of exceptions in my ULS and no site(s) being provisioned (something like "Column 'LinkTitle' does not exist" and various others...).

There was another alternative to accomplish my goal: Create an ExecuteUrl-element and call an applicationpage which activated the feature (and hence the featurereceiver). This didn't seem to work either.. I had the below code

 

protected void Page_Load(object sender, EventArgs e)
		{
			try
			{
				Guid featGuid = new Guid("70dc1ed8-5664-46cc-8068-310c033879b8");
				if (SPContext.Current.Web.Webs.Count > 0)
				{
					//Activate feature
					for (int i = 0; i < SPContext.Current.Web.Webs.Count; ++i )
					{
						using (SPWeb web = SPContext.Current.Web.Webs[i])
						{
							if (web.Features[featGuid] != null)
							{
								//Feature already activated, continue
								continue;
							}
							//Add feature to trigger feature receiver
							web.Features.Add(featGuid);
						}
					}
				}

				SPUtility.Redirect(SPContext.Current.Web.Url, SPRedirectFlags.Default, System.Web.HttpContext.Current);
			}
			catch { }
		}

This didn't work either: It threw an exception: Updates not allowed on GET requests. D'oh, Remember to set the AllowUnsafeUpdates-property to true AND revert it after you're done:

protected void Page_Load(object sender, EventArgs e)
		{
			try
			{
				Guid featGuid = new Guid("70dc1ed8-5664-46cc-8068-310c033879b8");
				if (SPContext.Current.Web.Webs.Count > 0)
				{
					//Activate feature
					for (int i = 0; i < SPContext.Current.Web.Webs.Count; ++i )
					{
						using (SPWeb web = SPContext.Current.Web.Webs[i])
						{
							if (web.Features[featGuid] != null)
							{
								//Feature already activated, continue
								continue;
							}
							bool allowUnsafeUpdates = web.AllowUnsafeUpdates;
							//Allow unsafe updates
							web.AllowUnsafeUpdates = true;
							//Add feature to trigger feature receiver
							web.Features.Add(featGuid);
							//Update
							web.Update();
							//Reverse setting
							web.AllowUnsafeUpdates = allowUnsafeUpdates;
							//Updaet again to reflect changes
							web.Update();
						}
					}
				}

				SPUtility.Redirect(SPContext.Current.Web.Url, SPRedirectFlags.Default, System.Web.HttpContext.Current);
			}
			catch { }
		}

Mission accomplished!

Tags: , , , ,

.NET

Exporting existing wsp packages from SharePoint

by Martin 5. juli 2010 13:01

I'm currently working on a project with migrating from one SharePoint installation to another newer installation. For this project, the client has a couple of installed wsp's in the farm. But they do not have the wsp's to reinstall them... So I somehow had to write up some code that could export a given wsp from the farm. I ended up writing an extension for STSADM (yeah, I know, I should use PowerShell, but I'm an oldie for a little longer :-)). I thought, I'd share the end result with those who wanted to give it a go. (Use the supplied wsp at your own risk)

The source code goes here:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.StsAdmin;
using System.Collections.Specialized;
using Microsoft.SharePoint.Administration;

namespace ExportWSP
{
	public class ExportWSP : ISPStsadmCommand
	{
		public string GetHelpMessage(string command)
		{
			return "-wsp ";
		}

		public int Run(string command, StringDictionary keyValues, out string output)
		{
			if (!keyValues.ContainsKey("wsp") && !keyValues.ContainsKey("all"))
			{
				throw new InvalidOperationException(string.Format("USAGE: -eit-exportwsp -wsp  [-all]. You supplied wsp: {0}, all: {1}", keyValues["wsp"], keyValues["all"]));
			}

			try
			{
				this.ExportWSPPackage(keyValues);
			}
			catch (Exception ex)
			{
				output = ex.Message;
				return 1;
			}

			output = "Success";
			return 0;
		}

		private void ExportWSPPackage(StringDictionary keys)
		{
			if (keys.ContainsKey("all"))
			{
				foreach (SPSolution sol in SPFarm.Local.Solutions)
				{
					this.ExportWSPPackage(sol.Name);
				}
			}
			else
			{
				this.ExportWSPPackage(keys["wsp"]);
			}
		}

		private void ExportWSPPackage(string wspName)
		{
			//Get reference to solution
			SPSolution sol = SPFarm.Local.Solutions[wspName];

			if (sol != null)
			{
				//Save file (assuming it does so to the execution path
				sol.SolutionFile.SaveAs(wspName);
			}
			else
			{
				throw new InvalidOperationException("Solution does not seem to exist");
			}
		}
	}
}

Below is a link to the wsp-file. The project has been built with STSDev a tool I absolutely love when developing SharePoint solutions!

To use the extension, simply use one of the following commands:

stsadm -o eit-exportwsp -all , or
stsadm -o eit-exportwsp -wsp <NAME OF WSP TO EXPORT>

The first line exports all the wsp's in the farm to the folder the command is executed from. The second export the given wsp to the folder the command is executed from.

Parameters explained:
-all: Exports ALL WSP's in the farm
-wsp <NAME OF WSP TO EXPORT>: exports a single wsp from the farm.

To install the solution, simply use:

stsadm -o addsolution -f exportwsp.wsp
stsadm -o deploysolution -n ExportWSP.wsp -imm -allowgac
stsadm -o execadmsvcjobs

 

ExportWSP.wsp (8,21 kb)

Tags: , , , ,

.NET | MOSS

SharePoint SearchBoxEx and OSSSearchResults.aspx

by Martin 12. marts 2010 14:09

I've been working on a solution for a client, where I where to add a searchbox to the masterpage. This wasn't hard: just add a SearchBoxEx web control to the page, give it the runat="server", add the ScopeDisplayGroupName="[Name-of-scope-goes-here]" and go! This seemed somehow to do the job. Search results seem to be presented... But even though I had set the Search Center setting in the Site Settings to /Search/Pages, the results where always displayed on the /_layouts/OSSSearchResults.aspx page. Some of the scopes had a cusotm results page, but SharePoint didn't seem to honor this setting.
Enter the UseSiteDefaults-property of the SearchBoxEx control: this is per default set to false :( This has to be set to true, if you want to use the custom settings in the site and scopes! Resulting markup for SearchBoxEx:

<SPSWC:SearchBoxEx runat="server" TextBeforeDropDown="" ScopeDisplayGroupName="DisplayGroupName" UseSiteDefaults="true" />

This caused the searchbox to use the correct search settings (e.g.: peopleresults.aspx and results.aspx in the search center)

Easy as pie in the end, but hard to find out Yell

Tags: , ,

.NET | MOSS

Sharepoint: This page has been modified

by Martin 18. august 2009 12:40

I've implemented a solution for a customer, where we created a site definition template. In the onet.xml-file we defined some modules for default pages. Fairly easy. We created an aspx-page that resembled the layout page in the feature for the web-project. This means: we actually cerated the same markup twice, we even inherited from the same class! This seemed to work fine. It's noteworthy that the installation is running SP2. The problems started to occur a little later up the development cyclus, when our tester would perform normal content editing tests. When he edited a default page (only the one created by the module in the site def, not if you changed the default page to another) it would say that the page has been modified since it had been checked out. Weird was, that it didn't seem to be consistent when it did it or not. Sometimes editing and saving/publishing the page worked like a charm Yell I didn't take the time to look into the problem, so I just said it was a setup issue, and it would be a problem in the production environment later on. But it became a big problem!!

I read a lot of places, the your pages had to inherit from the TemplateRedirectionPage-class. Our class inherited from the PublishingPage-class so I tried to change the inheritance to the TemplateRedirectionPage. This did NOT do the trick! It blew up the page with more strange ASP.NET errors. Eventually I found out, it was only the aspx in the site def template dir (placed in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\SiteTemplates) had to inherit from this class. but it didn't seem to help either; it still gave strange errors. At last I figured out, I had to remove ALL the markup from the aspx in the site def template dir! Then it would use my page layout in the web-feature instead! Just as defined in the onet.xml-module!

Example from onet.xml:

		<Module Name="DefaultCustomerPage" Url="$Resources:cmscore,List_Pages_UrlName;" Path="">
			<File Url="Default.aspx" Type="GhostableInLibrary" Path="CustomerSectionPage.aspx">
				<Property Name="Title" Value="$Resources:cmscore,IPPT_HomeWelcomePage_Title;" />
				<Property Name="MasterPageUrl" Value="~SiteCollection/_catalogs/masterpage/Customer.master" />
				<Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/CustomerSectionPage.aspx, Customer section page" />
				<Property Name="ContentType" Value="Customer section page" />
				<Property Name="PublishingAssociatedContentType"
Value=";#Customer section page;#0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390095C37FB9ADBD44F59D2F0889858A3913;#" />
			</File>
		</Module>

Example from aspx:

<%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage,Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %>

The example of the aspx has to be in ONE single line, two lines didn't work for me!

Tags: ,

.NET | MOSS

Long time no writing - new project coming up

by Martin 6. maj 2009 16:05

It's been a while since the last time I wrote a blog-post. I've been hung up on work, and I've been to United Bluff :)

I'm now done with the publishing site I've referred to earlier and I'm now going to undertake a smaller project (still as technical project manager) on a collaboration portal. Of course still MOSS :)
In my toolbox for this project, I'll definitely be using these tools:

I HIGHLY recommend having these in your toolbox!

UPDATE 090709:

I've run into other tools which speeded up the development process, and learned me even more about MOSS:

 

Tags: , ,

.NET | MOSS

C# imageresizing in application running Medium Trust

by Martin 6. januar 2009 20:03

I've for some time had a homemade gallery online (which works pretty ok for me). It leverages some code which resizes a Bitmap-object. After moving to a new hosting provider some of my code threw "Out of memory"-exceptions when resizing. I found out this is because the new hosting provider is running their Windows servers set up to Medium Trust. Following is the way I solved the problem. Old code (faulty if running in medium trust, but I don't think it's faulty in high trust):


public static Bitmap ResizeImage(Image b, int nWidth, int nHeight)
{
 Bitmap result = new Bitmap(nWidth, nHeight);
 using (Graphics g = Graphics.FromImage(result))
 {
  g.DrawImage(b, 0, 0, nWidth, nHeight);
  g.Save();
 }
 return result;
}

New working code, now with added imagequalitysettings:


public static Bitmap ResizeImage(Image b, int nWidth, int nHeight)
{
 Bitmap result = new Bitmap(nWidth, nHeight);
 using (Graphics g = Graphics.FromImage(result))
 {
  g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
  g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
  g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
  g.DrawImage(b, 0, 0, nWidth, nHeight);
  g.Save();
 }
 return result;
}

Might work for you too :)

Tags: , , , ,

.NET

Online codeformatter

by Martin 19. december 2008 13:00

I've run into this codeformatter online (an online utility to format code to look nice for e.g. blogposts):

http://www.manoli.net/csharpformat/

Seems to do an ok job. If any1 knows of others/better, please let me know :)

Tags:

.NET

Faster way to manipulate SPListItems

by Martin 19. december 2008 12:20

Sometimes in a Sharepoint installation, it's required to manipulate a lot of ListItems based on some specific criterias. This is normally done by iteraterating the whole site and subsites (and the subsites' subsites, etc). Doing this trough the object model and API is pretty straight forward to most developers, but very tedious to do when considering the time it takes to iterate a large site. There is a way to do it faster, which i'm going to demonstrate below. The basic idea is to "plug directly in" to the Content Database of the site in question, and get the needed ID's to make up a SPListItem-object.

The following example shows how to get all ListItems (which has an .aspx-extension) based on a certain contenttype (you just insert the name of the content type). After getting the data from the database, it's pretty straight forward to make a SPListItem-object from the ID's as shown. Basically we just READ from the database and make changes through the API. I'm not quite sure, if this is legal in terms of support from MS. But I don't think you break the warranty, because you only READ from the Content Database. Remember: NEVER manipulate the Content Database directly, this will leave your installation in an unsupported state. Shouts go out to my co-worker and colleague Ulrich who gave me the bits, I just changed them to fit my needs!

I haven't done the math on this one, but it's certainly way faster than iterating through the whole site. A query like this takes at the most (for the large installation I'm working with (around 300+ sites in a site colleciton)) 5 seconds.

And remember kids: always dispose your webs and sites either by using .Dispose() or by using... using() Smile (If i've forgot to do it in the code below, please slap me silly)

using (SPSite site = new SPSite("http://test/"))
   {
    SPContentDatabase db = site.ContentDatabase;

    SqlCommand c = new SqlCommand();
    string strConn = "Integrated Security=SSPI;Server=" + db.Server + ";database=" + db.Name;

    using (SqlConnection conn = new SqlConnection(strConn))
    {
     c.Connection = conn;
     try
     {
      conn.Open();

      string commandText = "select distinct(A.Id), A.leafname, A.listid, A.WebId as WebId from  alldocs A, alluserdata B where A.extension='aspx' and A.leafname = B.tp_leafname and A.listid = B.tp_listid and B.tp_Contenttype = '" + ContentTypeNameGoesHereAsString + "' order by A.webid";

      SqlDataAdapter adt = new SqlDataAdapter(commandText, conn);

      DataSet ds = new DataSet();

      adt.Fill(ds);

      if (ds.Tables.Count != 0)
      {
       ds.Tables[0].DefaultView.Sort = "WebId asc";
       SPWeb web = null;

       #region Iterate data
       foreach (DataRow dr in ds.Tables[0].Rows)
       {
        Guid id = (Guid)(dr[0]);
        string leafName = dr[1] as string;
        Guid listId = (Guid)(dr[2]);
        Guid webId = (Guid)(dr[3]);

        if (web == null)
        {
         web = site.OpenWeb(webId);
         Console.WriteLine("Now processing: " + web.Url);
        }
        else if (webId != web.ID)
        {
         //Clean up nice
         web.Dispose();
         //Create new web-instance
         web = site.OpenWeb(webId);
         Console.WriteLine("Now processing: " + web.Url);
        }
        SPListItem itm = web.Lists[listId].Items[id];

       [THIS IS WHERE YOUR CODE MANUPULATING THE LISTITEM GOES!]
       }
       #endregion

       if (web != null)
       {
        web.Dispose();
       }
      }
     }
     catch (Exception Ex)
     {
     }
    }
   

DISCLAIMER: Use the above at own risk! The author can not be held responsible for any damage to your Sharepoint installation you may encounter using the above example!

Tags: ,

.NET

Default web parts in sharepoint page layouts

by Martin 19. december 2008 11:40
I've been meaning to write a little about SharePoint and MOSS in particular. Now, I've finally come around to it. I will be starting a series of MOSS-related posts! Smile
First off will be about adding default (custom) web parts to a SharePoint PageLayout in the CAML.
If you are implementing default webparts in a MOSS WCM solution, you are probably using the AllUsersWebParts-tag in your pagelayout and adding a CDATA-tag containing the XML for the web part, you want default on your pagelayout. Three things to remember when doing this:
  1. The AllUsersWebPart-element has a property called WebpartOrder; this property is 1-based!
  2. Using this approach, remeber to comment the AllUserWebPart-element out for subsequent deployments. The feature activation of a feature containing pagelayouts adds the web parts over and over again. This means that you'll have the web part default on the page times [no-of-times-feature-is-deployed]. Not good. But just commenting the AllUserWebPart-element after the first deployment does the trick. This is a flaw/bug in the feature-framework, don't know if MS is coming around to fix it. (You could add the web part to the pagelayout programmatically with a feature receiver, but this will cause your pagelayout to become unghosted (customized), and this is a pretty bad idea if you plan to update the pagelayout (hence the .aspx-file) in the future).
    1. In theory it's possible to circumvent this "flaw" by just upgrading the solution instead of retracting and redeploying, but sometimes this just isn't an option...
  3. If you get an error when creating a new page with the default custom web part with an error like "No parameterless constructor defined for this object"

    , you probably haven't added [Description("Propertyname"), XmlElement(ElementName = "Propertyname")] to the properties you are trying to access in the AllUsersWebPart-xml. Also remember [SupportsAttributeMarkup(true), XmlRoot(Namespace = "NameSpace"), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)] for the class. This did the trick for me.

Hope this could be of help to somebody, I couldn't find info about this problem anywhere on the WWW. It is possible to get results for the "No parameterless constructor defined for this object"-error, but they all related to something else and not custom web parts.

EDIT: Andrew Connell advised me to include an example:


namespace Customer.SharePoint.WebParts
{
 [SupportsAttributeMarkup(true), XmlRoot(Namespace = "CustomContentEditor"), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
    public class CustomWebPart : Telerik.SharePoint.RadEditorWebPart
     {
           //a lot of code and properties go here

  [WebBrowsable(false), // Wether or not the property is to be visible in the property pane
  Personalizable(PersonalizationScope.Shared)] // Determines the scope to which changes will apply
  [Description("Content"), XmlElement(ElementName = "Content")]
  public string Content
  {
   get { return base.Text; }
   set { base.Text = value; }
  }
          //a lot of code and props go here
}

<AllUsersWebPart WebPartOrder="2" WebPartZoneID="uiRightWebPartZoneTop">
    <![CDATA[
<webParts>
  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
    <metaData>
      <type name="Customer.SharePoint.WebParts.CustomWebPart, Customer.SharePoint.WebParts.CustomContentEditor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4339bcf962296421" />
      <importErrorMessage>Cannot import this Web Part.</importErrorMessage>
    </metaData>
    <data>
      <properties>
        <property name="HelpUrl" type="string" />
        <property name="AllowClose" type="bool">False</property>
        <property name="ExportMode" type="exportmode">All</property>
        <property name="Hidden" type="bool">False</property>
        <!-- .. other props -->
        <!-- .. this is the interesting prop -->
        <property name="Content" type="string">You could write something here</property>
        <!-- .. other props -->
      </properties>
    </data>
  </webPart>
</webParts>      ]]>
</AllUsersWebPart>

Tags: , , , ,

.NET

Page List

About

Take a look at my LinkedIn-profile.

DISCALIMER: The content on this blog is in NO way affiliated with my employer. The opinions expressed on this blog are solely my own and in NO way endorsed by my employer.

Recent comments

Comment RSS

Month List