Lars Haupt-Hansen

Bits about SharePoint and other Microsoft Tech

TFSFieldMapping in TFS11

clock March 13, 2012 13:39 by author Lars Haupt-Hansen

TFSFieldMapping can be used to set the mapping between Microsoft Project and Team Foundation Server.

The usual path for TFSFieldMapping is C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE, but now it has moved to C:\Program Files\Common Files\Microsoft Shared\Team Foundation Server\11.0

If you use the old one you will get an error like:

TF200037:  You cannot update the MSPROJ property when using Microsoft Visual Studio Team System 2008 or an earlier version. Try the operation again with a compatible version of Visual Studio Team System.



Problem with PowerPivot Gallery Silverlight Control

clock October 19, 2011 16:50 by author Lars Haupt-Hansen

 

Been fiddling with the Denali CTP and the PowerPivot integration to SharePoint and the Carousel view is awesome (and also available on SQLServer 2008 R2 I believe)

image

But whenever I turned on our Custom masterpage the back/next arrow disappeared and the page just kept getting bigger and bigger (the scrollbar handle kept getting smaller and smaller). Switching back to V4.master resolved the problem.

A quick jump to Firefox/Firebug found the culprit:

image

The height of the <object> tag kept increasing.

Powering up Reflector on the Silverlight application revealed a method evaluating the difference in ScrollHeights between the s4-workspace and s4-bodyContainer <DIV> tags. This method does not always work as intended.

Investigating some more I found the root cause to be this CSS on our custom stylesheet.

#s4-topheader2

{

    margin-bottom: 26px;

}

 

Removing this makes the Silverlight control render correctly.



Checking event receivers in SharePoint 2010 using PowerShell

clock January 28, 2011 12:35 by author Lars Haupt-Hansen

Ever gotten to a point where you wondered if SharePoint has registered your EventReceiver or not? Well, I have, so here's how to check it using SharePoint PowerShell:

 

$w = get-spweb <URL-TO-WEB>

$l = $w.Lists['<LIST-NAME']

$l.EventReceivers



SharePoint and non-Office files

clock August 16, 2010 20:17 by author Lars Haupt-Hansen

In an ealier post I concluded that .MSG files were inappropriate for a mail archiving store as the user is only presented with Save and Cancel when clicking on them in SharePoint 2010.

Today I discovered the hard way that it also applies to PDF files and a range of other file types. Googling Binging a little on the subject found this http://whitepages.sfintelligence.com/index.php/2010/05/opening-pdf-files-in-sharepoint-2010/

It seems that it is security hardening in SharePoint 2010 that prevents the user from seeing the files directly. Fortunately there is a simple workaround (described above).

This also makes .MSG files open in Outlook as expected.



Creating a Custom Field Type in SharePoint 2010

clock July 5, 2010 17:16 by author Lars Haupt-Hansen

MSDN has been updated with a nice walkthrough on how to create a custom field type in SharePoint 2010

Most things are the same, but the walkthough also touches on new elements as SharePoint Mapped Folders (in Visual Studio 2010) and XSLT styles of the field values.

You can find it http://msdn.microsoft.com/en-us/library/bb861799.aspx or in the downloadable SharePoint 2010 SDK



Using SharePoint 2010 as a unified mail store – Part 2

clock June 30, 2010 22:20 by author Lars Haupt-Hansen

Last time we started on a solution allowing the user to save emails off the SharePoint, where they could be indexed and and found by other people:

  • right-click on mails in Outlook, choose a location  (part 1)
  • determine the format to save the mail message (this part)
  • and save the message off to SharePoint which will then index it so we can find it later.

In this article we will look into the SharePoint part.

But first lets consider the format to save the email in.

.MSG Native Message format. The entire message is stored including all the attachments

.MHT (HTML archive, stored in MIME format) Stores the message and inline images, but not attachments.

.HTML Plain HTML file - stores the message only.

First of all – SharePoint Search indexes all of the above file-types (.MSG also including attachments), so that will not be an issue.

But of these three only the first would meet my expectations. If I wanted to save a mail somewhere, I’d assume that the attachments also was saved.

The problem with .MSG is the presentation part. If I upload a .MSG file to a Document Library in my SharePoint 2010 environment and try to click it this is what’s not happening: Outlook shows me the file. What does happen is one of two things. Either I get presented by an Open/Save/Cancel dialog box (and Open will show the mail in Outlook) or by a Save/Cancel dialog box, where I first have to save the item off locally and then open it. Users deserve better.

My first thought then was to create a custom action for .MSG files on SharePoint displaying the mail in a dialog box. .NET libraries for parsing .MSG files exist – a quick search found Aspose, but I have never tried it.

But then it occurred to me. Why not use the new feature in SharePoint 2010 called Document Sets. Document sets fit perfectly:

  • They are indexed by SharePoint
  • The can contain multiple items, i.e. The mail message and attachments
  • The can have metadata, i.e. I can extract subject, from, to and other relevant fields into the Content Type and have them appear on my list of mails.

So, stay tuned for how to create Document Sets using the brand new .NET Client API. (seems that the Client API only extends to SharePoint Foundation 2010 and Document Sets are a feature of SharePoint Server 2010 and thus not in the Client API’s, so we’ll do it on the server instead)



Using SharePoint 2010 as a unified mail store

clock June 30, 2010 20:05 by author Lars Haupt-Hansen

Today I’ll start on creating an add-in to Outlook, that will allow users to

  • right-click on mails in Outlook, choose a location  (part 1)
  • and save the message off to SharePoint (part 2)  which will then index it so we can find it later.

The first step is of course to power up VS2010 and create an Outlook 2010 add-in.

The next thing we do is to add a Ribbon as ContextMenus (right-click menus) are stored in the Ribbon XML. This can be done by following to guide on MSDN.

Now my company stores our contacts in Microsoft CRM, and it is especially these mails that we would like to move out of my mailbox and into somewhere common.

What I would like to do however is to make a menu appear with all the projects for the customer so the owner of the mailbox (me Smile) can choose which project the mail is about or if it is a general mail

Menues that are dynamic in this way is aptly named <dynamicMenu> (MSDN), so we’ll create a new Ribbon and paste the following XML into the file:

<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
<contextMenus>
<contextMenu idMso="ContextMenuMailItem">
<dynamicMenu id="SaveToSharePointMailItemMenu"
imageMso='Forward'
label="Save to intranet"
getContent="SaveToSharePointMailItemMenuGetContent"
/>
</contextMenu>
</contextMenus>

</customUI>

The first thing here is the idMso attribute which specifies which menu we want our context menu to appear in. The first link to MSDN contains the magic id’s to use.

The other interesting part here is the getContent attribute which specifies the method to call when the menu items of the menu are created.

So we create a method GetContent() along the lines of:

public string SaveToSharePointMailItemMenuGetContent(IRibbonControl control)
{

StringBuilder MyStringBuilder = new StringBuilder(@"<menu xmlns=""http://schemas.microsoft.com/office/2009/07/customui"" >");
int buttonid = 1;

Selection selection = control.Context as Selection;

// we are using COM wrappers, so indexes start at 1, sigh ...
MailItem mail = selection[1] as MailItem;

Customer customer = CustomerFactory.GetCustomer(mail);

MyStringBuilder.Append(@"<button id='SaveToCustomerButtion' label='"+customer.Name+"' />");
if (cust.Projects.Count > 0)
{
// the Title of the menu separator is generated by the GetTitle() method
MyStringBuilder.Append(@"<menuSeparator id=""menusep1"" getTitle=""GetTitle"" />");
foreach (Project p in customer.Projects)
{
MyStringBuilder.Append(@"<button id='SaveToProject" + (buttonid++) + "' onAction='OnAction' label='" + p.Name + "' imageMso='CitationInsert' />");
}

}
MyStringBuilder.Append(@"</menu>");
return MyStringBuilder.ToString();
}

This will inspect the current item (for the first of multiple items if isMSO is set to ContextMenuMultipleItems) and find the relevant customer. The can be done using the properties on the MailItem.

Now if we hit F5 Outlook will fire up and we should see a “Save to Intranet” menu below the Delete option, when we right-click a mail in inbox. If you don’t, remember to add the CreateRibbonExtensibilityObject() method as described in the auto-generated comments in top if you add-in code.

The observant reader will have noticed the onAction=”OnAction” part of the Button tags. This allows us to call code, when the user (still me Smile) selects the menu item. This method is pretty simple:

public void OnAction(IRibbonControl control)
{
Selection selection = control.Context as Selection;

SharePointMailLibrary library = new SharePointMailLibrary();
foreach (MailItem mail in selection)
{
library.SaveDocument(mail);
}
}

In the next part I’ll describe saving off the mail to SharePoint.



Integrating Reporting Services into Microsoft Word – part 2

clock June 29, 2010 11:01 by author Lars Haupt-Hansen

In part 1 I created an AddIn to Microsoft Word and listed all reports on a Reporting Services solution in a Custom Task Pane.

I now want the task pane to show the parameters in the custom task pane when the user selects a report.

Developers new to Reporting Services should really start by reading Identifying Execution State, as this a good introduction to loading and rendering reports.

Having read that I discarded the on ReportingServices2005.GetReportParameters() and used ReportExectionService.LoadReport() (MSDN) instead:

    Exec.ReportExecutionService execService = new Exec.ReportExecutionService();
execService.Credentials = CredentialCache.DefaultCredentials;
string historyID = null;
    Exec.ExecutionInfo execInfo = new Exec.ExecutionInfo();
    Exec.ExecutionHeader execHeader = new Exec.ExecutionHeader();
   
    execService.ExecutionHeaderValue = execHeader;
    execInfo = execService.LoadReport(reportPath, historyID);

The report path is the path the RS report return by CatalogItem (MSDN).

The reason for this is that it will populate the ExecutionInfo (MSDN) data structure. One of the properties is the collection of ReportParameter (MSDN). And the ReportParameter class contains a collection ValidValues (MSDN). The list of ValidValues are populated if Reporting Services can do so with the given parameters. So if you have a report which lets the user choose a customer from a drop-down (probably fetched from a database somewhere and presented a Parameter with DataSet backing). Reporting Services will run that query for you and put the list of customers into ValidValues.

Now some parameter values depend on the user choosing other parameters first. If the customers before had projects, the Project parameter should of course only show the projects of the customer not all projects. Reporting Services allows for that by parameterized Datasets and will enforce that by disabling the parameters until the required parameters are set. The same thing happens in code.

In the above example of Customer -> Project relationship, Reporting Services will populate the ValidValues for the customer parameter, but not for the project parameter. What Reporting Services will do is to populate two other properties – State (MSDN) and Dependencies (MSDN).

State will have one of the four values of ParameterStateEnum (MSDN). The one we are interested in here is HasOutstandingDependencies. It tells us that the valid values cannot be calculated because some of other parameter has to be filled out first. The list of these dependencies is in the Dependencies collection.

The way to specify these parameters I by using ReportExectionService.SetExecutionParameters() (MSDN). . This method returns a new ExecutionInfo (MSDN) object which can be examined for valid values. Thus you keep calling SetExecutionParameters() until all the parameters in the resulting ExecInfo has State equal to HasValidValue.

Now all the parameters are valid and we are ready to call ReportExectionService.Render() (MSDN). The MSDN documentation on this is pretty decent, so I’ll skip that and go to the result:

result = execService.Render(format, devInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
Globals.ThisAddIn.InsertInDocument(format, result, extension);

 

If the format is “IMAGE” the result is the TIFF image, so, InsertInDocument is something like:

internal void InsertInDocument(string format, byte[] result, string extension)
{
Word.Selection selection = Globals.ThisAddIn.Application.Selection;
string tempFile = Path.GetTempFileName() + "." + extension;

FileStream stream = File.Create(tempFile, result.Length);
stream.Write(result, 0, result.Length);
stream.Close();
selection.InlineShapes.AddPicture(tempFile);
}

And presto, we have inserted the report as an embedded image in the Word Document. Only caveat here is that Reporting Services renders TIFF as full page, so the image might have to be cropped

You could probably find code for auto-cropping or you can insert render the report as MHTML and insert that instead.



Integrating Reporting Services into Microsoft Word – Part 1

clock June 29, 2010 10:47 by author Lars Haupt-Hansen

Recently I had a customer interested in integrating reports from SQLServer Reporting Services into Microsoft Word documents. Finding the problem intriguing I tried to create a solution.

First I created an Office 2010 AddIn using Visual Studio 2010. I then created a custom ribbon to show/hide a custom task pane in Word. These technologies have been shown elsewhere, so I'll skip these.

My company is currently using a Reporting Services 2005, so I went to MSDN to look up the webservice for Reporting Services.

It turned out that there was actually two webservices:

ReportingServices2005 Allows for listing and manipulating the different elements residing on your RS server.

ReportExecutionService Rendering of reports

So first I wanted to load all reports into a TreeView, so I started by calling ReportingService2005:

    ReportingServicesAddIn.ReportingServices.ReportingService2005 service = 
        new ReportingServices.ReportingService2005();

    // Use the current user as credentials 
    service.Credentials = CredentialCache.DefaultNetworkCredentials;

    // register a callback, when the request completes
    service.ListChildrenCompleted +=
        new ListChildrenCompletedEventHandler(service_ListChildrenCompleted;

// send the request to RS
    service.ListChildrenAsync("/"true);

 

This sends an asynchronous request to the Server to return all items. We will make the call asynchronously, so Word stays responsive while the request is processed. The callback does so housekeeping to insert the elements into the TreeView, but I won't bore you with those:

    void service_ListChildrenCompleted(object sender, ListChildrenCompletedEventArgs e)
    {        List<CatalogItem> list = e.Result.ToList();

        foreach (CatalogItem item in list)
        {
     // This is a folder,

         if (item.Type == ItemTypeEnum.Folder)
            {
             // send the request to RS
            }
            // send the request to RS
            else if (item.Type == ItemTypeEnum.Report
                    || item.Type == ItemTypeEnum.LinkedReport)
            {
                if (!item.Hidden) // don't show hidden items.
                {
         /* code deleted */
                }

            }
        }
    }


The interesting element here is the CatalogItem (MSDN) which contains information regarding the elements.

 

The end result was something like this:

 

 

Having populated the tree with all reports from the server, the next thing I wanted to do was to insert a report in the Word document as an image. But there is a snag – most reports (at least ours J) require the user to enter parameters controlling what is displayed.

Quickly scanning the documentation on ReportingServices2005 (MSDN) gave the promising GetReportParameters() method (MSDN). This does the trick of listing the parameters and their datatypes, but when we get to more user-friendly presentation of the parameters, we'll see that is lacking. I'll talk more about that in Part 2.




My name is Lars Haupt-Hansen, and I'm CTO and technical architect at Itera Consulting.

My main interests are SharePoint 2010 and how to integrate it and other Microsoft products into business applications that leverage the investmests that the customers have already made. 

Microsoft IT Professional Certifications
Microsoft Professional Developer Certifications

Sign in