Showing posts with label object model programming. Show all posts
Showing posts with label object model programming. Show all posts

Saturday, April 23, 2011

Code to Browse the Security Setup of SharePoint Site Collection

In case if you need to verify the security setup of your SharePoint site collection, you just need to run the following code as shown below:

using System;
using System.Linq;
using Microsoft.SharePoint;

namespace BrowseSecurity
{
    class Program
    {
        static void Main(string[] args)
        {
            BrowseSecurity("http://localhost");
            Console.Out.WriteLine(true);
        }

        private static void BrowseSecurity(string url)
        {
            using (SPSite site = new SPSite(url))
            {
                SPWeb web = site.OpenWeb();
                Console.WriteLine("\n\nUsers:");
                foreach (SPUser user in web.Users)
                {
                    Console.WriteLine(user.Name);
                }

                Console.ReadLine();
                Console.WriteLine("\n\n All Users:");
                foreach (SPUser user in web.AllUsers)
                {
                    Console.WriteLine(user.Name);
                }
                Console.ReadLine();
                Console.WriteLine("\n\n Site Users:");
                foreach (SPUser user in web.AllUsers)
                {
                    Console.WriteLine(user.Name);
                }
                Console.ReadLine();
                Console.WriteLine("\n\n Roles:");
                foreach (SPRole role in web.Roles)
                {
                    Console.WriteLine(role.Name);
                }
                Console.ReadLine();
                Console.WriteLine("\n\n Roles Definitions:");
                foreach (SPRoleDefinition roledef in web.RoleDefinitions)
                {
                    Console.WriteLine(roledef.Name);
                }
                Console.ReadLine();
                Console.WriteLine("\n\n Roles Assignments:");
                foreach (SPRoleAssignment roleA in web.RoleAssignments)
                {
                    Console.WriteLine("The following Role definition bindings exist for " +
                    roleA.Member.Name);
                    foreach (SPRoleDefinition roledef in roleA.RoleDefinitionBindings)
                    {
                        Console.WriteLine(roledef.Name);
                    }
                }
                Console.ReadLine();
                Console.WriteLine("\n\n Groups:");
                foreach (SPGroup group in web.Groups)
                {
                    Console.WriteLine(group.Name);
                }
                Console.ReadLine();
            }
        }
    }
}

Sunday, April 17, 2011

Send Email in SharePoint via .NET SmtpClient Class and SharePoint SPUtility Class

In SharePoint, you could send email programmatically by using either .NET Class Library or SharePoint Object Model. I always prefer the second method since using SharePoint ensures that the required settings are maintained by Central Administration.

The following show the two code examples on how you could do this:

Sending Email via .NET SmtpClient Class

using System.Net.Mail;
using Microsoft.SharePoint;

/// <summary>
/// Sends the mail via NET SmtpClient.
/// </summary>
/// <param name="Subject">The subject.</param>
/// <param name="Body">The body.</param>
/// <param name="IsBodyHtml">if set to <c>true</c> [is body HTML].</param>
/// <param name="From">From.</param>
/// <param name="To">To.</param>
/// <param name="Cc">The cc.</param>
/// <param name="Bcc">The BCC.</param>
/// <returns></returns>
public static bool SendMailviaNET(string Subject, string Body, bool IsBodyHtml, string From, string To, string Cc, string Bcc)
{
    bool mailSent = false;
    try
    {
        SmtpClient smtpClient = new SmtpClient();
        smtpClient.Host = SPContext.Current.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
        MailMessage mailMessage = new MailMessage(From, To, Subject, Body);

        if (!String.IsNullOrEmpty(Cc))
        {
            MailAddress CCAddress = new MailAddress(Cc);
            mailMessage.CC.Add(CCAddress);
        }
        if (!String.IsNullOrEmpty(Bcc))
        {
            MailAddress BCCAddress = new MailAddress(Bcc);
            mailMessage.Bcc.Add(BCCAddress);
        }

        mailMessage.IsBodyHtml = IsBodyHtml;
        smtpClient.Send(mailMessage);
        mailSent = true;
    }
    catch (Exception)
    {
        return mailSent;
    }
    return mailSent;
}

Sending Email via SharePoint SPUtility Class

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Collections.Specialized;

/// <summary>
/// Sends the mail via SharePoint SPUtility.
/// </summary>
/// <param name="Subject">The subject.</param>
/// <param name="Body">The body.</param>
/// <param name="IsBodyHtml">if set to <c>true</c> [is body HTML].</param>
/// <param name="From">From.</param>
/// <param name="To">To.</param>
/// <param name="Cc">The cc.</param>
/// <param name="Bcc">The BCC.</param>
/// <returns></returns>
public static bool SendMailviaSharePoint(string Subject, string Body, bool IsBodyHtml, string From, string To, string Cc, string Bcc)
{
    bool mailSent = false;
    try
    {
        SPWeb thisWeb = SPContext.Current.Web;
               
        StringDictionary headers = new StringDictionary();
        headers.Add("to", To);
        headers.Add("cc", Cc);
        headers.Add("bcc", Bcc);
        headers.Add("from", From);
        headers.Add("subject", Subject);
        if (IsBodyHtml) headers.Add("content-type", "text/html");

        mailSent = SPUtility.SendEmail(thisWeb, headers, Body);
    }
    catch (Exception)
    {
        return mailSent;
    }
    return mailSent;
}

Tuesday, February 8, 2011

Getting SharePoint Web Application URL Using SPAlternateUrl

By using SPAlternateURL object, you can get the URL or SharePoint 2010 Web Application since the alternate access mappings are associated with a Web Application. Sample code is provided below:

public static string GetWebAppURL(SPWebApplication oWebApp, SPUrlZone urlZone)
{
    string retVal = string.Empty;
    try
    {
        foreach (SPAlternateUrl altUrl in oWebApp.AlternateUrls)
        {
            if (altUrl.UrlZone == urlZone)
            {
                retVal = altUrl.Uri.ToString();
                break;
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return retVal;
}

public static string GetWebAppURL(SPSite oSite, SPUrlZone urlZone)
{
    string retVal = string.Empty;
    SPWebApplication oWebApp = null;
    try
    {
        if ((oWebApp = oSite.WebApplication) != null)
            retVal = GetWebAppURL(oWebApp, urlZone);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return retVal;
}

public static string GetWebAppURL(SPWeb oWeb, SPUrlZone urlZone)
{
    string retVal = string.Empty;
    SPWebApplication oWebApp = null;
    try
    {
        if(( oWebApp = oWeb.Site.WebApplication)!=null)
            retVal = GetWebAppURL(oWebApp, urlZone);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return retVal;
}

In order to call these functions, you need to pass either SPWebApplication, SPSite or SPWeb object and specify the SPUrlZone enumeration which has the following originating zone of a request:

  • Default - Specifies the default zone used for requests unless another zone is specified.
  • Intranet - Specifies an intranet zone.
  • Internet - Specifies an Internet zone.
  • Custom - Specifies a custom zone.
  • Extranet - Specifies an extranet zone.

Tuesday, February 1, 2011

The Disposable in SharePoint Development

If you don’t properly dispose of objects in the SharePoint object model that implement IDisposable, you will have memory usage problems in your application. The objects to be most careful of are SPSite and SPWeb, which must be disposed of because they consume large amounts of unmanaged memory.

But Wait… I Thought Garbage Collection Took Care of Memory Management?

The answer to this question is that an object like SPSite uses a mix of managed and unmanaged code. The memory usage of the managed side of SPSite is monitored by the .NET garbage collector, and when enough memory is used by the managed code, the garbage collector will kick in. The problem is that the .NET garbage collector doesn’t watch the unmanaged code’s use of memory and the unmanaged memory use is much greater than the managed memory use. So you can quickly run out of memory on the unmanaged
side without .NET ever feeling like it needs to do a garbage collection.

There are several coding patterns that I use when working with SPWeb and SPSite and other objects that implement IDisposable, so I would like to share with all of you:

Using Dispose with SPSite or SPWeb  object

SPSite oSite = new SPSite("http://localhost");

// Do something

SPWeb oWeb = oSite.OpenWeb();

// Do something

oWeb.Dispose();
oSite.Dispose();

The using clause with SPSite or SPWeb

using (SPSite oSite = new SPSite("http://localhost"))
{
    // Do something
    using (SPWeb oWeb = oSite.OpenWeb())
    {
        // Do something
    }
}

Using Dispose in the finally block of try, catch, finally code

SPSite oSite = null;
SPWeb oWeb = null;
try
{
    if ((oSite = new SPSite("http://localhost")) != null)
    {
        oWeb = oSite.OpenWeb();
        // Do something
    }
}
catch (Exception ex)
{
    // Handle exception
}
finally
{
    if (oWeb != null)
        oWeb.Dispose();

    if (oSite != null)
        oSite.Dispose();
}

Using Dispose with an object in a foreach loop

using (SPSite oSite = new SPSite("http://localhost"))
{
    foreach (SPWeb oWeb in oSite.AllWebs)
    {
        try
        {
            // Do something here
        }
        catch (Exception ex)
        {
            // Handle exception
        }
        finally
        {
            if (oWeb != null)
                oWeb.Dispose();
        }
    }
}

Do Not Dispose of the SPSite and SPWeb Return By SPContext

According to SharePoint best practices, SPSite and SPWeb objects returned by SPContext.Site, SPContext.Current.Site, SPContext
.Web, and SPContext.Current.Web should not be explicitly disposed by user code.

SharePoint Dispose Checker Tool

Alternatively, you can use SPDisposeCheck to measure your code against known Microsoft dispose best practices.

Tuesday, January 4, 2011

Write Error Logging Entries To The SharePoint Unified Logging Service (ULS) Logs

All SharePoint exceptions are derived from the SPException class. We can write error logging entries to the SharePoint Unified Logging Service (ULS) logs by using code similar to the following sample:

using Microsoft.SharePoint.Administration;
 

try
{
    // Some code
}
catch (Exception ex)
{
    // Create diagnostics category
    SPDiagnosticsCategory oCat = new SPDiagnosticsCategory("A new category", TraceSeverity.Monitorable, EventSeverity.Error);
    // Write to ULS
    SPDiagnosticsService.Local.WriteEvent(1, oCat, EventSeverity.Error, "Error custom message", ex.StackTrace);
}

ULS is stored in the file system in “C:\Program Files\Common Files\Microsoft Shared\web server extensions\14\LOGS”.

Friday, November 12, 2010

Deleting Data Using Silverlight and Javascript Client Object Model

Silverlight

private void Delete_Click(object sender, RoutedEventArgs e)
{
    ClientContext ctx = new ClientContext("Your Server Here");
    CamlQuery query = new CamlQuery();
    query.ViewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";
    List announcements = ctx.Web.Lists.GetByTitle("Announcements");

    ListItemCollection listItems = announcements.GetItems(query);
    ctx.Load(listItems);
    ctx.ExecuteQueryAsync((s, args) =>
    {
        ListItem lastItem = listItems[listItems.Count - 1];
        lastItem.DeleteObject();
        announcements.Update();
        ctx.ExecuteQueryAsync((s1, args1) =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                label1.Content = "Last record deleted";
            });
        }, null);
    }, (s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            label1.Content = args.Message;
        });
    });
}

Javascript

function Delete_Click() {
    var ctx = new SP.ClientContext.get_current();
    var query = new SP.CamlQuery();
    query.viewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";
    var announcements = ctx.get_web().get_lists().getByTitle("Announcements");
    var listItems = announcements.getItems(query);

    ctx.load(listItems, "Include(Title)");
    ctx.executeQueryAsync(function (s, args) {
        var lastItem = listItems.get_item(listItems.get_count() - 1);
        lastItem.deleteObject();
        announcements.update();
        ctx.executeQueryAsync(function (s, args) {
            var console = document.getElementById('DemoConsole');
            console.innerHTML = " Last Item Deleted";
        }, null);
    }, null);
}

For more information on Silverlight and JavaScript Client Object Model, see below:

Thursday, November 11, 2010

Updating Data Using Silverlight and Javascript Client Object Model

Silverlight

private void Update_Click(object sender, RoutedEventArgs e)
{
    ClientContext ctx = new ClientContext("Your Server Here");
    CamlQuery query = new CamlQuery();
    query.ViewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";
    List announcements = ctx.Web.Lists.GetByTitle("Announcements");

    ListItemCollection listItems = announcements.GetItems(query);
    ctx.Load(listItems);
    ctx.ExecuteQueryAsync((s, args) =>
    {
        foreach (var item in listItems)
        {
            item["Title"] = "Updated";
            item.Update();
        }
        ctx.ExecuteQueryAsync((s1, args1) =>
        {
            Dispatcher.BeginInvoke(() =>
            {
                label1.Content = "Records Updated";
            });
        }, null);
    }, (s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            label1.Content = args.Message;
        });
    });
}

Javascript

function Update_Click() {
    var ctx = new SP.ClientContext.get_current();
    var query = new SP.CamlQuery();
    query.viewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";
    var announcements = ctx.get_web().get_lists().getByTitle("Announcements");
    var listItems = announcements.getItems(query);

    ctx.load(listItems, "Include(Title)");
    ctx.executeQueryAsync(function (s, args) {
        var itemEnum = listItems.getEnumerator();
        while (itemEnum.moveNext()) {
            var item = itemEnum.get_current();
            item.set_item("Title", "JavaScript Update");
            item.update();
        }
        ctx.executeQueryAsync(function (s, args) {
            var console = document.getElementById('DemoConsole');
            console.innerHTML = "JavaScript Update Completed";
        }, null);
    }, null);
}

For more information on Silverlight and JavaScript Client Object Model, see below:

Adding Data Using Silverlight and Javascript Client Object Model

Silverlight

private void Add_Click(object sender, RoutedEventArgs e)
{
    ClientContext ctx = new ClientContext("Your Server Here");
    List announcements = ctx.Web.Lists.GetByTitle("Announcements");

    ListItemCreationInformation createInfo = new ListItemCreationInformation();
    ListItem newItem = announcements.AddItem(createInfo);
    newItem["Title"] = "A new item";
    newItem.Update();
    ctx.ExecuteQueryAsync((s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            label1.Content = "Item Added";
        });
    }, (s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            label1.Content = args.Message;
        });
    });
}

Javascript

function Add_Click() {
    var ctx = new SP.ClientContext.get_current();
    var announcements = ctx.get_web().get_lists().getByTitle("Announcements");

    var createInfo = new SP.ListItemCreationInformation();
    var newItem = announcements.addItem(createInfo);
    newItem.set_item("Title", "A new javascript item");
    newItem.update();

    ctx.executeQueryAsync(function (s, args) {
        var console = document.getElementById("DemoConsole");
        console.innerHTML = "Add Completed";
    }, null);
}

For more information on Silverlight and JavaScript Client Object Model, see below:

Wednesday, November 10, 2010

Retrieving Data Using Silverlight and JavaScript Client Object Model

Sliverlight

private void CAMLQuery_Click(object sender, RoutedEventArgs e)
{
    ClientContext ctx = new ClientContext("Your site here");
    CamlQuery query = new CamlQuery();
    query.ViewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";

    List announcements = ctx.Web.Lists.GetByTitle("Announcements");
    FieldCollection fields = announcements.Fields;
    ctx.Load(fields);

    ListItemCollection listItems = announcements.GetItems(query);
    ctx.Load(listItems);
    ctx.ExecuteQueryAsync((s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            BuildTable(fields, listItems);
        });
    }, (s, args) =>
    {
        Dispatcher.BeginInvoke(() =>
        {
            label1.Content = args.Message;
        });
    });
}

JavaScript

function CAMLQuery_Click() {
    var ctx = new SP.ClientContext.get_current();
    var query = new SP.CamlQuery();
    query.viewXml = "<View><Query><OrderBy><FieldRef Name=\"Editor\" Ascending=\"False\" /></OrderBy></Query></View>";
    var announcements = ctx.get_web().get_lists().getByTitle("Announcements");
    var listItems = announcements.getItems(query);
    ctx.load(listItems);
    var fields = announcements.get_fields();
    ctx.load(fields);
    ctx.executeQueryAsync(function (s, args) {
        var console = document.getElementById('DemoConsole');
        console.innerHTML = buildTable(fields, listItems);
    }, null);
}

For more information on Silverlight and JavaScript Client Object Model, see below:

Monday, November 8, 2010

How To Referencing the JavaScript Client Object Model

The following are simple steps to show how you can hooks your SharePoint page with JavaScript Client Object Model:

  1. From the Site Actions menu, choose New Page. Name the new page JSClientObjectModelTest.
  2. From the Page tab in the ribbon, click Save.
  3. Also from the Page tab, click the arrow under the Edit button and select Edit In SharePoint Designer.
  4. In SharePoint Designer, from the Home tab on the ribbon, select Advanced Mode.
  5. In the Content control with the ID PlaceHolderAdditionalPageHead, add the following markup after the SharePoint:RssLink tag (on one line):

    <SharePoint:ScriptLink runat="server" Name="sp.js" Localizable="false" LoadAfterUI="true"/>


  6. Scroll to the bottom of the page, and before the WebPartPage:WebPartZone tag, add the following markup (on one line):

    <script type="text/javascript" src="../SilverlightControls/JScriptTest.js" ></script>
    <div id="DemoConsole"></div>


  7. Click the Save icon in the upper-left corner of the window to save the changes to SharePoint. Click Yes in the Site Definition Page Warning.

For more information on Silverlight and JavaScript Client Object Model, see below:

Friday, July 17, 2009

How to Make SPGridView To Have Same Look And Feel Of The Out Of The Box SharePoint List View

When you attempt to develop a Web Part that uses an SPGridView control, you’ll notice the following differences to your SPGridView look and feel compared to the out of the box SharePoint List View:

  • SPGridView font type is Verdana, out of the box SharePoint List View font type is Tahoma
  • Font size and colour different
  • No alternating styles for items
  • Header style, pager styles, etc.

Screenshot below shows the differences:

 image

If you’re good in CSS and HTML, then you’ll find CSS Reference Chart for SharePoint 2007 is helpful and you should be able to change your SPGridView styles to have the same look and feel of of the out of the box SharePoint List View.

Instead of doing above you can assign the WebPart.UseDefaultStyles of your Web Part to false. See code below:

protected override void CreateChildControls()
{
    this.UseDefaultStyles = false;

By setting the UseDefaultStyles to false, your SPGridView styles will have the same look and feel of the out of the box SharePoint List View. See screenshot below:

image

Please note that UseDefaultStyles only applicable for SharePoint Web Part and not ASP.NET Web Part – for ASP.NET Web Part please use SPChromeSettings.UseDefaultStyles.

Thursday, July 16, 2009

Validate User Base Permissions Before Uploading Document to SharePoint Document Library

If you are building a custom Web Part to upload document to SharePoint Document Library, then you need to validate user’s base permission so that unauthorised user can’t perform upload. You can’t validate based on their permission levels since at anytime base permissions of any permission level can be changed by administrator. Plus, in object model there is no specific method to get the permission level or what permission level assigned to a group or a user.

This article describes how to perform document upload to SharePoint and validate user base permissions so that only authorized users are able to perform the upload.

In SharePoint, the out-of-the-box permission level allowed user with "Contribute" permission level or higher (i.e. "Full Control", "Design", "Manage Hierarchy" and "Approve") to upload document to SharePoint. The following code displays the base permissions for each permission level:

SPSite oSite = new SPSite("http://examplesite");
SPWeb oWeb = oSite.OpenWeb();

SPRoleDefinitionBindingCollection usersRoles = oWeb.AllRolesForCurrentUser;
foreach (SPRoleDefinition roleDefinition in usersRoles)
    retVal += roleDefinition.BasePermissions.ToString() + " | ";

System.Diagnostics.Debug.WriteLine(retVal);

Full Control” permission level:

  • FullMask
  • OR SPWeb.UserIsWebAdmin = TRUE

Design” permission level:

  • ViewListItems | AddListItems | EditListItems | DeleteListItems | ApproveItems | OpenItems | ViewVersions | DeleteVersions | CancelCheckout | ManagePersonalViews | ManageLists | ViewFormPages | Open | ViewPages | AddAndCustomizePages | ApplyThemeAndBorder | ApplyStyleSheets | CreateSSCSite | BrowseDirectories | BrowseUserInfo | AddDelPrivateWebParts | UpdatePersonalWebParts | UseClientIntegration | UseRemoteAPIs | CreateAlerts | EditMyUserInfo

Manage Hierarchy” permission level:

  • ViewListItems | AddListItems | EditListItems | DeleteListItems | OpenItems | ViewVersions | DeleteVersions | CancelCheckout | ManagePersonalViews | ManageLists | ViewFormPages | Open | ViewPages | AddAndCustomizePages | ViewUsageData | CreateSSCSite | ManageSubwebs | ManagePermissions | BrowseDirectories | BrowseUserInfo | AddDelPrivateWebParts | UpdatePersonalWebParts | ManageWeb | UseClientIntegration | UseRemoteAPIs | ManageAlerts | CreateAlerts | EditMyUserInfo | EnumeratePermissions
    OR SPWeb.UserIsWebAdmin = TRUE

Approve” permission level:

  • ViewListItems | AddListItems | EditListItems | DeleteListItems | ApproveItems | OpenItems | ViewVersions | DeleteVersions | CancelCheckout | ManagePersonalViews | ViewFormPages | Open | ViewPages | CreateSSCSite | BrowseDirectories | BrowseUserInfo | AddDelPrivateWebParts | UpdatePersonalWebParts | UseClientIntegration | UseRemoteAPIs | CreateAlerts | EditMyUserInfo

Contribute” permission level:

  • ViewListItems | AddListItems | EditListItems | DeleteListItems | OpenItems | ViewVersions | DeleteVersions | ManagePersonalViews | ViewFormPages | Open | ViewPages | CreateSSCSite | BrowseDirectories | BrowseUserInfo | AddDelPrivateWebParts | UpdatePersonalWebParts | UseClientIntegration | UseRemoteAPIs | CreateAlerts | EditMyUserInfo

Read” permission level:

  • ViewListItems | OpenItems | ViewVersions | ViewFormPages | Open | ViewPages | CreateSSCSite | BrowseUserInfo | UseClientIntegration | UseRemoteAPIs | CreateAlerts

and for "Site Collection Administrator" user, base permission as follows:

  • FullMask
  • OR SPWeb.UserIsSiteAdmin= TRUE

To validate whether user access rights to upload document to SharePoint, the following conditions shall be used:

  • SPWeb.UserIsSiteAdmin = TRUE OR
  • SPWeb.UserIsWebAdmin = TRUE OR
  • AddListItems is exist OR
  • EditListItems is exist OR
  • ApproveItems is exist OR

See code below for details:

public static void IsUserBasePermissionValidToUpload(SPWeb oWeb)
{
    try
    {
        if (oWeb.Exists)
        {
            // If user is site collection administrator or admin
            if (oWeb.UserIsWebAdmin || oWeb.UserIsSiteAdmin)
                return;

            // Get roles for current user
            SPRoleDefinitionBindingCollection usersRoles = oWeb.AllRolesForCurrentUser;
            // Validate if user has rights to upload document
            foreach (SPRoleDefinition roleDefinition in usersRoles)
            {
                if (roleDefinition.BasePermissions.ToString().Contains(SPBasePermissions.FullMask.ToString())
                    || roleDefinition.BasePermissions.ToString().Contains(SPBasePermissions.AddListItems.ToString())
                    || roleDefinition.BasePermissions.ToString().Contains(SPBasePermissions.EditListItems.ToString())
                    || roleDefinition.BasePermissions.ToString().Contains(SPBasePermissions.ApproveItems.ToString()))
                    return;
            }

            // If user has invalid rights, then throw exceptions
            throw new Exception("Unauthorised to upload document to SharePoint Document Library. " +
                "You are currently signed in as: " + oWeb.CurrentUser.LoginName);
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

SPUtility.Redirect – Redirect Pages at _layouts folder, the Safest Way

When you need to redirect to pages located at _layouts folder, the safest way is to use SPUtility.Redirect method. The following are sample to redirect to settings.aspx page:

SPUtility.Redirect("settings.aspx", SPRedirectFlags.UseSource | SPRedirectFlags.RelativeToLayoutsPage, HttpContext.Context);

If you want to redirect to custom pages at _layout folder, see below:

SPUtility.Redirect("sharepointmalaya/customadminsettings.aspx", SPRedirectFlags.Static | SPRedirectFlags.RelativeToLayoutsPage | SPRedirectFlags.RelativeToLocalizedLayoutsPage, HttpContext.Current);

Details on the SPRedirectFlags enumerations can be found here.

Wednesday, July 15, 2009

How To Check If MOSS Or WSS Is Installed

There are many approaches to check if MOSS or WSS is installed at specific installation site. One of the approach is to check the Windows Registry key.

If MOSS is installed, there will be registry entries in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\12.0

image

If WSS is installed, there will be registry entries in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0

image

Please note that if MOSS is installed both registry entries as shown above will be exist at installation sites.

I’ve created a helper class SharePointConfig.cs which exposes method and properties which are useful to those who are interested use this approach. See code below:

public class SharePointConfig
{
    private const string MOSS_REGISTRY_PATH = @"SOFTWARE\Microsoft\Office Server\12.0";
    private const string MOSS_BUILD_VERSION = "BuildVersion";
    private const string MOSS_TEMPLATE_PATH = "TemplatePath";

    private const string WSS_REGISTRY_PATH = @"SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0";
    private const string WSS_BUILD_VERSION = "BuildVersion";
    private const string WSS_TEMPLATE_PATH = "TemplatePath";
    private bool _ismossinstalled;
    private bool _iswssinstalled;
    private string _buildversion;
    private string _templatepath;

    /// <summary>
    /// Initializes a new instance of the <see cref="SharePointConfig"/> class.
    /// </summary>
    public SharePointConfig()
    {
        GetSharePointConfig();
    }

    /// <summary>
    /// Gets a value indicating whether this instance is MOSS installed.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is MOSS installed; otherwise, <c>false</c>.
    /// </value>
    public bool IsMOSSInstalled
    {
        get { return _ismossinstalled; }
    }

    /// <summary>
    /// Gets a value indicating whether this instance is WSS installed.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this instance is WSS installed; otherwise, <c>false</c>.
    /// </value>
    public bool IsWSSInstalled
    {
        get { return _iswssinstalled; }
    }

    /// <summary>
    /// Gets the build version.
    /// </summary>
    /// <value>The build version.</value>
    public string BuildVersion
    {
        get { return _buildversion; }
    }

    /// <summary>
    /// Gets the template path.
    /// </summary>
    /// <value>The template path.</value>
    public string TemplatePath
    {
        get { return _templatepath; }
    }

    /// <summary>
    /// Loads the share point config.
    /// </summary>
    public void GetSharePointConfig()
    {
        try
        {
            // Assume current user has full rights to registry settings
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                // Get MOSS registry key
                RegistryKey theRegistry = Registry.LocalMachine.OpenSubKey(MOSS_REGISTRY_PATH);

                if (theRegistry != null)
                {
                    // Get registry values
                    _buildversion = theRegistry.GetValue(MOSS_BUILD_VERSION).ToString();
                    _templatepath = theRegistry.GetValue(MOSS_TEMPLATE_PATH).ToString();
                    _ismossinstalled = MossOrWSSIsFound();
                }
                else
                {
                    // Get WSS registry key
                    theRegistry = Registry.LocalMachine.OpenSubKey(WSS_REGISTRY_PATH);

                    if (theRegistry != null)
                    {
                        // Get registry values
                        _buildversion = theRegistry.GetValue(WSS_BUILD_VERSION).ToString();
                        _templatepath = theRegistry.GetValue(WSS_TEMPLATE_PATH).ToString();
                        _iswssinstalled = MossOrWSSIsFound();
                    }
                }

            });
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    /// <summary>
    /// Mosses the or WSS is found.
    /// </summary>
    /// <returns></returns>
    private bool MossOrWSSIsFound()
    {
        bool retVal = false;
        try
        {
            if (!string.IsNullOrEmpty(_buildversion) && !string.IsNullOrEmpty(_templatepath))
            {
                Version buildVersion = new Version(_buildversion);
                if (buildVersion.Major == 12)
                    retVal = true;
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return retVal;
    }
}

The following tables list the members exposed by the SharePointMalaya.SSOHelper.SSOConfiguration type.

Public method SharePointConfig - Initializes a new instance of the SharePointConfig class, get registry key for either MOSS or WSS.

Public method IsMOSSInstalled - Gets a value indicating whether MOSS instance is installed.

Public method IsWSSInstalled - Gets a value indicating whether WSS instance is installed.

Public method BuildVersion - Gets either MOSS or WSS build version.

Public method TemplatePath - Gets either MOSS or WSS template path.

Get source code here:

Sample Web Part

image

Sunday, June 7, 2009

Retrieve Username and Password from SharePoint Single Sign-on (SSO) Provider Application

I’ve created a helper component SharePointMalaya.SSOHelper.SSOConfiguration that helped to provide the specific methods to retrieve username and password from the given SharePoint SSO provider application name.

The SharePointMalaya.SSOHelper.SSOConfiguration source code details are shown below:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Web;

using Microsoft.SharePoint;
using MSSO = Microsoft.SharePoint.Portal.SingleSignon;

namespace SharePointMalaya.SSOHelper
{
    /// <summary>
    ///
    /// </summary>
    public class SSOConfiguration
    {
        #region Member Variables

        private string _username;
        private string _password;
        private bool _isexistssoprovider;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SSOConfiguration"/> class.
        /// </summary>
        /// <param name="ssoApplicationName">Name of the sso application.</param>
        public SSOConfiguration(string ssoApplicationName)
        {
            try
            {
                ConnectToSSO(ssoApplicationName);
            }
            catch (Exception ex)
            {
                throw ex;
            }           
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the username.
        /// </summary>
        /// <value>The username.</value>
        public string Username
        {
            get { return _username; }
        }

        /// <summary>
        /// Gets the password.
        /// </summary>
        /// <value>The password.</value>
        public string Password
        {
            get { return _password; }
        }

        /// <summary>
        /// Gets a value indicating whether SSO provider is exist.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is exist SSO provider; otherwise, <c>false</c>.
        /// </value>
        public bool IsExistSSOProvider
        {
            get { return _isexistssoprovider; }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Connects to SSO.
        /// </summary>
        /// <param name="ssoApplicationName">Name of the sso application.</param>
        private void ConnectToSSO(string ssoApplicationName)
        {
            try
            {
                MSSO.ISsoProvider provider = MSSO.SsoProviderFactory.GetSsoProvider();

                if (provider != null)
                {
                    MSSO.SsoCredentials creds = provider.GetCredentials(ssoApplicationName);

                    IntPtr pUserName = IntPtr.Zero;
                    IntPtr pPassword = IntPtr.Zero;

                    try
                    {
                        // Get the non-secure string version of the credentials 
                        pUserName = Marshal.SecureStringToBSTR(creds.UserName);
                        _username = Marshal.PtrToStringBSTR(pUserName);

                        pPassword = Marshal.SecureStringToBSTR(creds.Evidence[1]);
                        _password = Marshal.PtrToStringBSTR(pPassword);

                        _isexistssoprovider = true;
                    }
                    finally
                    {
                        //Zero out and free the BSTR pointers
                        if (IntPtr.Zero != pUserName)
                        {
                            Marshal.ZeroFreeBSTR(pUserName);
                        }

                        if (IntPtr.Zero != pPassword)
                        {
                            Marshal.ZeroFreeBSTR(pPassword);
                        }
                    }
                }
            }
            catch (MSSO.SingleSignonException ssoEx)
            {
                throw ssoEx;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion
    }
}

The following tables list the members exposed by the SharePointMalaya.SSOHelper.SSOConfiguration type.

Public method SSOConfiguration - Initializes a new instance of the SSOConfiguration class, connects to SSO provider and get the username and password.

Public method Username - Gets the username from SSO provider.

Public method Password - Gets the password from SSO provider.

Public method IsExistSSOProvider - Gets a value indicating whether SSO provider is exist.

Example

The following is code sample on how to connect to the SSO provider and retrieve stored SSO username and password:

if (!string.IsNullOrEmpty(txtSSOApplicationName.Text))
{
    // Instantiate SSOConfiguration and connect to SharePoint SSO provider by passing SSO Application Name
    SSOConfiguration objSSOConfiguration = new SSOConfiguration(txtSSOApplicationName.Text);

    // Check if SSO provider is found
    if (objSSOConfiguration.IsExistSSOProvider)
    {
        // Assign stored SSO Username and Password to controls
        lblSSOUsername.Text = objSSOConfiguration.Username;
        lblSSOPassword.Text = objSSOConfiguration.Password;
    }
}

The following are screenshot showing a user logon to SharePoint site and retrieve his/her username and password from “SSO_Provider1” SSO Provider application name.

SSO1

Get source code here:

Sunday, May 3, 2009

Installing Custom Database as a SharePoint Feature

In any SharePoint project, sometimes there is a need to create an external custom RDBMS database to host non-related SharePoint information outside SharePoint's Content Database for example user credentials for form-based authentication, look up data, etc. To do this, the obvious solution is to use either one of following techniques:

  • provide customer with .SQL file and installation steps
  • provide customer with .MSI file and installation steps

None of the above technique is wrong!

However, I found technique no. 1 (install custom RDBMS database using .SQL file) is time-consuming and more prone to error - especially if customer who doing installation is not technical at all or the .SQL file doesn't obey the rules. For technique no. 2 - you need strong knowledge in Microsoft Windows Installer packaging tools and you need to download/configure MSI Redistributable package if you don't have one. So, the best solution is to utilize the SharePoint Feature Framework.

Features are the backbone of SharePoint development because every custom development project can and really should be deployed as a feature. Features give tremendous control over SharePoint configurations and capabilities at the administrator level. This means that developers can create features and then turn them over to SharePoint administrators without having to get involved repeatedly in small configuration changes.

I have developed a REUSEABLE FEATURE(SharePointMalaya.Feature.CustomDBInstaller.dll) that able to automate the installation of custom RDBMS database to any SharePoint’s database server. All you need to do is to generate SQL scripts using MS Server Management Studio, save the SQL scripts to SharePointMalaya.Feature.CustomDBInstaller feature folder, build WSP, install and activate the feature at SharePoint site.

SharePointMalaya.Feature.CustomDBInstaller feature comprises of SharePoint Event Handler which inherits from base abstract class SPFeatureReceiver to trap the activation, deactivation, installation, or uninstallation of a Feature. See codes below:

private const string FEATURE_FOLDER_PATH = "TEMPLATE\\FEATURES\\SharePointMalaya.Feature.CustomDBInstaller\\";
private const string TSQL_SCRIPT_INSTALLDB_FOLDER_PATH = FEATURE_FOLDER_PATH + "T-SQL\\Install\\";
private const string TSQL_SCRIPT_UNINSTALLDB_FOLDER_PATH = FEATURE_FOLDER_PATH + "T-SQL\\UnInstall\\";

/// <summary>
/// Occurs after a Feature is activated.
/// </summary>
/// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPFeatureReceiverProperties"></see> object that represents the properties of the event.</param>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    try
    {
        // Run with an account with higher privileges than the current user
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (SPSite oSite = properties.Feature.Parent as SPSite)
            {
                SPWeb oWeb = null;

                if (oSite != null)
                    oWeb = oSite.RootWeb;
                else
                    oWeb = properties.Feature.Parent as SPWeb;

                if (oWeb.Exists)
                {
                    // Turn off security validation
                    oWeb.AllowUnsafeUpdates = true;

                    // Execute T-SQL scripts from <<FEATUREFOLDER>>\T_SQL\Install folder
                    ExecuteSQLScripts(oSite, TSQL_SCRIPT_INSTALLDB_FOLDER_PATH);

                    // Turn on security validation
                    oWeb.AllowUnsafeUpdates = false;
                }
                else
                    throw new Exception("Unable to open site.");
            }
        });
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

/// <summary>
/// Occurs when a Feature is deactivated.
/// </summary>
/// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPFeatureReceiverProperties"></see> object that represents the properties of the event.</param>
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
    try
    {
        // Run with an account with higher privileges than the current user
        SPSecurity.RunWithElevatedPrivileges(delegate()
        {
            using (SPSite oSite = properties.Feature.Parent as SPSite)
            {
                SPWeb oWeb = null;

                if (oSite != null)
                    oWeb = oSite.RootWeb;
                else
                    oWeb = properties.Feature.Parent as SPWeb;

                if (oWeb.Exists)
                {
                    // Turn off security validation
                    oWeb.AllowUnsafeUpdates = true;

                    // Execute T-SQL scripts to uninstall from <<FEATUREFOLDER>>\T_SQL\UnInstall folder
                    ExecuteSQLScripts(oSite, TSQL_SCRIPT_UNINSTALLDB_FOLDER_PATH);

                    // Turn on security validation
                    oWeb.AllowUnsafeUpdates = false;
                }
                else
                    throw new Exception("Unable to open site.");
            }
        });
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

/// <summary>
/// Executes the SQL scripts.
/// </summary>
/// <param name="oSite">The o site.</param>
/// <param name="scriptsPath">The scripts path.</param>
private void ExecuteSQLScripts(SPSite oSite, string scriptsPath)
{
    SqlConnection objCon = null;
    SqlCommand objCmd = null;

    try
    {
        // Get SharePoint content database connection string
        string connectionString = oSite.ContentDatabase.DatabaseConnectionString;

        // Get T-SQL script files for installing database from Feature folder
        string[] fileEntries = Directory.GetFiles(SPUtility.GetGenericSetupPath(scriptsPath));

        // files exist then open connection to database and sort file by name
        if (fileEntries.Length > 0)
        {
            // Create and open connection object
            objCon = new SqlConnection(connectionString);
            objCon.Open();

            // Sort file name
            Array.Sort(fileEntries);

            // Loop for each files in directory
            foreach (string fileName in fileEntries)
            {
                // Proceed if file name is not empty and file extension is .SQL
                if (!string.IsNullOrEmpty(fileName) && fileName.EndsWith(".sql"))
                {
                    string tsqlScript = string.Empty;
                    using (StreamReader reader = new StreamReader(fileName))
                    {
                        // Reading all lines in file and parse T-SQL
                        tsqlScript = PrepareTSQL(reader.ReadToEnd());

                        // Proceed if content of the file is not empty
                        if (!string.IsNullOrEmpty(tsqlScript))
                        {
                            // Create command object
                            objCmd = new SqlCommand(tsqlScript, objCon);
                            objCmd.CommandType = CommandType.Text;

                            // Execute non query
                            objCmd.ExecuteNonQuery();
                        }
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        if (objCmd != null) objCmd.Dispose();
        if (objCon.State == ConnectionState.Open) objCon.Close();
        if (objCon != null) objCon.Dispose();
    }
}

/// <summary>
/// Prepares the TSQL.
/// </summary>
/// <param name="tsqlScript">The TSQL script.</param>
/// <returns></returns>
private string PrepareTSQL(string tsqlScript)
{
    string retVal = string.Empty;
    try
    {
        // Replace "GO" statement with empty string since GO is not a valid command in ADO.NET
        retVal = tsqlScript.Replace("GO", string.Empty);
    }
    catch (Exception) { }

    return retVal;
}

Get source code here:

The following are four (4) simple steps to update the SQL scripts to SharePointMalaya.Feature.CustomDBInstaller feature folder, build WSP, install and activate the feature:

Step 1: Generate SQL Scripts using MS Server Management Studio

Step 2: Drop the SQL Scripts to either 'Install' or 'UnInstall' folder

  • For SQL Scripts that install database objects, add script files to \12\TEMPLATE\FEATURES\ Customware.CustomDBInstaller\T-SQL\Install feature folder
  • For SQL Scripts that uninstall database objects, add script files \12\TEMPLATE\FEATURES\ Customware.CustomDBInstaller\T-SQL\UnInstall feature folder
  • Use <<SEQUENCENUMBER>>-<<FILENAME>>.sql as script filename to control the execution of SQL Scripts, see below:

Feature2

Step 3: Build WSP

  • Right- click on the Project, select WSPBuilder > Build WSP from the menu (if you don't have WSPBuilder, download and install from CodePlex)

Step 4: Install and Activate SharePoint Feature

  • Install the .WSP file to SharePoint site, at command prompt execute the following commands:
    • stsadm -o addsolution -filename SharePointMalaya.Feature.CustomDBInstaller.wsp
    • stsadm -o deploysolution -name SharePointMalaya.Feature.CustomDBInstaller.wsp -url http://<<SHAREPOINTURL>> -local –allowgacdeployment
  • Go to SharePoint Site Collection Features page (i.e. http://<<SHAREPOINTURL>>:<<PORTNUMBER/_layouts/ManageFeatures.aspx?Scope=Site), activate the SharePointMalaya.Feature.CustomDBInstaller feature:

Feature1