Thursday, December 17, 2009

Microsoft Virtualilzation Headaches

As a SharePoint consultant, I am constantly moving from client to client and the best way to develop and test the code, designs and configurations for each client while maintaining complete separation is to virtualize. Since I work for a Microsoft partner, we try to use Microsoft tools and technologies as much as possible, which can be quite frustrating, as you will find out below.

I recently started working for a large client with a global presence whose IT policies are well-established, difficult to change and not always up-to-date. In that vein, enter the corporate VPN: it's a web-based signin with a host checker that doesn't support any x64 OS.

This prompted me, running Win 7 x64, to try to get a co-worker's Hyper-V Win2k3 x86 MOSS VM and run it in Windows Virtual PC. Seems like a logical thing to do, right? I mean, a Microsoft VHD should work, and be able to be imported by other Microsoft tools, right? Wrong. After spending quite a bit of time trying to attach the VHD in Windows Virtual PC and boot directly into it, I concluded that this was not possible.

Apparently, you can only run VMs using the same architecture as the host in Windows Virtual PC. And you can only boot into a VM that was created on your machine using that method.

To solve my problem, I wiped my machine and installed Windows Server 2008 R2 to take advantage of Hyper-V. While I was at it, I grabbed an image of Windows Server 2003 x86 and built a nice development machine to use for this client.

My problem was solved, but I think in the future, I'll use the open-source VirtualBox by Sun if I'm not able to use Hyper-V. A colleague grabbed one of my Hyper-V VMs the other day and was signed into it from his Windows 7 host using VirtualBox within minutes.

Another annoyance is the resizing of VHD files. My client VM mentioned above was created as a dynamic 30GB disk. The space was quickly filled and my performance was soon shot. Compounding the issue was the fact that I had half a dozen snapshots. While Hyper-V does let you merge snapshots, the process is painful, to say the least.

Resizing the .vhd file can be done using some third-party tools (beware if you have snapshots or a dynamic disk) like VHD Resizer, but that doesn't address the problem of resizing the system partition within the VM itself. Resizing the boot partition isn't supported in Windows Server 2003, so I ended up using another open-source tool, Gparted. Boot into the VM using this tool and it's a breeze to resize the system partition.

I really wish Microsoft would make their virtualization technologies a little more robust in the future.

Thursday, October 15, 2009

Examination of CSS Differences in IE 6, 7 & 8

Anyone who has delved into the hairy world of SharePoint CSS knows that it can be difficult to effectively create a cross-browser experience that's *exactly* the same across recent versions of IE (6, 7, 8).

The fine people at Smashing Magazine have dissected all of the differences for us in this very useful article:

http://www.smashingmagazine.com/2009/10/14/css-differences-in-internet-explorer-6-7-and-8/

Monday, October 5, 2009

SharePoint CSS Builder

I have a project where we'd like to display a sharepoint calendar within another application. If you are using the stock SharePoint Master Pages it's pretty easy to go through and hide the navigational elements. If you use this tool: http://sharepointcanvas.com/spc/ it's abouta 2 second job.

Great tool.

Thursday, September 24, 2009

SPUtility.SendEmail truncates your message body

Use this instead to send longer emails from SharePoint:



MailMessage message = new MailMessage();
message.From = new MailAddress(list.ParentWeb.Site.WebApplication.OutboundMailSenderAddress);
message.To.Add(new MailAddress("email@email.com));
message.Subject = "Subject";
message.Body = "Body";
SmtpClient smtpClient = new SmtpClient(SPContext.Current.Site.WebApplication.OutboundMailServiceInstance.Server.Address);
smtpClient.Send(message);

Thursday, August 13, 2009

Getting WSPs out of the solution store

We recently started creating a DR farm and I needed to get the wsp's out of our production farm so i could ensure the exact same version went into the dr farm. Thankfully someone already took on this challenge:

http://spbyexamples.blogspot.com/2009/07/batch-solution-deployment-between-farms.html

Tuesday, August 4, 2009

SharePoint Public Facing Sites

This is a very good presentation on the considerations for deploying an external facing web site using SharePoint.

Thursday, July 16, 2009

Working with the BDC

I'm back to doing some BDC work and now remember how much I disliked it. I'm using hte BDC Application Definition Designer that comes with the SDK but it's always helpful to have a little refresher course on what everything does.

Randy Williams wrote and 8 part series over at SharePointMagazine.com that you should check out.

Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, Part 7, Part 8

Tuesday, July 7, 2009

Creating custom SharePoint web services

I found there are a lot of instructions on how to create web services but not many that give a best practices approach to doing this inside your solution in a way that is easy to repeat (like when you create new web methods in your custom web service and you don't want to manually re-edit all the wsdl and disco junk).

First, you need to download two things to follow along:

  1. STSDEV
  2. WSS Web Service Helper

Next, follow these steps:

  1. Create a new project in STSDEV, use the empty project C# assembly
  2. Add a new Web Service Application Project to your solution
  3. Add your web method to your web service. (If you just want to test this out, the default HelloWorld will work)
  4. Run the WSS Web Service Helper against your .asmx file (in your web service project). This will autogenerate your wsdl and disco .aspx files.
  5. Copy the .asmx file and the .cs codebehind (your webservice) and the two .aspx files generated by the WSS Web Service Helper and place them into your Rootfiles/ISAPI folder in your STSDev project.
  6. Go to your .asmx file and delete the CodeBehind attribute of the Webservice tag and place the fully qualified assembly string into the Class attribute (Namespace.Class, Assembly, Version, Culture, PublicKey)
  7. Go into the Generated *disco.aspx file and for both of the soap tags replace the address attribute with <% SPEncode.WriteHtmlEncodeWithQuote(Response,SPWeb.OriginalBaseUrl(Request), '"'); %>
  8. Next go to the *wsdl.aspx file and (at the bottom of the file) replace the location attribute of the soap12:address tag with <% SPEncode.WriteHtmlEncodeWithQuote(Response,SPWeb.OriginalBaseUrl(Request), '"'); %>
  9. Also in both the *disco.aspx and *wsdl.aspx files you need to change the <@ assembly tag to this:
    <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    because the .disco generator puts the wrong version and adds an extra Microsoft.SharePoint to the assembly reference.
  10. Deploy your project and test.
  11. Finally, if you have trouble, go here for troubleshooting, the tips are at the bottom of the article.
When you need to add or update your web methods, do it in the Web Service project and then repeat steps 4-9. Hopefully this method makes it a little less painful for you to develop custom web services in SharePoint.

Tuesday, June 9, 2009

Advanced List View Filtering

The filter section of views is limited at best, and in some cases it is just wrong. For example if you have a list and you want to filter based on this boolean expression:
Expression 1: ((Column1=A OR Column2=B) AND Column3=C) OR Column4=D
you would think you could expand the expression (because list view filters don't have parentheses) to
Expression 2: Column4=D OR Column3=C AND Column1=A OR Column3=C AND Column2=B
The SharePoint UI will group the expression in a different way, not based on the order of operations (often giving you empty results, and always giving you the wrong results)
However, SharePoint designer allows you to modify the filter yourself (of course it's kind of a pain).
Steps
  1. First make sure you've attempted to put your filter expression into view through the UI (this will place the appropriate columns in your Where clause so it will be easier to move things around.
  2. Open the list view page in SharePoint designer
  3. Find the <listviewxml> node
  4. Between the node you'll see that there is a lot of cryptic looking text that has a lot of &lt; and &gt; markup in it. This is the XML markup for the list view definition, we'll need to modify a part of this to alter the list view correctly
  5. Within this cryptic text look for '<Where', this is the beginning tag of the where clause. Once you find it, place your cursor before the '&' and highlight to the '\Where>'
  6. Copy this entire expression and paste it into notepad (or any other text editor)
  7. Do a replace on the text, replacing '&lt;' with '<' and '&gt;' with '>', now the text looks like xml (optionally, put in line breaks to make it easier to read)
  8. Now you have to build your expression, my suggestion is to start with the outermost expression and work your way in
    For example, Expression 1 builds up like so (this example doesn't include the correct syntax for the columns, only the logic):
    <where>

      <or>

        <column4=D>

        <and>

          <column3=C>

          <or>

              <column2=B>

              <column1=A>

          </or>

        </and>

      </or>

    </where>
  9. When you finally have it correct, remove your line breaks, and do a replace swapping '<' for '&lt;' and '>' for '&gt;'
  10. Paste the new where clause over the old where clause and save the page (this will customize the page from the site defintion)
  11. Test

Tuesday, June 2, 2009

SharePoint gets a minus

A while back I created several page layouts for my company so that we would have a standard format for pages, news stories, etc. We really hadn't had any problems until one of our news stories had a '+' in it's title, and thus the suggested filename had a '+' in it. Apparently you are allowed to create a page with the special character '+' in it, but it will break your page.

The behavior we saw was that you could see all the page content in edit mode, but none of it would show up when it was checked in/published. Also, there was some odd rendering of the page in edit mode.

I was scratching my head over this for a while and pretty much randomly stumbled onto the solution. In the future, I'd suggest removing any non alpha-numeric characters from file names just to be safe, even though SharePoint doesn't warn you or remove them.

Wednesday, May 20, 2009

Checking Out SharePoint Templates/Tools in Visual Studio 2010 Beta 1

For months now, ever since seeing some glimpses of the integrated SharePoint functionality in VS2010 I've been salivating at the prospect of a cohesive SharePoint development experience that it promises.

Check it out here on Channel 9.

Although the really interesting stuff is going to come with the release of the VS 2010 Tools for SharePoint, I was very excited to see what SharePoint surprises were tucked inside of the Visual Studio 2010 Beta that was released this week on MSDN.



When first choosing a SharePoint project template, nothing is available. This is because the default framework version selected is 4.0.



Switching to version 3.5 yields the SharePoint 2007 Sequential and State Machine Workflow templates.



Ultimately, attempting to create either of these projects failed. The folders were created in the file system, but there were no project, solution or workflow files to be seen.

I'm looking forward to the beta 2 / RC!

Monday, May 4, 2009

The Solution to Invalid Protocol Links in SharePoint

A client of mine recently had an issue where he wanted to insert a direct link to a FileMaker Pro document (e.g. fmp://...) in SharePoint. Both the rich text and source editors were stripping out the link, making life even more miserable for my FileMaker Pro-dependent client.

It turns out that SharePoint controls the list of allowed protocols in a static .js file, and not in Central Administration, as one might be inclined to assume.

Here's the solution:

  1. Open Core.js in Program Files\Common Files\microsoft shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\INC
  2. Look for the line with the text "Hyperlink.arrAllowedProtocols"
  3. Add the necessary protocol to the list of protocols below
  4. Return to a web browser and press Ctrl + F5 to force a reload of cached javascript files
  5. Insert the previously outlawed protocol link to test

Friday, April 17, 2009

SharePoint and SQL Agent Jobs

When you create an SSP, SharePoint automatically creates a SQL Agent job that deletes expired user sessions. However, if you are rebuilding your SSP, like I had to do recently, SharePoint will not delete the jobs it created for your old SSP. The jobs are set to run once per minute, so if one is mis-configured your SQL logs will be full of errors:
...for an incorrect target database:
[298] SQLServer Error: 18456, Login failed for user 'DOMAIN\MOSSSQLService'. [SQLSTATE 28000]
-or-
[298] SQLServer Error: 4060, Cannot open database "SharedServices_Provider_SSPPrimary" requested by the login. The login failed. [SQLSTATE 42000]

...for an incorrect user account
[298] SQLServer Error: 15404, Could not obtain information about Windows NT group/user 'DOMAIN\MOSSWrongUser', error code 0x5. [SQLSTATE 42000] (ConnIsLoginSysAdmin)
The broken jobs probably point to databases that no longer exist, so make sure the job's target database is your (new) SSP database, and that the job executes as the [domain]\SQLService user you specified during the MOSS install. You can disable or delete any old jobs. If the job hasn't been running for a while, you have probably noticed that SQL gobbles up all the RAM it has access to. Yum.

Monday, March 23, 2009

The magical AfricanPith

I was having a problem where my images in a folder in my RootFiles\Template\Layout\[ProjectName] directory of a feature solution were not being added to my wsp (or .cab) file when I did a build. After much headscratching I have found that the headscratchingly strange solution is that you need to keep the AfricanPith image in there. If I can figure out why this is, from looking at the code, I'll post the code fix.

Thursday, February 26, 2009

Unchecking the 'send email' option when adding users to a group.

Most of the time we don't want to send extra emails to people so we wanted to uncheck the send email checkbox from the New User form. Here's how:

Repeat this process for each front end-web server:
  1. Open C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\AclInv.aspx
  2. Find the control with ID="chkSendEmail"
  3. change the Checked="True" attribute of this control to Checked="False".
  4. No IISRESET is required

Dynamically add a ScriptManager in a WebPart

I've been working on creating a web part that populates a ASP.NET Ajax ReorderList with SharePoint list content, allowing you to reorder based on a column. Since all ASP.Net AJAX components require a ScriptManager you need to either add one to the MasterPage or do it dynamically. I chose to do it dynamically so only the pages that had ASP.Net Ajax components would have it (making the pages a little less bloated).

To get a ScriptManager to dynamically add for your web part, add a ScriptManager declaration to your class:

ScriptManager _scriptManager;

then add this code to your CreateChildControls method:

if(_scriptManger == null)
{
//first check to see if there is a ScriptManager loaded on the page already
_scriptManager = ScriptManager.GetCurrent(this.Page);
if(_scriptManager == null)
{
//since there wasn't one on the page, we create a new one and add it to the controls collection
_scriptManager = new ScriptManager();
this.Controls.Add(_scriptManager);
}
}

Thursday, January 29, 2009

STSDEV on 64bit and DebugRefreshAssemblyInGAC

My new development machine is 64bit and STSDEV has a few things that need to be fixed in order for it to work on 64bit machines - see my $(ProgramFiles) post. The problem I'm talking about here surfaces when you do a DebugRefreshAssemblyInGAC build.

Apparently the .vbs script that the $(ISSAPP_SCRIPT) token in the DebugRefreshAssemblyInGAC section is referring to (C:\windows\system32\iisapp.vbs), will not run until you make CScript your default script environment for *.vbs scripts.

In order to fix the errors STSDEV gives you follow these steps:

  1. Go to C:\Windows\System32 and copy cscript.exe and iisapp.vbs
  2. Place the files in another folder (I used 'C:\Utilities\Builds' as you see below)
  3. alter your DebugRefreshAssemblyInGac to read as follows

    <Target Name="DebugRefreshAssemblyInGac" >
    <Message Text="(Re)installing assembly in GAC and recycling app pool" Importance="high" />
    <Exec Command="$(GACUTIL) -if $(TargetPath)" />
    <Exec Command='cscript.exe iisapp.vbs /a "SharePoint - 80" /r' WorkingDirectory='C:\Utilities\Builds'/>
    <Message Text="" Importance="high" />
    </Target>
  4. Close your solution, then reopen and retry your build

Wednesday, January 28, 2009

STSDEV Gotcha Reference

We've tried our best to document as many gotchas as we've found while working with STSDEV, but we've never done a list as thoroughly as Jian Sun's post. Check it out as it's definitely worth the read.

Microsoft Learns You Good

Some good free training info:

  1. RAMP UPs: http://msdn.microsoft.com/en-us/rampup/dd221355.aspx

    These seem pretty helpful. I'm most interested in the workflow (since it's been a while since I've done WF development in SP and SilverLight, because that's just so darn cool.

  2. Social Networking features of SharePoint: http://www.microsoft.com/events/series/detail/webcastdetails.aspx?seriesid=92&webcastid=5448

    Chances are, unless you're brand new to MOSS, you've probably seen everything in the first 10 minutes, so skip ahead and get to the AdventureWorks demo.

Monday, January 26, 2009

Page Layouts and <asp:Content>

I had a page layout that I liked, but I needed a slightly different version, so I copied the original, made my edits, redeployed my solution and provisioned a page with the new layout. BAM! A big fat error:

Only Content controls are allowed directly in a content page that contains Content controls.


Whats the deal? Everything looked exactly like the previous, working layout... or so I thought. The copy and paste apparently changed some of the <asp:Content> controls to <asp:content>, which SharePoint does not like. Re-capitalizing my tags fixed the issue.

Friday, January 23, 2009

Another STSDEV shortcoming

I just created a development machine that is 64bit. In order to keep using STSDEV you have to go into your build targets and change the $(ProgramFiles) token to the actual hard-coded path of your program files directory, otherwise it defaults to the 32 bit program files directory.

Just do a find and replace.

Thursday, January 15, 2009

Content Type Lookup Reference

Sure you can dig all over the 12 hive looking for content type IDs. In fact, you should probably do it at least once to get an idea of what SharePoint does and what files it uses, but after you've done that. Here's the easy way.

STSDEV solution filesize limitation

STSDEV uses the MakeCab executable to build its .cab/.wsp solution files. Unfortunately, MakeCab has some holdover default settings from the dark ages of computing, one of which is its generated filesize maximum, which is set to 1.44Mb. This hasn't been a problem for me, as most packages tend to be fairly lightweight. However, when deploying a solution with lots of binary resources (a masterpage or layouts feature, for example), you will need to tell STSDEV and MakeCab that you want to build a bigger file. Deploying without making the adjustments will result in an incredibly unhelpful error from STSADM:

The file manifest.xml does not exist in the solution package.

A blogger at PointBridge was nice enough to document this here, but the fix is fairly simple so I've added the code below.

To fix your solution packages, you'll need the source for STSDEV. Open the file
\STSDev\Core\Builders\DeploymentFiles\CabDdfBuilder.cs, and enter the following at the end of the .ddf settings section, and recompile:

writer.WriteLine(".Set CabinetFileCountThreshold=0 ");
writer.WriteLine(".Set FolderFileCountThreshold=0");
writer.WriteLine(".Set FolderSizeThreshold=0");
writer.WriteLine(".Set MaxCabinetSize=0");
writer.WriteLine(".Set MaxDiskFileCount=0");
writer.WriteLine(".Set MaxDiskSize=0");

Packages generated with your new STSDEV build will no longer be truncated.



Wednesday, January 14, 2009

SPFile.MoveTo() not triggering alerts in doc library

SPFile.MoveTo(), at first glance, looks to be a very straightforward method where a file can be moved from one folder to another.

Trying to use it and have an alert triggered by your newly copied file? Forget it.

MoveTo() copies the binary to the target library as expected, but fails to recreate the item metadata (created, modified, users, dates, etc.) and will not trigger the alerts that your users set up for the target library.

To work around this problem, you can create your own method that uses the SPFileCollection.Add(), which allows you to specify metadata, as described here:

http://www.u2u.info/Blogs/Patrick/Lists/Posts/Post.aspx?ID=1141

Thursday, January 8, 2009

.NET Web Service Error: "Server did not recognize the value of HTTP Header SOAPAction"

Most of the time when we create a web service, we get to dictate what the final WSDL will look like and we use that in our application or provide it to other members on a team to consume.

A current project I'm working on requires me to create a web service based on an established WSDL that would be consumed by another service. In order for there to be interoperability between the 2, my WSDL and the reference WSDL had to be identical.

I went about creating the proxy class using WSDL.exe as I normally would and had my simple service up and running in about 5 minutes. When the external service tried to connect to mine, there was the "Server did not recognize the value of HTTP Header SOAPAction" error.

Upon closer examination, my WSDL was identical to theirs with one exception:

<soap:operation soapAction="FaultyAction" style="document" />

Should have been:

<soap:operation soapAction="" style="document" />

After some web-scouring, I finally determined how to set the soapAction attribute in the WSDL:

[WebMethod]
[SoapDocumentMethod(Action="")]
public Gateway_Response Gateway_Request(Gateway_Request returnValue)
{
...
}

Wednesday, January 7, 2009

HTML and Inline $SPUrl Gotcha

When mixing html tags and SharePoint controls, like in a custom master page or page layout for example, it's easy to make the following mistake:
<img src="<% $SPUrl:~SiteCollection/Style%20Library/MyImage.gif%>" />

Why won't this work? This doesn't work because the inline code is in a standard html tag and not a server control, and it doesn't get evaluated when the page is parsed, so the entire inline expression is just interpreted as a literal string. When this happens, you'll get this error:
Literal expressions like '<% $SPUrl:~SiteCollection/Style%20Library/MyImage.gif%>' are not allowed.
I know this is .Net 101, but if you aren't paying attention it's easy to overlook. So... don't forget to either use server controls, or specify a runat="server" attribute for your html tags.