U2U Blog

for developers and other creative minds

Enabling access to SharePoint data to a Silverlight application running outside the SharePoint context

In previous posts about Silverlight integration with SharePoint I always used Silverlight applications that are deployed to the _LAYOUTS folder, or uploaded to a document library, or even compiled as an embedded resource of a web part. In all these examples the Silverlight application runs within the context of SharePoint.

In this post I will explain how you can use SharePoint data from within a Silverlight applications that runs within a normal ASP.NET web application and thus not in the context of SharePoint.

Create a sub folder with the name ClientBin and copy the .xap file to this directory. Check the web.config of your ASP.NET web site must be Silverlight enabled.

Embed a Silverlight application in an ASP.NET web page as follows:

<form id="form1" runat="server" style="height:100%;">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    <div  style="height:100%;">
        <asp:Silverlight ID="Xaml1" runat="server"
            Source="~/ClientBin/SL.XAML.AdventureWorksProducts.xap"
            MinimumVersion="2.0.31005.0" Width="100%" Height="100%"
            InitParameters="siteurl=
http://wss.u2ucourse.com,listname=AdventureWorks Products" />
    </div>
</form>

 

Notice that you have to add a script manager tag and a Silverlight tag. The Silverlight control sets properties like Width, Height, Source and InitParameters. One of the initial parameters is the URL of the SharePoint site.

Run the web site. You will see that it generates a security error.

image

If you click the yellow warning sign in the status bar of the browser, you would see that a network error was generated. This is because you want to make a cross-domain call. To solve this issue you have to create a clientaccesspolicy.xml file that contains the following xml:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

 

This allows all calls coming from other domains. If you want to restrict the access to a well-defined domain, you have to specify that URL in the <domain uri=”…” /> node. Read more on the subject in this MSDN article.

This file must be copied to the root of the web application, in this case the SharePoint web application. You can try to copy it to the IIS web application directory but this will not help. The best way to install this file in the root is to open SharePoint Designer and to open the SharePoint web application from there. Copy the file into the root:

image

Run your web application again and it will work like a charm!

image

It's all Dynamics CRM

While working on my computer on this beautiful sunny sunday afternoon, I got a reminder about my agenda for the next week. That made me wonder which other courses were assigned to me till the end of the year. And it looks good. I will end the year with first Dynamics CRM 4.0 for Power Users and then Developing Dynamics CRM 4.0 Solutions.

I especially look forward to the second one. The first three days are similar to the Microsoft Extending Dynamics CRM Course, but the last two days we extend the scope and learn how to build solutions in combination with SharePoint 2007. I am curious to find out how many students will join us for just the last 2 days (Creating solutions using MS Dynamics CRM 4.0 and MS Office SharePoint Server 2007).

Anyway, to "celebrate" my  CRM-only agenda, I will publish a multi-part blogpost with Dynamics CRM resources for Users, Consultants, Administrators, Customizers and Developers. These resources are links collected from many different sites. They contain videos, white papers, tools, articles, source code, ...

I hope you had a nice weekend!

CRM Resources-R-us - Part II: Demos, Show Cases and Case Studies

In the second part of the “Resources-R-us” series,  I bring you links to Demos, Show Cases, Success Stories and Case Studies:

  • CRM Online Demo during Kurt DelBene's keynote at Office Developer's Conference (Video - MSN)
    Ben Riga demonstrates CRM Online (formerly CRM Live) during Kurt DelBene's keynote at Office Developers Conference (ODC) 2008. February 11, 2008
  • Microsoft Dynamics CRM Customer Showcase Launch Video (Video - Microsoft)
    This ‘Customer’ video profiles how Microsoft Dynamics CRM ‘Fits’ businesses such as Nortel, Renault, Dallas Cowboys and Mitsubishi Caterpillar Forklift Europe B.V. The running length is 4:05.
  • Microsoft Dynamics CRM Customer Showcase Brochure (Document - Microsoft)
    Make the case for your Microsoft Dynamics CRM solution sales: Learn how the platform enables other businesses to achieve consistent and measurable business-process improvements. The 26 customer success stories in this brochure feature diverse deployment scenarios—including On premise, Microsoft Dynamics CRM Online, and Partner- hosted—among small- to enterprise-size businesses in diverse industries, worldwide.
  • Microsoft Dynamics CRM Sizzle Video
    One minute video that features customers and partners describing Microsoft Dynamics CRM.
  • Microsoft Dynamics CRM Partner-Hosted Evidence Video -- Orbit Imaging (Video - Microsoft)
    This video, available in two and four minute versions, describes how an on demand CRM solution is helping a fast-growing healthcare industry franchise better target its IT investments, and obtain speed to value with its Microsoft Dynamics CRM deployment.
  • Flash Demo: Microsoft Dynamics CRM Government (Flash Video - Microsoft)
    Flash Demo around Microsoft Dynamics CRM for Governement. Build on CRM 3.0
  • Microsoft Dynamics Case Study (Document - Microsoft)
    Multitenant CRM Enables Rapid Deployment, Flexible Foundation for U.S. Dynamics Field Sales Team
  • Microsoft Solution Helps Nielsen Company Track Business More Effectively (Document - Microsoft)
    Nielsen Media Research, part of the Nielsen Company, is the world’s leading provider of television, radio, and print audience measurement and advertising information services.
  • Dynamics CRM Success Stories (Site/Links - Microsoft)
    Contains links to success stories from different industries and company sizes. The categories are Healthcare, Media + Entertainment, Education, Financial Management, Government , Professional Services, Manufacturing and Microsoft Dynamics CRM Online.
  • Dynamics CRM Case Studies (Site/Links - Microsoft)
    Microsoft Case Studies filed under Dynamics CRM.
  • Dynamics CRM Belux Success Stories: In DutchIn French
    Use the search box to filter on Dynamics CRM!

In the next part (PART III): resources that help you use Dynamics CRM.

In these series:
Part I: Introducing Dynamics CRM
Part II: Demos, Show Cases and Case Studies
Part III: Using Dynamics CRM
Part IV: Admin, Management and Deployment
Part V: Extensibility & Development
Part VI: Tools & Add-ons
Part VII: The Bits

Creating a Calendar View with PowerShell

Some days ago someone asked me if it is possible to create a calendar view on a SharePoint list. And yes, it is possible.

First let’s take a look at the .NET code to create a calendar view.

using (SPSite site = new SPSite("http://wss.u2ucourse.com"))
{
    using (SPWeb web = site.OpenWeb())
    {
        SPList sourcelist = web.Lists["Course Calendar"];

        string querystring =
            "<OrderBy><FieldRef Name='Title' /></OrderBy>"
          + "<Where><DateRangesOverlap><FieldRef Name=\"EventDate\" />"
          + "<FieldRef Name=\"EndDate\" /><FieldRef Name=\"RecurrenceID\" />"
          + "<Value Type=\"DateTime\"><Week /></Value></DateRangesOverlap></Where>";

        SPView newview = sourcelist.Views.Add("DemoCalView", null,
               querystring, 3, false, false,
               SPViewCollection.SPViewType.Calendar, false);
                        

        newview.ViewFields.Add(sourcelist.Fields["Title"]);
        newview.ViewFields.Add(sourcelist.Fields["Start Time"]);
        newview.Update();

    }
}

 

If you go to your SharePoint site and inspect this new view you will see that only the entries for this week are visible because of the DataRangesOverlap query that is set to weekly, but that it shows the data in a monthly view. This is because of the calendar scope that you can set in the user interface, but how to create a calendar view with a weekly scope programmatically?

Now to PowerShell. To create that same view with PowerShell you have to execute the following commands:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$siteUrl = "
http://wss.u2ucourse.com"
$site = new-object Microsoft.SharePoint.SPSite($siteurl)
$web = $site.OpenWeb()
$list = $web.Lists["Course Calendar"]
$querystring = "<OrderBy><FieldRef Name='Title' /></OrderBy>"
$querystring += "<Where><DateRangesOverlap>"
$querystring += "<FieldRef Name='EventDate' /><FieldRef Name='EndDate' />"
$querystring += "<FieldRef Name='RecurrenceID' />"
$querystring += "<Value Type='DateTime'><Week /></Value>"
$querystring += "</DateRangesOverlap></Where>"
$newview = $list.Views.Add("DemoCalView", $null, $querystring, 3, $false, $false, "CALENDAR", $false)
$titlefield = $list.Fields["Title"]
$newview.ViewFields.Add($titlefield)
$datefield = $list.Fields["Start Time"]
$newview.ViewFields.Add($datefield)
$newview.Update()

I hope to have helped someone out :)

Creating Search Content Sources with a PowerShell CmdLet

In this blog I already posted many tips on how to use PowerShell on SharePoint. PowerShell has been developed by Microsoft for performing Windows Administration tasks. You can even automate tasks by writing PowerShell scripts. PowerShell works with the .NET object model. This means that you need an in-depth knowledge of the object model of the technology you want to manage with PowerShell. In the case of SharePoint this is a really big beast with a lot of facets. As you or your administrator wants to perform more advanced management tasks your PowerShell commands and scripts will become a lot more complicated. In that case you can extend PowerShell functionality with PowerShell CmdLets.

In PowerShell version 1.0 CmdLets are written in managed code, meaning in languages like VB.NET and C#. There exist Visual Studio templates that can used to develop your custom PowerShell CmdLets.

Now I hear you think: “Wait! Why bother writing PowerShell CmdLets if you can solve this issue by developing custom STSADM commands?”. At this point you can start a discussion on what the best option is. I advise the following rule of thumb: if you or your administrator only has to manage SharePoint, than you go for custom STSADM commands because in that case STSADM is part of your daily job. If you or your administrator uses PowerShell to perform administrative tasks on different technologies (like SQL Server, Exchange and SharePoint), your best option is PowerShell CmdLets.

The base principles of writing PowerShell CmdLets are explained in this MSDN article.

In this post I will explain how you can manage Search content sources using PowerShell and how you can develop custom PowerShell CmdLets to create a new content source.

You can download the source code for the PowerShell CmdLet here. Be aware that this is demo code and that it need to be extended with solid exception handling.

When you want to work with Search content sources you first have to load the necessary assemblies:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Search")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.Search")

 

Then you have to retrieve an instance of the Shared Service Provider. As PowerShell doesn’t run in the context of SharePoint, you have to pass the name of the Shared Service Provider to the static method GetContext of the Microsoft.Office.Server.ServerContext class. In PowerShell you achieve this as follows:

#Instantiate Shared Service Provider
$serverctx = [Microsoft.Office.Server.ServerContext]::GetContext(“U2USharedServices”)

 

Once you have retrieved an instance of the Shared Service Provider you have access to the services that it hosts. The Search service is one of these services. You can instantiate the Search service by executing the GetContext static method of the Microsoft.Office.Server.Search.Administration.SearchContext class.

#instantiate the Search Service

£
$searchctx = [Microsoft.Office.Server.Search.Administration.SearchContext]::GetContext ($serverctx)

#display the name of the search service instance
$searchctx.Name

 

You can retrieve and display the Search content sources as follows:

#show the available content sources
$content = new-object Microsoft.Office.Server.Search.Administration.Content($searchctx)

foreach ($cs in $content.ContentSources)
{
    Write-Host "NAME: ", $cs.Name, " - ID: ", $cs.Id, " - CrawlStatus: ", $cs.CrawlStatus
    Write-Host "Full Crawl Schedule: ", $cs.FullCrawlSchedule.Description
    Write-Host "Incremental Crawl Schedule: ", $cs.IncrementalCrawlSchedule.Description
}

 

The trouble starts when you now want to create a new content source using PowerShell because you need to specify the type of content source you want to create. As you already know, you can create content sources of the following types:

  • WebContentSource                          
  • SharePointContentSource
  • FileShareContentSource
  • ExchangePublicFolderContentSource
  • BusinessDataContentSource

If you want to create a FileShare content source you can write this as follows in C#:

 

ContentSource newContentSource = content.ContentSources.Create(
     typeof(FileShareContentSource), nameContentSource);
newContentSource.StartAddresses.Add(new Uri(url));
FileShareContentSource fileShareContentSource =
     (FileShareContentSource)newContentSource;
fileShareContentSource.FollowDirectories = true;
fileShareContentSource.Update();

 

As you can see, the Create method asks for the type of the content source. The second parameter is the name for the new content type. You also have to specify the start address URL. In case of a file share  content source you can also specify whether you want to index the sub folders or not. After having set the  necessary properties you have to execute the Update method.h

Executing the correct Create method is rather difficult to achieve in PowerShell. It would be easier if you could execute something like this:

set-createcontentsource “name of the SSP” “name new content source” “type of content source” “start address”

 

In this case you can opt to write a PowerShell CmdLet to extend PowerShell functionality. PowerShell CmdLets are written in managed code. There exist a couple of Visual Studio project templates that you can download and use. (The link was down this weekend but I hope it will be restored).

Open Visual Studio 2005 and choose Windows PowerShell as project type in the left pane and the Windows PowerShell template in the right pane.

image

This creates a project skeleton consisting of a  PSSnapIn file and a class inheriting from. The project contains a reference to the System.Management.Automation assembly. This assembly comes with the PowerShell SDK.

Right-click the PSSnapIn file to view the code. The code contains 5 properties that need to be set by you. The most important one is  the Name property which will be used when you register your PowerShell CmdLet. The class inherits from PSSnapin which is the base class for creating snap-ins. Snap-ins are the deployment unit of Windows PowerShell and are tagged with a RunInstaller attribute for registering the Snap-in with PowerShell.

[RunInstaller(true)]
public class CreateContentSourceSnapIn : PSSnapIn
{
    public override string Name
    {
        get { return "CreateContentSourceCmdLet"; }
    }
    public override string Vendor
    {
        get { return "U2U"; }
    }
    public override string VendorResource
    {
        get { return "CreateContentSourceCmdLet,U2U"; }
    }
    public override string Description
    {
        get { return "Registers the CmdLets and Providers in this assembly"; }
    }
    public override string DescriptionResource
    {
        get { return "CreateContentSource,Registers the CmdLets and Providers in this assembly"; }
    }
}

 

The name will be used to register the CmdLet.

A Snap-in contains one or more CmdLets. A CmdLet is a class that inherits from the base class CmdLet residing in the System.Management.Automation namespace.

The class is preceded by the name of the CmdLet and consists of:

  • a verb that indicates the action of the CmdLet (get or set)
  • a noun that must be specific and describe what the action will perform

In this case the name of the CmdLet looks as follows:

[Cmdlet(VerbsCommon.Set, "CreateContentSource", SupportsShouldProcess = true)]
public class CreateContentSource : Cmdlet
{

}

 

You can define a number of parameters if the CmdLet needs some exra information before it can execute its extra functionality. As this sample CmdLet is going to create a new content source, it defines 4 parameters:

  • name shared service provider
  • name content source
  • type of the content source
  • start address of the content source

The first incoming parameter is the SharedServiceProvider name and is defined as follows:

private string nameSharedServiceProvider;

[Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true,
    HelpMessage = "The Name of the Shared Service Provider")]
[ValidateNotNullOrEmpty]
public string SharedServiceProviderName
{
    get { return nameSharedServiceProvider; }
    set { nameSharedServiceProvider = value; }
}

 

The Position attribute indicates that this parameter is the first one that need to be specified when the CmdLet is executed. The Mandatory attributes indicates that this attributes is required. The ValueFromPipelineByPropertyName attribute means that the value for this attribute can come from a property in the incoming pipeline object that has the same name as the parameter. You can specify a HelpMessage attribute that will display when help is asked for the CreateContentSource command. The ValidateNotNullOrEmpty is a validation rule indicating that the incoming value cannot be null or empty.

The other parameters are defined in a similar way.

There is one member to override: the ProcessRecord method. In this method you need to write the implementation code of your extra functionality. The implementation in the sample looks as follows:

protected override void ProcessRecord()
{
    Microsoft.Office.Server.ServerContext serverctx = null;
    SearchContext searchctx = null;

    try
    {
        // open the context of the Shared Service Provider
        serverctx = ServerContext.GetContext(nameSharedServiceProvider);
        if (serverctx != null)
        {
            searchctx = SearchContext.GetContext(serverctx);
            WriteObject("Connected to search context " + searchctx.Name);

            if (searchctx != null)
            {
                Content content = new Content(searchctx);

                switch (typeContentSource)
                {
                    case "sharepoint":
                        CreateSharePointContentSource(content);
                        break;

                    case "web":
                        CreateWebContentSource(content);
                        break;

                    case "fileshare":
                        CreateFileShareContentSource(content);
                        break;

                    case "exchange":
                        CreateExchangeContentSource(content);
                        break;

                    case "bdc":
                        CreateBDCContentSource(content);
                        break;
                }

            }
        }
    }
    catch (Exception ex)
    {
        WriteObject("ERROR: " + ex.Message);
    }
}

 

Each type of content source is created in a separate private method. When an exception occurs the error message is written to the console.

This is the sample code for the creation of the file share content source:

private void CreateFileShareContentSource(Content content)
{
    ContentSource newContentSource = content.ContentSources.Create(
        typeof(FileShareContentSource), nameContentSource);
    newContentSource.StartAddresses.Add(new Uri(url));
    FileShareContentSource fileShareContentSource =
        (FileShareContentSource)newContentSource;
    fileShareContentSource.FollowDirectories = true;
    fileShareContentSource.Update();
    fileShareContentSource.StartFullCrawl();
}

 

When the content source is created and the properties set, a full crawl on the new content source is started.

When the code is ready to deploy, build your project. To register the CmdLet with PowerShell open a Visual Studio command prompt, navigate to the bin\debug folder of your project and execute the installer by running the InstallUtil tool.

Installutill CreateContentSourceCmdLet.dll

 

Open Windows PowerShell and load the SharePoint assemblies if this is not yet done by your profile. Load also the PowerShell snap-in by executing the following:

Add-PSSnapIn CreateContentSourceCmdLet

 

This is the name you specified in the PSSnapIn installer class.

I can now create a new content source in PowerShell by executing the following:

set-createcontentsource “U2USharedServiceProvider” “Office Documents” “fileshare” “\\springfield\DocsToIndex”

 

When this command has executed successfully, the new content source will appear in the Search Settings pages of the SharePoint Central Administration.

image

image

A bit besides the subject of this post, but I read an excellent post on how to index and search your .NET source code and PowerShell scripts here.