Sunday, November 22, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Installing SharePoint 2010 Beta on Windows 2008 Server R2

Updated November 23rd
Warning for the hotfix for the token authentication in WCF (kb971831)

see :
7.6 hotfix for the token authentication in WCF

1 - Introduction

 For those who have the chance to be allowed to download the SharePoint 2010 Beta because they benefit of an MSDN subscription or because they are employed by a company that is a Microsoft partner, here is a way to install the Beta version of SharePoint 2010 in order to test it.
As usual I will do my best to supply a step by step tutorial as detailed as possible which demonstrates how to install 2010 SharePoint Bêta on Windows server 2008 R2.

- Environment for this SharePoint 2010 installation:

The environment I propose to mount in this tutorial is a development environment that uses a SharePoint 2010 Beta Farm installation on a single computer using an unique local administrator account.

The SharePoint 2010 content databases will run on a SQLServer 2008 Standard Edition Database Engine.

I personally have not a MSDN subscription to date (but maybe have it soon) but my company is a Microsoft partner, so I had the chance to have the Beta version of SharePoint but for the OS, I chose to take advantage of testing the new version of SharePoint by testing in the same time the Windows 2008 Server R2 OS because Microsoft provides presently an 180 days evaluation version of it.

As you certainly know, SharePoint 2010 requires a 64 bits OS to run.
Therefore, I have chosen to create the Virtual Machine with VMware Workstation 6.5.3 because it is to date the only way of making run an 64 bit OS guest on a 32 bits OS host.

I will check if it is possible to mount an image with the free VMware Player product in order this tutorial do not require any purchase for a developer that has the benefits of the SharePoint Beta download. If it is possible, I will publish about it later.

Updated November 23rd [...

I have verified that you can actually also create a Virtual Machine running Windows 2008 Server R2 64 bits on a 32 bits host by using the free version of VMware:

VMware player 3.0.


You can download this software after registration at:

http://downloads.vmware.com/d/info/desktop_downloads/vmware_player/3_0

...]

Last, if you want to install SharePoint 2010 using Domain Accounts, you can visit the post of Jeremy Thake, very useful with treeview menu listing all the operations to be performed:

Install SharePoint 2010 Public Beta on Standalone Windows Server 2008

2 Creating the Virtual Machine

 2.1 Download Windows Server 2008 R2 Evaluation

Windows Server 2008 R2 is available in 64-bit (x64) only.

 You have to register to obtain it.

Open VMWare and Select "New Virtual Machine"

The new virtual machine wizard is opening

Choose the option "Installer disc image file "  and browse to refer the previously downloaded image of the Windows 2008 Server R2.
The wizard will detect automatically the OS version and will start easy install.

The wizard will retrieve automatically your user account.
Don't provide any product key you don't need any for this evaluation version, but take time to provide a password because this account will be your Administrator account of your new Virtual Machine and using an Administrator account that has not a password will lead to many problems when configuring your machine  and more trouble when working with SharePoint 2010.

Click OK to the warning message

Choose your Virtual machine name and location.

On this screen let the default values

The Wizard summarize your settings but you can still change some by clicking "Customize Hardware...". Especially the RAM allocated to the Virtual Machine.



When you click "Finish", the installation begins by loading the files.

Then, you have to choose the version of your Operating System.
Do not choose a Web Server version otherwise you will not be able to add an "Application Server" role to the server later.
Choose the Full Installation of the Enterprise Version.



The Easy install will install the OS automatically and in my case it did it in approximately 30 minutes!



Then you can access to your new server. You will see the "Initial Configuration tasks".

After you have completed the installation of Windows Server® 2008 R2, and before you deploy the new server in your enterprise, some configuration is required to identify the computer to other computing resources on your network, secure the computer, enable administrators to perform tasks on the computer, and customize the computer by adding server roles and features.
You can complete these tasks by using commands in the Initial Configuration Tasks window, which opens immediately after the operating system installation is complete.
The Initial Configuration Tasks window opens at each startup, unless the Do not show this window at logon check box is selected.

If you want to open this windows manually run this command:

C:\Windows\System32\Oobe.exe

3 Configuring the server - Standard Configuration Operations

3.1 Hardware Acceleration

In order to accelerate your Virtual Machine you have to perform the following operations :
Right click your desktop and choose "Screen resolution".

Then, click
Troubleshoot tab
Change Settings button

You will access to the "Display Adapter Troubleshooter" dialog.
Set the cursor to the Full position.

3.2 Windows Activating

Go back to the "Initial Configuration tasks" windows and we are going to go through the standard configuration operations easily because the windows lits them.

 

Be sure the Virtual Machine has an Internet Access.

We have to activate Windows in order to take advantage of the 180 days of the evaluation process.
Click on the "Activate Windows" link.



Do not look for any product key, as said before, you do not need any, just click next.

The activation will be done automatically through Internet. You will notice then the activation number and the number of days remaining on the bottom right corner of the desktop.

3.3 Changing Computer Name

Now, click the "Provide computer name and domain" link,then set your new Virtual machine name.

3.4 Downloading Updates

Click the "Download and install updates link" then turn on automatic updates, and proceed to the latest updates installation.

i

Then restart the Virtual machine.

3.5 Disabling Internet explorer Enhanced Security

To disable Enhanced Security Configuration to specific users by using a computer running Windows Server 2008

  1. Click Start, point to Administrative Tools, and then click Server Manager.
  2. If the User Account Control dialog box appears, confirm that the action it displays is what you want, and then click Continue.
  3. Under Security Summary, click Configure IE ESC.
  4. Under Administrators, click On (Recommended) or Off, depending on your desired configuration.
  5. Under Users, click On (Recommended) or Off, depending on your desired configuration.
  6. Click OK.
  7. Restart Internet Explorer to apply Enhanced Security Configuration.

G

4 Configuring the server - Configuration Operations for SharePoint (MOSS 2007 or SharePoint 2010)

4.1 Adding Server Roles and Roles Services - Application Server - Web Server

On the Initial configuration task windows, click "Add Roles"
The "Add Roles" Wizard is opening.
Check the check box for Application Server.
The wizard opens a modal dialog for the Required Features

Just click the "Add Required Features" button.
You are taken to and intermediate dialog. Click "Next" to go to the "Role Services" dialogs.
Click "Next"

On the "Role Services" dialog, select the followings :
.Net Framework 3.5.1
Web Server (IIS) Support
TCP Port Sharing
HTTP Activation
TCP Activation
Named Pipes Activation

Then Click "Next"
You are taken to an the intermediate page for the Web Server (IIS) Role

Click "Next"
The Select Role Services for Web Server (IIS) Role is displaying, but just let the default options.

Click "Next" to access the confirmation dialog

Then click "Install" and the Roles and Features are being installed

Check the "Installation Result" dialog and close it.

5 Installing SQL Server 2008

For these operations I let you consult one of my previous post that explains the same for Windows 2003 Server. The operations are exactly the same.

Integrating Reporting Services 2008 with SharePoint 2007 Step 1 - SQL Server 2008 Installation

6 Downlaoding the Microsoft SharePoint Server 2010 Beta

Go to this page to download the Microsoft SharePoint Server 2010 Beta. You have to register to access to the download.

Download the Microsoft SharePoint Server 2010 Beta

You will notice that a link is available toward the

SharePoint Server 2010 system requirements

I chose the Microsoft SharePoint Server for Internet Sites Enterprise 2010 Beta

The next section will detail the required things to do in order to be compliant with these requirements. As we install SharePoint on Windows 2008 Server R2 and because we have run the latest updates, most of the required add in will be useless.

7 Configuring the server - Configuration Operations for SharePoint 2010 Beta 1

7.1 Downloading and installing SQL Server 2008 SP1

First, we have to update the previously installed SQL Server with the SP1 downlodable at :

SQL Server 2008 Service Pack 1

Do not forget to choose the x64 package

Here is the package after the download

and the first installation screenshot

7.2 Downloading and installing Cumulative update package 2 for SQL Server 2008 Service Pack 1

Then, we have to install the Cumulative update package 2 for SQL Server 2008 Service Pack 1

Cumulative update package 2 for SQL Server 2008 Service Pack 1

Follow the regsitration process. You will be provided an auto extractable package that needs a password and the appropriate password.

Here is the screenshot after all the process

and the first installation screenshot

7.3 Downloading and installing SQL Server 2008 Analysis Services ADODM.NET

For ending with the products related to SQLServer 2008 download and install the SQL Server 2008 Analysis Services ADODM.NET. Here is the direct link to the download:

ADOMD.NET

Here is the screenshot after the download.

And the first screenshot

7.4 Downloading and installing  Geneva framework Runtime

This is useful even before launching the SharePoint prerequisites installation.

Geneva Framework Runtine

Here is the screenshot after the download.

And the first screenshot

 

7.5 Downloading and installing  Microsoft Sync Framework Runtime v1.0 (x64)

 

Microsoft Sync Framework Runtime v1.0 (x64)

Here is the screenshot after the download.

And the first screenshot

7.6 hotfix for the token authentication in WCF

Regarding the update (KB971831),

hotfix that provides a method to support the token authentication without transport security or message encryption in WCF

it seems that the link supplied by MSDN and by the page "Determine hardware and software requirements (SharePoint Server 2010)" are not leading to the correct update for the R2 version of the OS.

As referenced by Jeremy Thake in his post, I think the good update is to find at:

http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=23806

Its name: Windows6.1-KB976462-x64

I performed the installation today and it ran perfectly well.

You can find the complete explanation regarding this update on the SharePoint Team Blog:

Installation notice for the SharePoint Server Public Beta on Microsoft Windows Server 2008 R2 and Microsoft Windows 7

8 Microsoft SharePoint Server for Internet Sites Enterprise 2010 Beta Installation

8.1 Installing the SharePoint Prerequisites

Double click the installation package to launch the installation of  Microsoft SharePoint Server for Internet Sites Enterprise 2010 Beta

The SharePoint 2010 installation Wizard is opening

Click the "Install Software Prerequisites" in order to update, complete and check the previous preparation described in the previous sections of this post. The Microsoft SharePoint Product and technologies 2010 Preparation Tool is opening

Accept the licence agreement

The prerequisites are being installed 

You should obtain this screen if you followed the operations previously described in this post.

8.2 Installing the SharePoint Files

Back to the SharePoint 2010 Installation wizard, click the "Install SharePoint Server" link. The launched wizard requires the product key.

Then, accept the terms of the licence agreement.

Choose the complete installation

While SharePoint is being installed, notice that a 14 repository is now created where we had the 12 for the 2007 version.

The wpressources repository is created beside the 14.



When the installation of the SharePoint files is finished you are asked to continue with the SharePoint Products Configuration Wizard.

Do not continue with the Wizard but cancel it otherwise you will have an issue due to the current installation described in this post.
In the SharePoint 2010 version, you are not allowed as before to mount a Farm installation on a single machine using local accounts.
If you had continued with the wizard you would have been stopped in the configuration by the following issue:

the specified user Administrator is a local account. Local accounts should only be used in stand alone mode.

Fortunately there is a workaround to succeed in obtaining a Farm environment using local accounts as we used to have in the previous version that I have found in this post:

Single Server Complete Install of SharePoint 2010 using local accounts

 

8.3 Using SharePoint 2010 Management Shell to create the SharePoint 2010 Configuration databases

Open the SharePoint 2010 Management Shell.

Type the following command

New-SPConfigurationDatabase

run the command by pressing the Carriage Return Key

The Shell willl ask you for:
The database name --> choose any name, for example SharePoint_Config
The database Server name --> type the name of your Virtual Machine in my case VMDEV-007

You will be then prompt for the system account credential. In our case to go fast and not start explaining the "least privileges administration policy" just type the administrator login and password the which you are logged with.

Then you are asked for a passphrase. You can use P@ssw0rd that matches the security policies required.



8.4 Running the SharePoint Products Configuration Wizard

This time you can open the SharePoint Products Configuration Wizard.

Let the option "Do not disconnect from this server farm" checked.

Then you will be prompted to chose the Central Administration Site port number. I personally always use 55555 for the configuration of all my development environments in order to type the same Url on all my Virtual Machines.

Let the default NTLM value for the "Authentication provider", Kerberos requires network configuration we cannot perform in the current environment anyway.

The wizard, then, summarize your choices.

Then the 9 main configuration operations are performed.

Finally, the "configuration Successful" dialog summarizes your configuration again and informs you that the central Administration of SharePoint 2010 will be launched when you close it.

When you click "Finish" to close the wizard, the Central Administration Site is opening, and you are prompted for credentials

Then you are asked to sign up to User Experience Improvement Program.

Another page let you choose between configuring your farm yourself or by using a wizard.

When this choice is made, you display for the first time the brand new Welcome Page of SharePoint 2010 Central Administration.

9 Creating your first site in Microsoft SharePoint Server for Internet Sites Enterprise 2010

9.1 Creating your first Web Application for SharePoint 2010

On the default page of the SharePoint 2010 Central Administration, click the "Manage Web Application" link in the "Application Management" section

On the "Manage Web Application" page click the "New" menu entry then click "New Web Application"

I have personally chosen to create it on the default IIS web site, and as a personal usage
named it "Web App - 80"
let the Application pool default settings
named the content database "WSS_Content_WebAppp-80"



You are then prompted the changes are processed

and finally that the SharePoint 2010 Web Application is created.

Click "OK" to close the wizard and to be taken back to the Web Application Management Page where you can see the new SharePoint 2010 Web Application.

9.2 Creating your first Site Collection for SharePoint 2010

From the Web Application Management Page click the "Application Management" link in the left menu in order to proceed to the creation of your first SharePoint 2010 Site Collection.

Then, click the "Create site collections" link under the "Site Collections" section. You are taken to the "Create Site Collection" page.
I have personally chosen to create a team site called "SharePoint 2010" team site"



When launching the creation, you are prompted the changes are processed

then prompted on that the site was created successfully.

When clicking on this site link, you can display your first SharePoint 2010 site.

 

Well done !

 

10 Aknowledgments

Thanks to Neil 'The Doc' Hodgkinson for his post solving the local accounts issue. He updated his post yesterday, and you can find a link to a nice article about the SharePoint 2010 installation.

Thanks to Augusto Simoes for his post that makes me save a lot of time

 

Labels: , ,

Saturday, June 13, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Create a Report from an Analysis Services 2008 Database and deploy it in SharePoint 2007

Creating and deploying a Reporting Services 2008 report bound to an SQL Server 2008 Analysis Services Data Source in SharePoint 2007

Introduction

The goal of this tutorial is to show how to use an SQL Server 2008 Analysis Services Database to generate an SQL Server 2008 Report and how to deploy it in SharePoint 2007.
So we are going to use together three of the most famous Microsoft products at the moment:

  • SQL Server Analysis Services 2008
  • SQL Server Reporting Services 2008
  • SharePoint 2007

I have written SharePoint 2007 on purpose since this tutorial is usable both for MOSS 2007 and Windows SharePoint Services 3.0. As we use SQL Server Reporting Services 2008 AND SharePoint 2007, SSRS 2008 has of course been installed in SharePoint Integrated Mode.

Prerequisites

  • You have a complete environment to generate and deploy reports with SQL Server Reporting Services 2008 in SharePoint Integrated Mode, so including SQL Server Reporting Services 2008, SharePoint 2007 and BIDS.
  • You have installed SQL Server Analysis Services 2008 on this environment
  • You have installed SQL Server 2008 Databases Samples Adventure Works

If you miss any of these features you can find within that blog, articles describing the required steps with screen shots and references to MSDN and Technet documentation to install and configure them either in a single or a multiple server environment.
(See previous posts January, February, March 2009. this is the first article of the serie: Integrating Reporting Services 2008 with SharePoint 2007 Step 1 - SQL Server 2008 Installation )

Tutorial overview

The first step of this tutorial is quite long because you have to perform the several operations described in the Technet Analysis Services Tutorial.
Then using the BIDS Report Wizard you will create a Report bound to an SQL Server 2008 Analysis Services datasource.
You will then deploy it in SharePoint 2007 and check the deployment within a SharePoint site.

The required steps are the following:

Step 1 Analysis Services Tutorial
Step 2 Analysis Services Tutorial checking
Step 3 Creating Reporting Services Project
Step 4 Selecting the data Source
Step 5 Designing the Analysis Services Query
Step 6 Passing through next 3 Wizard dialogs
Step 7 Defining  Deployment Locations
Step 8 Closing the Wizard
Step 9 Report changes and preview in BIDS
Step 10 Defining the report Datasource location in BIDS
Step 11 Deploying the report in SharePoint 2007 with BIDS
Step 12 Checking the report deployment in SharePoint 2007

Step 1 Analysis Services Tutorial

Using your environment including the 2008 Databases Samples Adventure Works, do the Technet Analysis Services Tutorial.
You can stop at the end of Step 3 (browsing the Deployed Cube) that is a good initiation to SSAS 2008 and is enough to generate a significant report and deploy it in SharePoint.

Step 2 Analysis Services Tutorial checking


At the end of the step 3 of the tutorial you should have:

The following view in the Analysis Services database.



The following items in the project folder.



The following in BIDS.



Step 3 Creating Reporting Services Project


Open BIDS, in File menu point  "New “, click “Project"
Choose a Report Server Project Wizard and name this AnalysisServicesBasedReport



Step 4 Selecting the data Source


On "Select the Data Source" windows, choose Microsoft SQL Server Analysis Services as the data source type.



Then click the "EDIT" button to display the "Connection Properties" modal dialog.
In the "server name" text box type the name of your database server where your Analysis Services 2008 database is located.
When the complete name is defined, you will see in the "Select or enter a database name" drop down list the name of the  Analysis Services 2008 database corresponding to the Analysis Services Tutorial: "Analysis services Tutorial".
Select this database and optionally test the connection.

Click OK to close the modal dialog and you will see appear your connection string in the corresponding field of the main dialog.

Step 5 Designing the Analysis Services Query


Click "Next" to display the "Design the Query" dialog.



Click the "Query Builder..." button to open the Query Builder.
Notice that you are now within a SQL Analysis Services 2008 environment since you can see a cube with its measures, KPIs and dimensions.

On the Metadata pane expand Customer dimension and drag and drop the Full Name field in the right pane.
Do the same with the "Product name" field of the "Product" dimension.



Then end by drag and dropping the "Sales Amount" item of the "Internet Sales" folder located beyond the Measures node of the "Analysis Services Tutorial" cube.
You will notice that the values will be automatically populated.

We are now going to filter the Data using the Dimensions.
In Customer Dimension expand "Location" folder and drag and drop State-province to the Top Right pane
Then expand the "Filter Expression" drop down list, and check the checkbox for "Oregon".
You will notice that a first filtering operation is automatically performed.

Then in the "Order Date" dimension, expand "Order Date English Month Name", then expand English Month Name and drag and drop "February 2002"  just bellow the "State-province" Filter row. As before, the filtering operation runs automatically and you will see only 6 rows left.

Click OK to close the "Design the Query" dialog.
You are taken back to the "Design the Query" dialog and can see the Query string generated by the Query Builder.


Step 6 Passing through next 3 Wizard dialogs

Then click "Next" three times in order to arrive to the "Choose the Deployment Location" dialog.






Step 7 Defining  Deployment Locations


On the "Choose the Deployment Location" dialog, as we are planning to deploy the report based on the SQL Server 2008 Analysis services database, in a SharePoint 2007 document library, we are in the case of an SQL Server 2008 Report Server running in SharePoint integrated mode and we have to type the following in the two input boxes:

Report server:
The SharePoint Site. Notice that if, as in my screenshot your site is the root web site of a root site collection the URL is the same than the Web Application Url

--> http://yourMachineName:portNumber

Deployment folder:
We have to type the URL of the document library where we plan to deploy the report. For example if your document library root folder name is Adventure Works Reports

--> http://yourMachineName:portNumber/adventure works Reports



Step 8 Closing the Wizard

Then in the last dialog "Completing the Wizard", we can name our report,

and after having clicked "Finish" the usual BIDS environment is opening and we can see the report in design mode.



Step 9 Report changes and preview in BIDS


In design mode we can change the report name and the column names to display friendlier names.

Then we can switch to "Preview" mode to check our modifications.

Step 10 Defining the report Datasource location in BIDS

We have now to deploy the report but before deploying it we have to define the datasource location in SharePoint.
So, open the project properties dialog by right-clicking the project name and clicking properties.

In the opening "AnalysisServicesBasedReport Property Pages" dialog, in the TargetDataSourceFolder, copy and paste the URL present in the TargetReportFolder field.



Step 11 Deploying the report in SharePoint 2007 with BIDS


Then in the BIDS Solution Explorer, right click the project name again and click "Deploy".
In the BIDS Output Pane, you can check the deployment status.

Step 12 Checking the report deployment in SharePoint 2007

You can now open your SharePoint document library to check the presence of your .rdl file.

And finally click the .rdl in order to display the SQL Server Reporting Services 2008 Report based on an SQL Server Analysis Services 2008 Datasource in the RSViewerPage.aspx page within a Sharepoint 2007 site.

Labels: , , ,

Monday, May 25, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Bind a Microsoft ASP .NET Chart Control within a SharePoint web part to a DataSet

Bind a Microsoft ASP .NET Chart Control embedded in an Ajax refreshable SharePoint Web Part to a DataSet obtained from a call to a Web service

Summary

Introduction
1 - Prerequisites
2 - Tutorial Overview
3 - Tutorial
 
1 - Step 1 Creating the Web Service used as a datasource
1.1 Creating the IIS Web Site for the Web Serice
1.2 Compiling the Web Service
1.3 Deploying the Web Service
1.4 Testing the Web Service


2 - Step 2 Binding an ASP .Net Chart Control embedded in a SharePoint Web Part to the Dataset
2.1 Create the web part project
2.2 Deploy WSPBuilder
2.3 Add a Web Reference to the web Service
2.4 Code of the Web Part (without Ajax feature)
2.4 Web Part SharePoint Solution Creation with WSPBuilder
2.5 Web Part SharePoint Solution Deployment
2.5 Web Part testing
2.6 Modify the Code Access Security Policy with WspBuilder
2.7 Adding Ajax feature to the Web Part
2.8 Adding Ajax Timer to the Web Part

Introduction

This tutorial is the following of the last tutorial about ASP .NET Chart Control for SharePoint that I have posted on 2008 December 10, Create a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control, and that was showing how to place an Microsoft ASP .NET Chart Control inside an Microsoft AJAX refreshable web Part. In this previous tutorial, the web part was not bound to any datasource.

In the present tutorial I will show how to bind a Microsoft Asp .net Chart Control embedded in  a SharePoint Web Part to a DataSet. There is many examples of datasource binding in the Samples Environment for Microsoft Asp .Net Chart Controls   but most of them bind the Chart Control to a SQL Datareader.
I will rather show how to bind the control to a DataSet and will use a DataSet coming from a call to a Web Service.

Furthermore, I will still place the chart control inside an update panel in order to improve the user experience.


1 - Prerequisites

  • Usual development environment for SharePoint (Windows 2003 Server or Windows Server 2008 with a SharePoint installation).
  • Microsoft Chart Controls for Microsoft .NET Framework 3.5 are installed on the development environment. You can download installation package here
  • Microsoft Visual Studio 2008 is installed on the development environment.
  • Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008is installed on the development environment.
  • Your SharePoint environment is properly configured for ASP .Net Chart Controls. If you are not sure you can check the configuration in my previous post, sections 3.3 and 3.4, or do the quick tutorial of this previous post in order to validate your environment by displaying the Chart Control Sample on a SharePoint page.
                     
                    Use Microsoft Chart Controls for .NET Framework in a SharePoint web site 
    
  • Your SharePoint environment is properly configured for AJAX. If you are not sure you can check the configuration in my previous post, sections 4.1, or do the quick tutorial of this previous post in order to validate your environment by displaying the Chart Control Sample inside an Ajax refreshable Web Part.
                     
                    Create a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control 
    
  • You have downloaded WSPBuilder Package in order to be able to use WSPBuilder to deploy the Web part.
  • You have a SharePoint team site ready to welcome the Asp .Net Chart control Web part.

2 - Tutorial Overview

In this tutorial, first, we are going to develop a Web Service that will provide a datasource for that web part.
Then we will develop a web part that will embed an ASP .Net Chart Control an display a trend based on the data coming from the call to the Web Service.
We will for this web part use the minimal configuration to respect the best practices:
  • we will place the web part dll in the bin directory of the SharePoint Application,
  • we will use WspBuilder to deploy the web part and modify the Code Access Security of our web application in order the web part code will be authorized to run.

There is anyway an exception I will use in a matter of demonstration.
I WILL NOT sign the web part dll with a strong name to show that, if you deploy a web part dll in the bin directory , there is no real need to sign it with a strong name, except to prevent unauthorized versions of the Web Part in the future. As mentioned in the MSDN documentation:

Deploying Web Parts in Windows SharePoint Services

[...]

Strong Naming a Web Part Assembly

Strong naming uses a private key to digitally sign an assembly. Strong naming also stamps the assembly with a public key to validate the signature. This technique guards against unauthorized versions of a Web Part. If the public key fails to validate the digital signature, Windows SharePoint Services will refuse to run the module.

When deploying a Web Part to the bin, the recommend practice is to strong name the assembly. When deploying a Web Part to the Global Assembly Cache, the assembly must have a strong name. An assembly without a strong name is not recommended in Windows SharePoint Services.

[...]

Furthermore, since we are not creating signed code, we do not need to tell our assembly to allow partially trusted code calls, so we do not need to use the AllowPartiallyTrustedCallers attribute

I will perform these different operations of configuration when required by a SharePoint or an ASP .Net exception so as we can examine what a specific configuration is for. Furthermore, as we cannot anticipate certain exceptions like Code Access Security exceptions, waiting for exceptions before configuring a SharePoint element is often the usual way of programming for SharePoint. 

Last, we will place the ASP .NET Chart Control of the Web Part in an Update Panel in order to improve user experience.

This tutorial includes the following steps:

  • Step 1: Creating the IIS Web Site for the Web Service
  • Step 2: Compiling the Web Service
  • Step 3: Deploying the Web Service
  • Step 4: Testing the Web Service
  • Step 5: Create the web part project
  • Step 6: Deploy WSPBuilder
  • Step 7: Add a Web Reference to the web Service
  • Step 8: Copy the Code of the Web Part (without Ajax feature)
  • Step 9: Web Part SharePoint Solution Creation with WSPBuilder
  • Step 10: Web Part SharePoint Solution Deployment
  • Step 11: Web Part testing
  • Step 12: Modify the Code Access Security Policy with WspBuilder
  • Step 13: Adding Ajax feature to the Web Part
  • Step 14: Adding Ajax Timer to the Web Part

3 - Tutorial

 

1 - Step 1 Creating the Web Service used as a datasource

1.1 Creating the IIS Web Site for the Web Service

Open IIS manager then right click on the Web Sites node then point to "New", click "Web Site".



On the opening dialog of the Web Site Creation Wizard click "Next".



In the web Site Description dialog, type "Web Service Test Charting  - 201"



In "IP Address and Port Settings" dialog for the IP Address type 201 in the input box "TCP port this Web site should use".



In "Web Site Home Directory" dialog click "Browse", then create a new folder under the Inetpub\wwwroot directory and name it "Web service Test Charting - 201".



In "Web Site Access Permissions" dialog click check "Run scripts" and "Execute".



As specified in the last dialog, you have successfully completed the Web Site creation.



1.2 Compiling the Web Service


Open Visual Studio.
Create a New web service project in file mode and C# named WebServiceTestCharting.




In the Service1.asmx.cs file, copy the following code:

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml.Linq;

using System.Timers;

using System.Diagnostics;

 

namespace WebServiceTestCharting

{

    /// <summary>

    /// Summary description for Service1

    /// </summary>

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    [ToolboxItem(false)]

    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.

    // [System.Web.Script.Services.ScriptService]

    public class Service1 : System.Web.Services.WebService

    {

        static Timer timer1 = new Timer();

        DataSet myDataSet;

        DataTable myDatatable;

        static System.Collections.Generic.SortedList<DateTime, double> myValues = new System.Collections.Generic.SortedList<DateTime, double>();

 

        static Service1()

        {

            if (timer1.Enabled == false)

            {

                Debug.WriteLine("contructor ");

 

                timer1.Elapsed += new ElapsedEventHandler(OnElapsedTime);

                timer1.Interval = 1000;

 

                timer1.Enabled = true;

            }

        }

 

        static protected void OnElapsedTime(object sender, EventArgs e)

        {

            DateTime now = DateTime.Now;

            Debug.WriteLine(now);

 

            myValues.Add(now, Math.Sin((double)DateTime.Now.Second));

        }

 

        [WebMethod]

        public DataSet Sinusoid()

        {

            myDataSet = new DataSet();

            myDatatable = new DataTable("myTable");

 

            DataColumn myDataColumnTime = new DataColumn("Time", System.Type.GetType("System.DateTime"));

            DataColumn myDataColumnValue = new DataColumn("Value", System.Type.GetType("System.Double"));

 

            myDatatable.Columns.Add(myDataColumnTime);

            myDatatable.Columns.Add(myDataColumnValue);

            myDataSet.Tables.Add(myDatatable);

 

            for (int i = 0; i < myValues.Keys.Count; i++)

            {

                myDataSet.Tables["myTable"].Rows.Add();

                myDataSet.Tables["myTable"].Rows[i][0] = myValues.Keys[i];

                myDataSet.Tables["myTable"].Rows[i][1] = myValues[myValues.Keys[i]];

            }

 

            Debug.WriteLine("number of rows in DataTable :  " + myDataSet.Tables["myTable"].Rows.Count);

            return myDataSet;

        }

    }

}

Then build the project.

1.3 Deploying the Web Service


Right click the Project node in Visual Studio and click "Open Folder in Window Explorer".
Then copy the following elements and paste them in the previously created folder of the IIS Web Site (C:\Inetpub\wwwroot\Web Service Test Charting - 201)

  • web.config
  • bin folder
  • Service1.asmx
  • Service1asmx.cs


1.4 Testing the Web Service


Then go back to IIS, locate the web service IIS web site and display in the right pane the web service files.
Right click the Service1.asmx file picture and click "Browse".



The opening page shows the supported operation and you notice the presence of the web method: Sinusoid.



Click the Sinusoid link in order to display the Web Method page.



On this page click "Invoke" button. The opening page displays the xml view of the DataSet. Notice that no rows are present yet.



Close the page and click invoke a second time As the timer has started, the dataset contains now several rows.



If you are using debug view, as I have put Debug trace instruction in the code you should obtain this:




2 - Step 2 Binding an ASP .Net Chart Control embedded in a SharePoint Web Part to the Dataset

2.1 Create the web part project

In Visual Studio, create a new class library project and name it BindableChartWebParts.



Rename the Class1.cs in MsChartingWebPart

Add the following references to the project:

System.Drawing;
System.Web;
Microsoft.SharePoint
System.web.DataVisualisation




2.2 Deploy WSPBuilder

In Visual Studio, in the Solution Explorer, right click the project node and click "Open Folder in Window Explorer".
Then create a new folder named "WSPBuilder".



In the folder create a "80" folder and in this folder, create a "bin" folder.




Then in the WSPBuilder folder place the following elements of the WSPBuilder package downloaded on CodePlex:

CabLib.dll
WSPBuilder.exe
WSPBuilder.exe.config



Then go back to Visual Studio, right click your project node in the Solution Explorer and click "Properties".
In the project properties  pane click the "Build" left menu entry.
Then using the "browse" button change the output path so as it point to the WSPBuilder bin folder.



2.3 Add a Web Reference to the web Service

In the Visual Studio Explorer, right click the "References" node and choose add a service reference.



In the "Add Service Reference" dialog, click "Advanced" button.



In the "Service Reference Settings" dialog click the "Add web reference" button.
In the "Add Web Reference" dialog, in the URL input box type the previously created Web Service URL:
http://localhost:201/Service1.asmx (if you are working on the server) then click go.

The wizard connects to the web service and display the supported operation page.

In the "Web reference name" input box, type "WebServiceTestCharting201"
Then click the "Add Reference" Button




You can check the new Web Reference in the Visual Studio Solution Explorer.



2.4 Code of the Web Part (without Ajax feature)

Copy the following code inside the MsChartingWebPart.cs file.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using System.Drawing;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using Microsoft.SharePoint.WebPartPages;

using System.Web.UI.DataVisualization.Charting;

using System.Data;

using System.Diagnostics;

 

namespace BindableChartWebParts

{

    [ToolboxData("<{0}:MsChartingWP runat=server></{0}:MsChartingWP>")]

    public class MsChartingWebPart : WebPart

    {

        System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();

 

        protected override void OnInit(EventArgs e)

        {

            base.OnInit(e);

        }

 

        protected override void CreateChildControls()

        {

            //to change the style of the chart and add a title

 

            Chart1.ChartAreas.Add("datedLabel");

            Chart1.Series.Add("Series 1");

 

            Chart1.Series["Series 1"].ChartType = SeriesChartType.Spline;

            //to change the style of the line

            //Chart1.Series["Series 1"].MarkerStyle = MarkerStyle.Diamond;

            //Chart1.Series["Series 1"].MarkerSize = 7;

            //Chart1.Series["Series 1"].MarkerColor = Color.White;

            //Chart1.Series["Series 1"].MarkerBorderColor = Color.Black;

 

            Chart1.ChartAreas["datedLabel"].AxisX.IsLabelAutoFit = true;

            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Angle = 30;

            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.IsEndLabelVisible = true;

 

            string strTimeFormat = "hh:mm:ss";

            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Format = strTimeFormat;

 

 

 

            WebServiceTestCharting201.Service1 myService = new BindableChartWebParts.WebServiceTestCharting201.Service1();

 

            System.Data.DataSet myDs = myService.Sinusoid();

 

            string str30secBefore = DateTime.Now.AddSeconds(-30).ToString();

            string expression = "Time > '" + str30secBefore + "'";

 

            DataView myFilteredView = new DataView(myDs.Tables[0], expression, "", DataViewRowState.CurrentRows);

 

            Chart1.Series["Series 1"].Points.DataBindXY(myFilteredView, "Time", myFilteredView, "Value");

 

            Chart1.Width = 412;

            Chart1.Height = 296;

 

            this.Controls.Add(Chart1);

        }

    }

}

 

Then build the project

2.4 Web Part SharePoint Solution Creation with WSPBuilder

Go back to the WspBuilder folder. Double click the WspBuilder.exe.
Notice that a command prompt is opening , that a .wsp file is created and also a solutionId.txt file.
We are going to write a little .bat file to make the WspBuilder.exe command prompt stay open, and to give build instructions to the WspBuilder.exe.

Create a text file and rename it to genWsp.bat.
Right click the file and choose Edit.
Inside this file type the following:

wspbuilder.exe -WSPname BindableChartWebParts.wsp
pause


Then double click the .bat file and notice that the command prompt stays open and allows you to check if the build was successful.



Notice also that the new generated .wsp file has now a friendlier name.


2.5 Web Part SharePoint Solution Deployment


Open a command prompt, and if you have added the path of the SharePoint stsadm tool (C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN) in the environment variables type the following in the command prompt. (take care to use an account that is both Administrator of the Server and belongs to the SharePoint Farm Administrators).

Stsadm -o addsolution -filename

Then drag and drop the previously built .wsp file in the command prompt.



then type Enter. The stsadm tool adds your .wsp file to the SharePoint Farm Solution store.



Open the SharePoint Central Administration Console.
Click the Tab Operations
Then in the Global Configuration Section click the link Solutions Management

In the Solution Management page locate the bindablechartwebpartsolution.wsp solution and click on it.
On the Solution Properties page click Deploy solution
In the Deploy Solution page, choose the Web Application where you want to use the web part, then click OK.



Open your web application web.config file, and notice that the deployment using a wsp allows adding automatically an entry in the web.config file of a web application. In our case:

      <SafeControl Assembly="BindableChartWebParts" Namespace="BindableChartWebParts" TypeName="*" Safe="True" />

As specified previously in this post, I have decided not to compile the web part .dll with a strong name on purpose. It is to show that a dll deployed in the bin directory of a web application does not need a strong name.

2.5 Web Part testing

Because there is an entry for our web part in the safecontrols section of the web.config of a SharePoint Web Application, the site collections of this web application will be allowed to populate their web part galleries with the web part.
Choose a site collection of the web application where you deployed the solution, open its site settings page, in the Galleries section locate the Web parts and click the link.
The web part gallery is opening.





Click New.
In the Web Part Gallery: New Web Parts page locate the BindableChartWebParts.MsChartingWebPart and check its checkbox, then click the populate Gallery button



Then go to a web part page of a site within the site collection and add the web part to the page.







Then, don't panic, you have a security exception, and it is perfectly normal.
Your web part was deployed to the bin directory of a web application and the web.config file of this web application has its trust level set to WSS_Minimal so the web part code has the minimal privileges to run.
This exception is a common ASP .Net exception that prevents an Asp .Net application from calling an Url outside its domain. We had this exception thrown because of the call to the web service.
Of course to prevent this exception I could have put the Sinusoid web service with the other SharePoint web services in the SharePoint _vti_bin (as I did in that post Integrate ASP.NET Web Service based AJAX with MOSS 2007 or Windows SharePoint Services 3.0 ), but I did not do it on purpose to illustrate the Code Access Security exception fixing with WspBuilder.

2.6 Modify the Code Access Security Policy with WspBuilder

To fix this issue we are going to redeploy the web part and before redeploying, place in the manifest .xml of the .wsp a new instruction for adding security permissions.
WspBuilder allows us to do it in a very friendly way.

In the wspbuilder folder, create a new .txt file and name it "WspBuilder_CAS.txt".
Inside this file write the following:

<IPermission class="System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" >
</IPermission>

That will authorize the requests to outside locations for the web application. (there is a way to authorize only one or several locations by typing Url's, but to stay simple for this tutorial, I will authorize all the locations).

Then reopen the genWsp.bat and add the following instruction:

-CustomCAS WspBuilder_CAS.txt

so as the entire content of the .bat be the following:

wspbuilder.exe -WSPname BindableChartWebParts.wsp -CustomCAS WspBuilder_CAS.txt
pause


Double click the modified .bat file to regenerate a new .wsp solution file with the new Code Access Security instructions within its manifest.xml file.

Then we just have to upgrade the solution by typing this instruction in a command prompt:

stsadm -o upgradesolution -name BindableChartWebparts.wsp  -filename C:\Dev\BindableChartWebPart\WSPBuilder\BindableChartWebParts.wsp -immediate -allowcasPolicies



The solution upgrade triggers a recycling of the web application pool that leads to the usual time to wait the page refreshing, and when it's done the web part is displaying the sinusoid trend.



Exit edit mode.
Refresh the page and notice that the time value has changed and the web part is calling the web service each time we refresh the page.





It would be nice to refresh only the web part wouldn't be? That is we will do in the next part of this post by placing the Chart Control and a refresh button inside an update panel control...

It is what I have done in a previous post (Create a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control), so if you check it you can perform the second part of this tutorial before I have finished to write it...

2009 June 10th.
...Back to write the end of the post.
We are going to make the Web Part to be refreshable without showing a visible Post Back of the Web Part Page, by embedding the Web Part Children Controls within an Update Panel.
Finally, we are going to use an Ajax Timer for automating the refresh of the web Part.

2.7 Adding Ajax feature to the Web Part

- Prerequisites:

First, we have to add a reference to the System.Web.Extensions in the Web Part project to be able to take benefits of Microsoft Ajax Features.




Then we have to modify the Web Part code doing the following operations:

  • Declare and instantiate the UpdatePanel without forgetting to give it an ID.
  • Set the UpdateMode of the Update panel to conditional because we are going to refresh the Update panel by calling its Update method and the call to this method requires the conditional mode.
  • Declare, instantiate and configure a Link Button to refresh the Web part, add an Event Handler to the Link Button click.
  • Make the chart Control and the Link Button to be children controls of the Update Panel ContentTemplateContainer.
  • In the method referred by the Link Button Event Handler, place the Update Panel Update() method.

Here is the Web Part code after having performed these different code modifications.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
using System.Data;
using System.Diagnostics;
 
 
namespace BindableChartWebParts
{
    [ToolboxData("<{0}:MsChartingWP runat=server></{0}:MsChartingWP>")]
    public class MsChartingWebPart : WebPart
    {
        System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();
 
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
        }
 
        //UpdatePanel declaration
        UpdatePanel updatepanel1;
        protected override void CreateChildControls()
        {
            //UpdatePanel instantiation, and identification
            updatepanel1 = new UpdatePanel();
            updatepanel1.ID = "updplAjaxRefreshableChartControlWebPart";
            updatepanel1.UpdateMode = UpdatePanelUpdateMode.Conditional;
 
            //LinkButton declaration, instantiation, and configuration
            LinkButton lbtnRefresh = new LinkButton();
            lbtnRefresh.ID = "lbtnWebPartRefresh";
            lbtnRefresh.Text = "Refresh";
            lbtnRefresh.Click += new EventHandler(lbtnRefresh_Click);
 
            Chart1.ChartAreas.Add("datedLabel");
            Chart1.Series.Add("Series 1");
 
            Chart1.Series["Series 1"].ChartType = SeriesChartType.Spline;
            //to change the style of the line
            //Chart1.Series["Series 1"].ChartType = SeriesChartType.Line;
            //Chart1.Series["Series 1"].MarkerStyle = MarkerStyle.Diamond;
            //Chart1.Series["Series 1"].MarkerSize = 7;
            //Chart1.Series["Series 1"].MarkerColor = Color.White;
            //Chart1.Series["Series 1"].MarkerBorderColor = Color.Black;
 
            Chart1.ChartAreas["datedLabel"].AxisX.IsLabelAutoFit = true;
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Angle = 30;
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.IsEndLabelVisible = true;
 
            string strTimeFormat = "hh:mm:ss";
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Format = strTimeFormat;
 
 
 
            WebServiceTestCharting201.Service1 myService = new BindableChartWebParts.WebServiceTestCharting201.Service1();
 
            System.Data.DataSet myDs = myService.Sinusoid();
 
            string str30secBefore = DateTime.Now.AddSeconds(-30).ToString();
            string expression = "Time > '" + str30secBefore + "'";
 
            DataView myFilteredView = new DataView(myDs.Tables[0], expression, "", DataViewRowState.CurrentRows);
 
            Chart1.Series["Series 1"].Points.DataBindXY(myFilteredView, "Time", myFilteredView, "Value");
 
            Chart1.Width = 412;
            Chart1.Height = 296;
 
            updatepanel1.ContentTemplateContainer.Controls.Add(Chart1);
            updatepanel1.ContentTemplateContainer.Controls.Add(lbtnRefresh);
 
            this.Controls.Add(updatepanel1);
        }
 
        void lbtnRefresh_Click(object sender, EventArgs e)
        {
            updatepanel1.Update();
        }
    }
}
 

Then we have to build and deploy the new version of the web part as we did before by using a .wsp, but before being allowed to use this new version of the Web Part we have to add a ScriptManager to the Web Part Page that will welcome the Web Part.
In a previous post (Create a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control), I have added the ScriptManager to the Web Part Page, but for this one, I will add a ScriptManager to the Master Page of the Site Collection, that will allow all the Site Content Pages to manage one or several Update Panels without thinking each time not to forget to add a ScriptManager to the Page.
Regarding the option to add a ScriptManager to the Page by placing the instruction within the Web Part code, I have seen a lot of example of this option on SharePoint blogs, but I do not advice to do it that way, since it seems to only work randomly. You can also refer to Mike Ammerlaan's Blog. The best explanation of the random nature of success using this approach is in this post:

Adding a ScriptManager to your Page Programmatically through a Web Part

But there is also people that seem to feel confident with it, so..

Best practices and common errors when adding a ScriptManager programmatically from a WebPart
Integrating ASP.NET Ajax WebPart with SharePoint 3.0

Last, you can also find several other options here:

Add ScriptManager to Page Programmatically?

As I use a Site Collection based on a native SharePoint Site Definition the Site Collection Master Page is the default.master and is located in the Global folder under the 12 hive.



I will add the ScriptManager to this Master Page only for this post, but if I had to do it in a real SharePoint project, I would have used a custom Master Page deployed with a SharePoint Feature instead.

So, open the default.master with Visual Studio, then drag and drop a ScriptManager control just under the WebPartManager of the Master Page.



Refresh the page.
The LinkButton Refresh appears, and if you click it, the web part will be refreshed and you will see the sinusoid curve changes.





In the next step, we are going to use an Ajax Timer for automating the refresh of the web Part.

2.8 Adding Ajax Timer to the Web Part

So we have to modify the Web Part code again and perform the following operations:

  • Adding an Ajax timer to the Web part.(You will find it in the AJAX Extension Section of the Visual Studio Toolbox - You can check the previous screenshot where I did the drag and drop of the ScriptManager)
  • Adding an EventHandler to the timer Tick.
  • Making the Ajax timer to be child controls of the Update Panel ContentTemplateContainer.
  • In the method referred by the Event Handler added to the timer Tick, placing the Update Panel Update() method.

We will use the previous refresh button to start the timer.

  • Renaming all the references to "refresh" for the Link Button to "Start Timer"
  • In the method referred by the Link Button Event Handler, place the instruction to set the Timer interval to 1 second so as to start the Timer when the Link Button is clicked.

Here is the Web Part code after having performed these different code modifications.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
using System.Data;
using System.Diagnostics;
 
 
namespace BindableChartWebParts
{
    [ToolboxData("<{0}:MsChartingWP runat=server></{0}:MsChartingWP>")]
    public class MsChartingWebPart : WebPart
    {
        System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();
 
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
        }
 
        //UpdatePanel declaration
        UpdatePanel updatepanel1;
        Timer timRefresh;
        protected override void CreateChildControls()
        {
            //UpdatePanel instantiation, and identification
            updatepanel1 = new UpdatePanel();
            updatepanel1.ID = "updplAjaxRefreshableChartControlWebPart";
            updatepanel1.UpdateMode = UpdatePanelUpdateMode.Conditional;
 
            //LinkButton declaration, instantiation, and configuration
            LinkButton lbtnStartTimer = new LinkButton();
            lbtnStartTimer.ID = "lbtnWebPartStartTimer";
            lbtnStartTimer.Text = "Start Timer";
            lbtnStartTimer.Click += new EventHandler(lbtnStartTimer_Click);
 
            //Ajax Timer instantiation, and identification
            timRefresh = new Timer();
            timRefresh.ID = "timWebPartRefresh";
            timRefresh.Tick += new EventHandler<EventArgs>(timRefresh_Tick);
 
 
            Chart1.ChartAreas.Add("datedLabel");
            Chart1.Series.Add("Series 1");
 
            Chart1.Series["Series 1"].ChartType = SeriesChartType.Spline;
            //to change the style of the line
            //Chart1.Series["Series 1"].ChartType = SeriesChartType.Line;
            //Chart1.Series["Series 1"].MarkerStyle = MarkerStyle.Diamond;
            //Chart1.Series["Series 1"].MarkerSize = 7;
            //Chart1.Series["Series 1"].MarkerColor = Color.White;
            //Chart1.Series["Series 1"].MarkerBorderColor = Color.Black;
 
            Chart1.ChartAreas["datedLabel"].AxisX.IsLabelAutoFit = true;
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Angle = 30;
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.IsEndLabelVisible = true;
 
            string strTimeFormat = "hh:mm:ss";
            Chart1.ChartAreas["datedLabel"].AxisX.LabelStyle.Format = strTimeFormat;
 
 
 
            WebServiceTestCharting201.Service1 myService = new BindableChartWebParts.WebServiceTestCharting201.Service1();
 
            System.Data.DataSet myDs = myService.Sinusoid();
 
            string str30secBefore = DateTime.Now.AddSeconds(-30).ToString();
            string expression = "Time > '" + str30secBefore + "'";
 
            DataView myFilteredView = new DataView(myDs.Tables[0], expression, "", DataViewRowState.CurrentRows);
 
            Chart1.Series["Series 1"].Points.DataBindXY(myFilteredView, "Time", myFilteredView, "Value");
 
            Chart1.Width = 412;
            Chart1.Height = 296;
 
            updatepanel1.ContentTemplateContainer.Controls.Add(Chart1);
            updatepanel1.ContentTemplateContainer.Controls.Add(lbtnStartTimer);
            updatepanel1.ContentTemplateContainer.Controls.Add(timRefresh);
 
            this.Controls.Add(updatepanel1);
        }
 
        void timRefresh_Tick(object sender, EventArgs e)
        {
            updatepanel1.Update();
        }
 
        void lbtnStartTimer_Click(object sender, EventArgs e)
        {
            timRefresh.Interval = 1000;
        }
    }
}
 

So, now, when we click the Start Timer Link Button, the Web Part is refreshing automatically each second.





Labels: , , , , ,

Thursday, May 14, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Enumerate Role Assignments to retrieve Groups and Users Permissions - Generating a complete report

Introduction:

The following SharePoint Application Page with C# in line code enumerates all the roles assignments of a Windows SharePoint Services 3.0 or MOSS site collection and displays for each web site:
  • The role member and reports if it is a Group or an User.
  • If it is a group, displays the number of users in the Group and the users list.
  • If it is a group, displays the permissions for all significant Site Collection elements (if inheritance was broken for a List, a Folder or an Item, this will be specified). It is information at a cross-site level.
  • In any case (User or group), displays the Roles list for the current web site.
  • In any case (User or group), displays for each previous roles, the Roles Permissions list.
This post and its code sample is an improvement of the previous post Enumerate Role Assignments to retrieve Groups and Users Permissions in a Windows SharePoint Services 3.0 or MOSS Site . I also did this new post to help a reader that has asked me information about SharePoint Roles and Permissions reporting.
Why to use it?

In Windows SharePoint Services 3.0, access to Web sites, lists, folders, and list items is controlled through a role-based membership system by which users are assigned to roles that authorize their access to Windows SharePoint Services objects.

To give a user access to an object, you can do so either by adding the user to a group that already has permissions on the object, or by creating a role assignment object, setting the user for the role assignment, optionally binding the role assignment to the appropriate role definition with base permissions, and then adding the assignment to the collection of role assignments for the list item, folder, list, or Web site. If you do not bind the role assignment to a role definition when assigning a user to a role, the user has no permission.

As there is two ways of granting permissions to a specific user, this can easily lead to a lack of organization regarding Security Granting Policy, and you may have some SharePoint sites to clean up.

When you want to check the users and the groups present in a Site Collection web sites and their role, it can take time doing it by browsing "People and Group" administration pages for each web site. It would be nice to display all the information in a single report. The following code sample will give you this kind of report, and it will be easier for you to reorder Users and Groups using it.

How to use it?

Copy the following code in an .aspx file.
Paste the file in the LAYOUTS directory.
"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"

Browse the page with site administrator permissions from any site using the usual Application Page url (If you have named the aspx page enumerateroles.aspx access it via url ...myWebSite/_layouts/enumerateroles.aspx).
Check Report in the page.

Code of the Role Assignments Report Application Page:

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" %>
 
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Utilities" %>
<%@ Import Namespace="System.Security.Permissions" %>
<%@ Import Namespace="Microsoft.SharePoint.Security" %>
<%@ Import Namespace="System.Diagnostics" %>
<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <asp:Label ID="lblOutPut" runat="server" />
    <asp:Panel ID="pnlHidden" runat="server" />
 
    <script type="text/javascript" language="JavaScript">
 
        document.getElementById('<%=pnlHidden.ClientID %>').style.display = 'none';
 
        function Toggle(node) {
            // Unfold the branch if it isn't visible
            if (node.nextSibling.style.display == 'none') {
                // Change the image (if there is an image)
                if (node.children.length > 0) {
                    if (node.children.item(0).tagName == "IMG") {
                        node.children.item(0).src = "/_layouts/IMAGES/collapseminus.gif";
                    }
                }
                node.nextSibling.style.display = '';
            }
            // Collapse the branch if it IS visible
            else {
                // Change the image (if there is an image)
                if (node.children.length > 0) {
                    if (node.children.item(0).tagName == "IMG") {
                        node.children.item(0).src = "/_layouts/IMAGES/collapseplus.gif";
                    }
                }
                node.nextSibling.style.display = 'none';
            }
        }
    </script>
</asp:Content>
 
<script runat="server">       
 
    string htmlOutput = "";
 
    protected string WriteIsRootWeb(SPWeb aWeb)
    {
        if (aWeb.IsRootWeb)
        {
            return " (This is the Site Collection Root Web)";
        }
        else
        {
            return "";
        }
    }
 
 
    [SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        using (SPSite mySite = SPContext.Current.Site)
        {
            string siteUrl = mySite.Url;
            this.Page.ClientScript.RegisterClientScriptBlock(base.GetType(), "GroupPermissionCallback", "\r\nfunction WebForm_DoCallback(controlId,url,GroupPermissionCallback,ctx,unknownNullValue,unknownBooleanvalue)\r\n{\r\n    var strUrl ='" + siteUrl + "/'+ url;\r\n    open(strUrl, '_blank');\r\n}\r\n\r\n", true);
        }
    }
 
    public override void VerifyRenderingInServerForm(Control aControl){}
 
    protected override void Render(HtmlTextWriter writer)
    {
        bool isAgroup = true;
        SPGroup aGroup = null;
 
        foreach (SPWeb aWeb in SPContext.Current.Site.AllWebs)
        {
            htmlOutput += "\n<br>******************************************";
            htmlOutput += "\n<br><span style='color:blue'>Roles Assignments Report on web site " + aWeb.Title + WriteIsRootWeb(aWeb) + "</span>";
            htmlOutput += "\n<br>******************************************<br>";
 
            htmlOutput += "\n<br><div style='padding-left:40px'>List of " + aWeb.Title + " Groups";
 
            foreach (SPGroup Group in aWeb.Groups)
            {
                htmlOutput += "\n<br>" + Group.Name + " ID: " + Group.ID;
            }
 
            htmlOutput += "\n</div>";
            htmlOutput += "\n<div style='padding-left:20px'>";
            foreach (SPRoleAssignment aRole in aWeb.RoleAssignments)
            {
                isAgroup = true;
                htmlOutput += "\n<br>*************<br>";
                try
                {
                    aGroup = aWeb.Groups.GetByID(aRole.Member.ID);
                }
                catch
                {
                    isAgroup = false;
                }
 
                if (isAgroup)
                {
                    htmlOutput += "\n<br><span style='color:#357EC7'>Group Id : " + aRole.Member.ID.ToString() + " | " + " Principal Name : " + aRole.Member.Name + "</span>";
 
                    int numberOfusers = aWeb.Groups.GetByID(aRole.Member.ID).Users.Count;
                    htmlOutput += "\n<br><br>Number of users:" + numberOfusers;
                    aGroup = aWeb.Groups.GetByID(aRole.Member.ID);
                    htmlOutput += "\n<br>";
                    if (numberOfusers > 0)
                    {
                        htmlOutput += "\n<br>List of " + aGroup.Name + " users";
 
                        foreach (SPUser aUser in aGroup.Users)
                        {
                            htmlOutput += "\n<br> - " + aUser.Name;
                        }
                    }
 
                    GroupPermissions myGroupPerm = new GroupPermissions();
                    myGroupPerm.GroupId = aRole.Member.ID;
 
                    System.IO.StringWriter myStrWriter = new System.IO.StringWriter();
                    HtmlTextWriter myWriter = new HtmlTextWriter(myStrWriter);
 
                    pnlHidden.Controls.Add(myGroupPerm);
 
                    myGroupPerm.GroupId = aRole.Member.ID;
                    myGroupPerm.RenderControl(myWriter);
 
                    htmlOutput += "<br><br><a onClick='Toggle(this)'><IMG style='text-decoration:none;border:0px' SRC='/_layouts/IMAGES/collapseplus.gif' /><span style='cursor:hand'>All (cross-sites) Permissions for " + aRole.Member.Name + "</span></a><div style='width:98%;display:none;'>" + myStrWriter.ToString() + "</div>";
                    htmlOutput += "\n";
                }
                else
                {
                    htmlOutput += "\n<br><span style='color:#3BB9FF'>User Id : " + aRole.Member.ID.ToString() + " | " + " Principal Name : " + aRole.Member.Name + "</span>";
                }
                htmlOutput += "\n<br><br>role(s) for " + aRole.Member.Name + " in " + aWeb.Title + ": <br>";
                foreach (SPRoleDefinition aRoleDefBinding in aRole.RoleDefinitionBindings)
                {
                    htmlOutput += "\n<br> - " + aRoleDefBinding.Name + "   (" + aRoleDefBinding.Description + ")";
                    htmlOutput += "\n<div style='padding-left:10px;'>List of permissions for " + aRoleDefBinding.Name + ":";
                    htmlOutput += "\n<br>" + aRoleDefBinding.BasePermissions.ToString();
                    //htmlOutput += "\n\n" + aRole.RoleDefinitionBindings.Xml + "\n\n";//to see the xml from View Source of the page
                    htmlOutput += "\n</div>";
                }
 
                htmlOutput += "\n<br>";
            }
            htmlOutput += "\n</div><br>";
        }
 
        htmlOutput += "\n<br>*************<br>";
 
        lblOutPut.Text = htmlOutput;
 
        base.Render(writer);
    }
</script>
 


Labels: ,

Monday, April 20, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Populate an ASP .Net Treeview from a SQL self-join table

I had last week an ASP .net TreeView control to fill from a self-join table. I looked on the Internet to find an Algorithm but I did not find any solution using C# or VB .Net but a solution in Code Project using SQL or other using DataSets. I then decided to post the following Algorithm that might help somebody else.
Here is the table I used in the example and the generated treeview image on the right.


Location.ID Location.Name Location.ParentID
1 Americas 0
2 Europe 0
3 Asia 0
4 Northern America 1
5 Western Europe 2
6 Western Asia 3
7 Eastern Asia 3
8 South-Eastern Asia 3
9 Northern Europe 2
10 Southern Europe 2
11 Canada 4
12 United States 4
13 Netherlands 9
14 France 9
15 Israel 5
16 Japan 6
17 Spain 10
18 United Kingdom 9
19 Vietnam 8
20 Quebec 11
21 California 12
22 District of Columbia 12
23 England 18
24 Hefa 15
25 Midi Pyrenees 14
26 Nara 16
27 New Jersey 12
28 Noord-Brabant 13
29 Ontario 11
30 Santa Cruz De Tenerife 17

 

Here is the code I used to generate the treeview:

<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Page Language="C#" %>

 

<%@ Import Namespace="System.Data.SqlClient" %>

<%@ Import Namespace="Microsoft.SharePoint" %>

<%@ Import Namespace="System.Collections.Generic" %>

<form runat="server">

<asp:treeview runat="server" id="TreeView1" />

</form>

 

<script runat="server">

   

    public class Location

    {

        private string _locationName;

        private int _locationId;

        private int _parentLocationId;

 

        public string LocationName

        {

            get { return _locationName; }

            set { _locationName = value; }

        }

 

        public int LocationId

        {

            get { return _locationId; }

            set { _locationId = value; }

        }

 

        public int ParentLocationId

        {

            get { return _parentLocationId; }

            set { _parentLocationId = value; }

        }

    }

        //list of all nodes

        SortedList<int, Location> myLocations = new SortedList<int, Location>();

        //list of all created nodes

        SortedList<int, TreeNode> myCreatedNodes = new SortedList<int, TreeNode>();

 

    public void Page_Load(object sender, EventArgs e)

    {

        string result="<br>start loading  page : " + DateTime.Now.Second + " " + DateTime.Now.Millisecond;

        try

        {

            System.Data.SqlClient.SqlConnection myCon = new System.Data.SqlClient.SqlConnection("Server=localhost;Database=myCompany;integrated security=SSPI");

 

            myCon.Open();

            SqlCommand myCommand = new SqlCommand();

 

            myCommand.CommandText = @"select ID,

                                        Name,

                                        ParentID

                                        from Location

                                        ";         

           

            myCommand.Connection = myCon;

            SqlDataReader myReader = myCommand.ExecuteReader();

            Location myLocation = null;

            while (myReader.Read())

            {

                myLocation = new Location();

                myLocation.LocationName = Convert.ToString(myReader[1]);

                myLocation.LocationId = Convert.ToInt32(myReader[0]);

                myLocation.ParentLocationId = Convert.ToInt32(myReader[2]);

                myLocations.Add(myLocation.LocationId, myLocation);

            }

 

            myCon.Close();

 

            TreeNode aNode = null;

            result+="<br>start processing treeview : " + DateTime.Now.Second + " " + DateTime.Now.Millisecond;

           

            foreach (int aKey in myLocations.Keys)

            {

                string code = myLocations[aKey].LocationId.ToString();

                aNode = new TreeNode(myLocations[aKey].LocationName, code);

                CreateNode(aNode);

            }

            result += "<br>end processing treeview : " + DateTime.Now.Second + " " + DateTime.Now.Millisecond;

        }

        catch (Exception ex)

        {

            Response.Write("error<BR>" + ex.Message);

            Response.Write("Trace<BR>" + ex.StackTrace);

        }

        Response.Write(result);

    }

 

    public void CreateNode(TreeNode aNode)

    {

        //This list stores all the nodes id from the current node to the ultimate parent

        List<int> myPath = new List<int>();

        if (!myCreatedNodes.ContainsValue(aNode))//if the node was not alreazdy created

        {

            int nodeId=1001;

            nodeId = Convert.ToInt32(aNode.Value);

            //Building the current node path untill the ultimate parent

            myPath.Add(nodeId);

            while (nodeId != 0)

            {

               if(nodeId!=0){

               nodeId= myLocations[nodeId].ParentLocationId;

               myPath.Add(nodeId);

                }

            }

        }

       

        //descending from Ultimate parent until the node

        //if the current node does not exists we create it and add it to created nodes collection.

        //if it has not a parent we add it to the treeview

        //if it has a parent,the parent was already created because we come from it, so we add the current node to the parent.

        TreeNode nodeToAdd = null, ParentNodeTofind = null;

        for (int j = myPath.Count - 1; j > -1; j--)

        {

            if (myPath[j] != 0)

            {

                //checking for each path if the nodes was already created

                if (!myCreatedNodes.Keys.Contains(myLocations[myPath[j]].LocationId))

                {

                    //creating the node and adding it to the created nodes collection.

                    nodeToAdd = new TreeNode(myLocations[myPath[j]].LocationName, myLocations[myPath[j]].LocationId.ToString());

                    myCreatedNodes.Add(myLocations[myPath[j]].LocationId, nodeToAdd);

 

                    int parentId = myLocations[myPath[j]].ParentLocationId;

                    //checking if the node has a parent

                    if (parentId == 0)//this node has no parent we add it to the tree view

                    {

                        TreeView1.Nodes.Add(nodeToAdd);

                    }

                    else//this node has a parent

                    {

                        //rerieving parent node (sure to find it)

                        ParentNodeTofind = myCreatedNodes[myLocations[myPath[j]].ParentLocationId];

                        //we add the node to its parent childNodes

                        ParentNodeTofind.ChildNodes.Add(nodeToAdd);

                    }

                }

            }

        }

    }

</script>

 

 

Sunday, April 19, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Use Linq inside a Script Block of an Application Page - SharePoint minimal configuration for Linq


When developing for SharePoint you maybe use Linq. Assume you are developing a new piece of code and to improve your development speed you have decided to test this code in an Application Page inside a Script Block.

Suddenly, you want to use a Linq instruction but you remind that your page is called by a web site of a new Web Application and this Web Application web.config has not been modified to use .Net 3.5 new features.
Actually, at this point it is very fast to activate the use of Linq.

  1. Modify your Application Page to have intellisense.

    You have two page directives to paste:

    the Assembly Page Directive to add a reference to the System.Core.dll (there is just one version of this dll the3.5 version)

    <%@ Assembly Name="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" %>



    the Import Page Directive to specify the System.Linq Namespace 

    <%@ Import Namespace="System.Linq" %>


    From this point you will have Linq Intellisense in your Visual Studio 2008 Editor.



    So, you keep writing your code and obtain this page:



    <%@ Page Language="C#" %>

     

    <%@ Assembly Name="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" %>

    <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    <%@ Import Namespace="Microsoft.SharePoint" %>

    <%@ Import Namespace="System.Linq" %>

    <html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <title></title>

    </head>

    <body>

        <script runat="server">

            void Page_Load(object sender, EventArgs e)

            {

                SPListCollection myListCollection = SPContext.Current.Web.Lists;

                var listQuery = from SPList aList in myListCollection where (aList.Title) == "Customers" select aList;

     

                if (listQuery.Count() > 0)

                {

                    Response.Write("<br>How many Customers ? <br>" + listQuery.ElementAt<SPList>(0).ItemCount);

                }

                else

                {

                    Response.Write("<br>" + "There is no list with this name");

                }

            } 

        </script>

    </body>

    </html>

     



     But if you try to execute the page you will get a compilation Exception from SharePoint.



  2. Modify your web.config

    To fix the Linq compilation issue open your Web Application web.config and paste this xml code just under the ending Tag of System.Web.


        </webParts>

        <machineKey validationKey="E150B1AD042FFFD037943E670D1ED5EE50FCA3A12F8782BE" decryptionKey="F3790C833070BFBE30590B9CC6380A0592DF229F0DA7E3E7" validation="SHA1" />

        <sessionState mode="SQLServer" timeout="60" allowCustomSqlDatabase="true" partitionResolverType="Microsoft.Office.Server.Administration.SqlSessionStateResolver, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

      </system.web>

      <!--Start adding Linq Compilation Instruction - Marc -->

      <system.codedom>

        <compilers>

          <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4"

                    type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

            <providerOption name="CompilerVersion" value="v3.5"/>

            <providerOption name="WarnAsError" value="false"/>

          </compiler>

          <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4"

                    type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

            <providerOption name="CompilerVersion" value="v3.5"/>

            <providerOption name="OptionInfer" value="true"/>

            <providerOption name="WarnAsError" value="false"/>

          </compiler>

        </compilers>

      </system.codedom>

      <!--End adding Linq Compilation Instruction - Marc -->

      <runtime>

        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

          <dependentAssembly>



    And you're done!



Labels: , ,

Saturday, April 18, 2009  by Marc Charmois - About Me / Previous Posts / Archives - Home

Adding Breadcrumb Navigation for SharePoint Application Pages Programmatically



When creating a new Application Page (an .aspx page deployed to the c:\program files\common files\microsoft shared\web server extensions\12\template\layouts directory) you can easily manually fill the content place holder provided by the application.master in order to obtain a page that seems really to be an Out of The Box SharePoint Application Page.

Page Title (Browser Page Title)

<asp:Content ID="Content4" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
    <SharePoint:EncodedLiteral ID="EncodedLiteral2" runat="server" Text="Delete Items" EncodeMethod='HtmlEncode' />
</asp:Content>

Page Title (Displayed in th Application Page)

<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
    <SharePoint:EncodedLiteral ID="EncodedLiteral1" runat="server" Text="Delete Items from a Custom List" EncodeMethod='HtmlEncode' />
</asp:Content>

Page Description (Displayed in th Application Page)

<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
    <SharePoint:EncodedLiteral ID="EncodedLiteral3" runat="server" Text="Use this page to delete items from a Custom List" EncodeMethod='HtmlEncode' />
</asp:Content>

The above code sample will produce the following result:

There is one thing that you cannot perform manually using Content Place Holder, it is the Breadcrumb Navigation.

You have two ways of adding Breadcrumb Navigation for SharePoint Application Pages:

  1. Adding a siteMapNode element in the layouts.sitemap
    Jan Tielens has written several posts on that topic. The exposed several approaches use xml files and deployment techniques in order to make your custom Application Page to be known by SharePoint as one of its native Application Pages. Doing that allows the native SharePoint breadcrumb generating mechanism to place automatically a Breadcrumb in your custom Application Page.
  2. For more information you can visit:
    Adding Breadcrumb Navigation for SharePoint Application Pages
    Adding Breadcrumb Navigation to SharePoint Application Pages, the Easy Way
    Adding Breadcrumb Navigation to Application Pages in SharePoint Central Administration

  3. Adding Breadcrumb Programmatically
  4. This approach uses server-side code (C# or VB .Net). It is the opposite approach compared to Jan's one because we will customize SharePoint only at the page level.

    Pros:
    Your SharePoint customizations of the Application Page stay at the level of the page, so you can deploy all using a single Feature.
    You can build your own navigation (SiteCollection Root Web > Web Site1 >..> Web Site n,  Web Site n > List, Web Site n > Doc Lib, etc.) 

    Cons:
    You have to decide about what navigation you want.
    You have to build the navigation using C# or VB .Net.
    You might have to put parameters in the URL when calling the page (List ID, Doc Lib ID, Page Name,etc.) if you do not use a CustomAction Element to call the Application Page.

In the following code sample I will programmatically, using C#, add a breadcrumb to an Application Page called by a new entry in the Action Menu of a list.

So, with this UrlAction :

<UrlAction Url="~site/_layouts/custom directory/myCustomApplicationPage.aspx?id={ListId}"/>

 

The steps are the followings:

  • At the first Load of the page 
    Getting the Breadcrumb element(s) from URL and/or SPContext 
    Storing some of the elements in an Hidden Control for the PostBack of the page.
  • For the Postback
    Getting the Breadcrumb element(s) from the Hidden Control.
  • In any case
    Building the Breadcrumb HTML
    Override the RenderChildren method of the Application page to fill the PlaceHolderTitleBreadcrumb with the Breadcrumb HTML 

  • The following code sample shows how to perform these operations using C#:

        <asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderMain" runat="server">

            <br />

            <br />

            <asp:Label ID="lblItemsToDeleteList" runat="server"></asp:Label>

            <br />

            <br />

            <input type="hidden" runat="server" id="listid" />

        </asp:Content>

     

        <script runat="server">

            string breadcrumbListLink = string.Empty;

            string breadcrumbWebLink = string.Empty;

            string listUrl = string.Empty;

            SPList aList = null;

            public void Page_Load(object sender, EventArgs e)

            {

                if (IsPostBack)

                {

                    //provisioning bread crumb

                    using (SPWeb myWeb = SPContext.Current.Web)

                    {

     

                        //get the list ID stored before Postback

                        aList = myWeb.Lists[new Guid(listid.Value)];

                        listUrl = Microsoft.SharePoint.Utilities.SPUrlUtility.CombineUrl(myWeb.Url, aList.RootFolder.Url);

                        //server side step to provision the bread crumb.

                        breadcrumbWebLink = "<a href='" + myWeb.Url + "'>" + myWeb.Title + "</a>";

                        breadcrumbListLink = "<a href='" + listUrl + "'>" + aList.Title + "</a>";

                    }

                    return;

                }

     

                using (SPWeb myWeb = SPContext.Current.Web)

                {

                    try

                    {

                        aList = myWeb.Lists[new Guid(Request.QueryString["id"])];

     

                        //provisioning bread crumb

                        listUrl = SPUrlUtility.CombineUrl(myWeb.Url, aList.RootFolder.Url);

                        breadcrumbWebLink = "<a href='" + myWeb.Url + "'>" + myWeb.Title + "</a>";

                        breadcrumbListLink = "<a href='" + listUrl + "'>" + aList.Title + "</a>";

     

                        //storing the list ID to be retrieved after Postback in order to build bread crumb.

                        listid.Value = aList.ID.ToString();

                    }

                    catch

                    {

                        lblItemsToDeleteList.Text = "The list does not exist. Check that the page URL is correct and has not been manually modified.";

                        return;

                    }

                }

            }

     

            protected override void RenderChildren(HtmlTextWriter output)

            {

                LiteralControl myBreadcrumb = new LiteralControl(breadcrumbWebLink + " > " + breadcrumbListLink);

                Master.FindControl("PlaceHolderTitleBreadcrumb").FindControl("ContentMap").Controls.Add(myBreadcrumb);

                base.RenderChildren(output);

            }

        </script>

     



    I have posted the complete page example in CodePlex :

    SharePoint Delete Items of Custom Lists


     

    Labels: , , , ,