SharePoint App-only Policy Apps

SharePoint App-only Policy Apps

In the new world of Apps for SharePoint 2013 there is an app-only policy available to allow SharePoint Apps to make requests to SharePoint sites, on premise or SharePoint Online, without user intervention if necessary. So why is this so important in the Cloud App Model (CAM)?

Well, one case is where you may have a middle tier of web services which return SharePoint information that is accessible by a specific set of web clients that do not necessarily need the access to the SharePoint repositories directly or may be external systems making updates or retrieving data from SharePoint that may have no authenticated way of calling the SharePoint without that middle tier. In this case the SharePoint App would have the necessary permissions to retrieve or write data back to the SharePoint repositories without the calling application requiring access. The calling application would only need access to the middle tier web services in order to retrieve the underlying repository data. The middle tier could be secured differently, via certificates or Active Directory.

Another instance could be something like a re-occurring timer job that may need to perform some actions on the SharePoint repository on a regular basis e.g. a timer job or possibly a newsletter flyer being emailed based on information held in a SharePoint repository.

So how do we get this app-only policy and SharePoint App bolted together in order to make use of this new feature in the CAM world? It’s actually very simple and in this blog post I aim to provide you with a sample to work with to get you going.

First we need a scenario….

Scenario

A timer job is required to log how many items there are currently in a SharePoint list which require pending actions. An administrator reviews a list which the SharePoint App writes to on a regular basis to inform them of the number of items that are pending actions.

A simple scenario but something to work from to demonstrate the SharePoint App-only policy. For the purposes of making it really simple, I have created a console app sample that uses the app-only policy.

Important Notes

In order to install an App which uses the app-only policy, the user must be a site collection administrator to grant the app-only policy.

Apps that do not make OAuth authenticated calls cannot use the app-only policy. The app-only policy is only available in apps that run out side of SharePoint, provider-hosted or auto-hosted (SharePoint Online) app, basically not apps which are SharePoint-hosted and using the JSOM library.

Steps..

Pre-Requisites

Ensure you include the tokenhelper.cs file in your solution.

Include references to Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime

1)     Register the console app in the site collection (Office 365 or SharePoint On Premise)

https://tenantdomain.sharepoint.com/sites/sitecollection/_layouts/15/appregnew.aspx

Register the details below and ensure you generate the ClientId and Client Secret, also add the app title and app domain as required. There is no re-direct URL required.

SPORegisterAppOnlyPolkicyApp

SPORegisterAppOnlyPolkicyAppConfirm

2)      Browse to the site collection (Office 365 or SharePoint On Premise)

https://tenantdomain.sharepoint.com/sites/sitecollection/_layouts/15/appinv.aspx

3)      Enter the app id (ClientId) generated in the appregnew.aspx page

SPORegisterAppOnlyPolkicyAppPermissions

4)      Enter the permissions xml, references to permission polices can be found here: http://msdn.microsoft.com/en-us/library/office/fp142383(v=office.15).aspx

I allowed the app to have Full Control rights at the web level with the “AllowAppOnlyPolicy” set to “true”.


<AppPermissionRequests AllowAppOnlyPolicy="true" >

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />

</AppPermissionRequests>The app is now registered.

6)      After you click Create you should trust the app that was registered.

SPORegisterAppOnlyPolkicyAppTrustApp

5)      Update your app.config file with the following section and apply the appropriate ClientId and ClientSecret Note that, getting any of these incorrect may cause a 400 bad request. If you debug the error, the tokenhelper.cs will fail at the following code:

<appSettings>

<addkey="ClientId"value="generated ClientId"/>

<addkey="ClientSecret"value="generated ClientSecret"/>

</appSettings>

Bad Request Error: If you debug the error, the tokenhelper.cs will fail at the following code when the tokenhelper class tries to receive a valid OAuth response.


OAuth2AccessTokenResponse oauth2Response;

try

{

oauth2Response =

client.Issue(AcsMetadataParser.GetStsUrl(targetRealm), oauth2Request) asOAuth2AccessTokenResponse;

}

6)  You can also generate the permission request XML by adding a SharePoint App and updating the permission to allow the app to make app-only calls to SharePoint and generate the appropriate scoped permissions. Then you could view the code in the appmanifest.xml file and copy the relevant generated code. If you are new to this I would recommend following this described step.
7)      Add the appropriate code to get a app-only token.


privatestaticvoid Main(string[] args)

{

ServicePointManager.ServerCertificateValidationCallback =

newRemoteCertificateValidationCallback(delegate { returntrue; });

var siteURL = "https://tenantdomain.sharepoint.com/sites/sitecollection";

Uri siteUri = newUri(siteURL);

// Get the realm for the URL

string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);

//Get the access token for the URL

string accessToken = TokenHelper.GetAppOnlyAccessToken(

TokenHelper.SharePointPrincipal,

siteUri.Authority, realm).AccessToken;

// Get client context with access token

using (var clientContext =

TokenHelper.GetClientContextWithAccessToken(

siteUri.ToString(), accessToken))

{

Web web = clientContext.Web;

clientContext.Load(web, w => w.Title);

clientContext.ExecuteQuery();

var title = web.Title;

Console.WriteLine(title);

}

Console.ReadKey();

}

The sample code above displays the web title in the console application.

Getting our pending action items from the documents list

Now lets add the code for the sample to return items from a document library to query pending items.

In the site collection the default document library has 3 items which have a different pending status. The pending column is our flag that an item requires actions. The library items are shown below.

SPORegisterAppOnlyPolkicyAppDocuments

The code required to query the list appropriately can be added in the section where a client context has been generated (clientContent). We use the clientContext with the app-only access token to retrieve the information from the list based on the app permissions specified earlier.

The code has been documented below.

// Get client context with access token

using (var clientContext =

TokenHelper.GetClientContextWithAccessToken(

siteUri.ToString(), accessToken))

{

Web web = clientContext.Web;

// Retrieve the List from the web

List documents = clientContext.Web.Lists.GetByTitle("Documents");

var pendingItemsQuery = @"<View><Query><Where><Eq><FieldRef Name='Pending'/><Value Type='Integer'>1</Value></Eq></Where></Query></View>";

CamlQuery listQuery = newCamlQuery();

listQuery.ViewXml = pendingItemsQuery;

ListItemCollection documentListItems = documents.GetItems(listQuery);

clientContext.Load(documentListItems);

clientContext.ExecuteQuery();

if (documentListItems.Count > 0)

{

Console.WriteLine("Items that have pending actions are listed below");

foreach (ListItem li in documentListItems)

{

Console.WriteLine(li.FieldValues["Title"].ToString());

}

}

else

{

Console.WriteLine("No pending items in documents list.");

}

}

Console.WriteLine("Press any key to exit");

Console.ReadKey();

Returned Console Output

The output of the query is listed below.

SPORegisterAppOnlyPolkicyAppConsoleOutput

The executable can be scheduled using the Windows task scheduler to perform the required functions on a provider hosted server. The app is trusted via OAuth (ClientId and ClientSecret), which registered at the site collection level. To make the deployment easier, you could include a SharePoint app project in the solution and register the app to be deployed to any site collection via the app catalog. Should you need to query more site collections, you could change the scoped permissions to the tenant or deploy the app at each site collection.

A simple solution to have an application query SharePoint sites in Office 365 or SharePoint 2013. The solution can be extended to update a logging list for the administrator to log pending actionable items.The Client side Object Model (CSOM) could be utilized to perform whatever functions are required for any app of this nature.

 

SharePoint 2013 Claims and the Welcome Control

Recently, one of my colleagues wanted to update the SharePoint 2013 welcome control with custom claim values, rather than the default values, when utilizing ADFS SAML claims based authentication. If the signed in users display name is not updated in the all users table on the SharePoint web site, then the welcome control will display the primary encoded format of the user id. For example, if the user was authenticated by a trusted Identity Token Issuer, utilizing the User Principle Name (UPN) as the identifier claim, the format will be as follows:

i:05.t|Trusted Identity Token Issuer Name|UPN

The SharePoint claims encoding article can be found here: SharePoint 2013 and SharePoint 2010 Claims Encoding

If you are also not planning on running a SharePoint user profile import, then setting welcome control display can be a little problematic. One approach is to have a custom control in the master page. The control can update the inner HTML of the welcome control, so that it can display a value from augmented claims. In the example below, I specifically pull out the Claim Type of Email, but depending on your scenario, you could use any valid claim augmented from the SharePoint STS which was originally provided by the identity provider STS.

Please note that you may want to check the user is authenticated first and the claims exist, as per the notes in code below.

            // Cast the Thread.CurrentPrincipal
            IClaimsPrincipal icp = HttpContext.Current.User as IClaimsPrincipal;

            string claimValueforWelcomeControl = "No Claims Found";

            // Access IClaimsIdentity which contains claims
            IClaimsIdentity claimsIdentity = (IClaimsIdentity)icp.Identity;
            // Create a Claims Collection - could use IEnumberable and then LINQ
            ClaimCollection claimsCollection = claimsIdentity.Claims;
            // Grab the type we want to display from the claimsCollection
            if (claimsCollection.Count > 0)
            {
                try
                {
                    foreach (Claim c in claimsCollection)
                    {
                        // Whichever claim type you want from claims to be displayed in the welcome control
                        if (c.ClaimType == ClaimTypes.Email)
                        {
                            // consider checking the claimtype exists in the collection first
                            if (c.Value != null)
                            {
                                // Set the Welcome Control Value to the claim value
                                claimValueforWelcomeControl = c.Value;
                            }
                        }
                    }
                }
                catch (SPException ex)

                {

                    Literal1.Text = ex.ToString();
                }
            }

            try
            {
                ClientScriptManager clientScriptManager = Page.ClientScript;
                StringBuilder sb = new System.Text.StringBuilder();
                if (!clientScriptManager.IsClientScriptBlockRegistered("WelcomeControlUpdate"))
                {
                    
                    sb.Append("<script type=\"text/javascript\">");
                    // **** consider JQuery instead: $(document).ready(function (){"); ****
                    sb.Append("window.onload = function () {");
                    // sb.Append("document.getElementById('zz4_Menu').innerHTML = 'Some Claim Value';");
                    sb.Append("document.getElementById('zz4_Menu').innerHTML = '" + "From Claims: " + claimValueforWelcomeControl + "';");
                    sb.Append("}");
                    sb.Append("</script>");
                    clientScriptManager.RegisterStartupScript(this.GetType(), "WelcomeControlUpdate", sb.ToString());
                }
            }
            catch (Exception ex)
            {
                Literal1.Text = ex.ToString();
            }



SharePoint Development: Custom Web Part Settings

This post briefly covers how to create custom web part settings in your Visual Studio solution.

In the main webPart.CS file add the following settings:

 // Custom WP Setting – English RSS URL

 [Personalizable(PersonalizationScope.Shared),

 WebBrowsable(true),

 WebDisplayName(“English RSS URL”),

 WebDescription(“Enter the English RSS URL”),

 Category(“Custom Web Part Settings”)]

 publicstring ENRSSUrl { get; set; }

 // Custom WP Setting – English RSS URL

 [Personalizable(PersonalizationScope.Shared),

 WebBrowsable(true),

 WebDisplayName(“French RSS URL”),

 WebDescription(“Enter the French RSS URL”),

 Category(“Custom Web Part Settings”)]

 publicstring FRRSSUrl { get; set; }

 Update the createChildControls method:

protected override void CreateChildControls()

{

 Control control = Page.LoadControl(_ascxPath);

 // Reference public properties in visual webpart control

 VisualWebPart1UserControl vswebcontrol = control asVisualWebPart1UserControl;

 // Pass through the values to the web part control

 vswebcontrol.toolPartENRSSUrl = ENRSSUrl;

vswebcontrol.toolPartFRRSSUrl = FRRSSUrl;

Controls.Add(control);

}

Reference the settings in the main web part control class:

public partialclass VisualWebPart1UserControlUserControl

 {

 // Public Properties

 public string toolPartENRSSUrl { get; set; }

 public string toolPartFRRSSUrl { get;set; }

 // Internal strings

 string ENURL = string.Empty;

 string FRURL = string.Empty;

 protectedvoid Page_Load(object sender, EventArgs e)

{

 // Set the string values

ENURL = toolPartENRSSUrl;

FRURL = toolPartFRRSSUrl;

 // Reference the custom web part settings

lblEN.Text = ENURL;

LblFR.Text = FRURL;

}

}

It’s as simple as this !

SharePoint 2010 Document Library Replicator: Part 4

Its been a while since my last post on this solution. The code is almost complete and this is the final update to the current solution. The solution can be downloaded from CodePlex here.

In this post, the code update covers the following areas:

1 – A new method has been added to read the configuration list where we specify source and target document libraries. A new class named SPListOperations was created with a method named queryConfigList to query the replicator configuration list for source and target libraries.

2 – The itemupdated and itemdeleted methods in the solution have been updated to call a method that performs the add and delete operation.

Changes to the Event Receiver methods

///

<summary>

///

 An item was updated.

 ///

 </summary>

 public override void ItemUpdated(SPItemEventProperties properties)

{

 base.ItemUpdated(properties);

replicatorOperation(properties,“Added/Updated”);

}

<summary>

///

An item was deleted

///

</summary>

public override void ItemDeleted(SPItemEventProperties properties)

{

 base.ItemDeleted(properties);

replicatorOperation(properties,“Deleted”);

}

New method to perform the copy/update and delete operations

public void replicatorOperation(SPItemEventProperties properties, string operation)

{

 using (SPSite spsite = newSPSite(properties.WebUrl))

 try

 {

EventFiringEnabled = false;

 if (properties.ListItem.ParentList.Title != “Replicator Logger”)

{

 SPWeb siteForLogger = spsite.OpenWeb();

 // determine target filename – the same as the source

 string targetfilename = properties.ListItem.Name.ToString();

 string SourceLibPath = properties.WebUrl + “/” + properties.ListItem.ParentList.ToString();

 string sourceLibrary = properties.ListItem.ParentList.ToString();

 string targetLibraryFromConfigList = SPListOperations.queryConfigList(siteForLogger, sourceLibrary).ToString();

 // Query the Configuration List

 if (targetLibraryFromConfigList != “NotListed”)

{

 // Copy/Delete the file to the destination library (targetlibrary)

 if (operation == “Added/Updated”)

{

 properties.ListItem.File.CopyTo(targetLibraryFromConfigList + “/” + targetfilename, true

);

}

if (operation == “Deleted”)

{

 SPFile spFileTarget = siteForLogger.GetFile(targetLibraryFromConfigList + “/” + targetfilename);

spFileTarget.Delete();

 }

 // Write to the Replicator Log – unfinished…

 ReplicatorLogger replogger = newReplicatorLogger();

 // Get the current Date and Time

 DateTime dtime = DateTime.Now;

 // Create the title for the logger list item

 string title = (dtime.Date.ToString() + “_” + dtime.Hour.ToString() + “_” + dtime.Minute.ToString() + “_” + dtime.Second.ToString() + “_” + targetfilename.ToString());

// Write to the log list

EventFiringEnabled = false;

replogger.writeToLog(title, dtime.ToShortDateString(), properties.UserDisplayName.ToString(), operation, SourceLibPath, targetfilename, siteForLogger);

}

}

}

catch (SPException spEx) { }

 finally

{

 // Enable Event Firing

 EventFiringEnabled = true;

}

 }

 SPListOperations Class and a new queryConfigList method

using Microsoft.SharePoint;

 namespace DocLibraryReplicator

{

 internal class SPListOperations 

{

publicstaticstring queryConfigList(SPWeb spWeb, string query)

{

 // Build a query.

 string result = “NotListed”;

 SPQuery spQuery = newSPQuery();

spQuery.Query =  string.Concat(“<Where><Eq>”, “<FieldRef Name=’Source Library Path and Name’/>”,“<Value Type=’Text’>” + query + “</Value>”, “</Eq></Where>”);

spQuery.ViewFields = string.Concat(“<FieldRef Name=’Source Library Path and Name’ />”);

spQuery.ViewFieldsOnly = true;

 // Fetch only the data that we need.

 // Get data from a list.

 string listUrl = spWeb.ServerRelativeUrl + “lists/Replicator Configuration”;

 SPList spList = spWeb.GetList(listUrl);

 // result = list.GetItems(spQuery);

 string sourceList = spWeb.Url + “/” + query;

 foreach (SPListItem spItem in spList.Items)

{

 string a = spItem.GetFormattedValue(“Source Library Path and Name”).ToString();

 if (spItem.GetFormattedValue(“Source Library Path and Name”).ToString() == sourceList)

result = spItem[“Target Library Path and Name”].ToString();

}

 }

 return result;

}

 }

 }

 There you have the final pieces which make up the replicator. This solution does not take checking SPFolders into consideraton, but could easily be modified to accomodate this.

SharePoint 2010 Document Library Replicator: Part 3

Today I added the following changes to the solution:

1 – Added a ReplicatorLogger Class to the solution.

2 – Updated the Feature Receiver code to create a Replicator logger list in the Web.

3 – Updated the ItemUpdated method in the Event Receiver to write to the Replicator Logger list when an item is added or updated.

The following code is the new ReplicatorLogger Class:

internal class ReplicatorLogger

 {

publicvoid writeToLog(string title, string logDate, string modifiedBy, string action, string copySource, string fileName, SPWeb web)

{

 // Get the current httpcontext

 System.Web.HttpContext currentContext = System.Web.HttpContext.Current;

 // Set the httpcontext to null;

 HttpContext.Current = null;

 using (web)

{

 try

 {

 // Create an item the Replicator Logger list to record the event

 SPList spList = web.Lists[“Replicator Logger”];

 SPListItem logItem = spList.Items.Add();

logItem[“Title”] = title;

logItem[“Log Date”] = logDate;

logItem[“Modified By”] = modifiedBy;

logItem[“Action”] = action;

logItem[“Copy Source”] = copySource;

logItem[“File Name”] = fileName;

logItem.Update();

 }

 catch (SPException spEx)

{

 }

 finally

 {

 // Set the httpcontext back to the original

 System.Web.HttpContext.Current = currentContext;

}

}

}

}

The following code was added to the Feature Receiver to create the Replicator logger list:

 // Create the replicator logging list

 spWeb.Lists.Add(“Replicator Logger”, “Document Library Replicator Logging List”, spWeb.ListTemplates[“Custom List”]);

 SPList replicatorLoggingList = spWeb.Lists[“Replicator Logger”];

replicatorLoggingList.NoCrawl = true;

replicatorLoggingList.Fields.Add(“Log Date”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Modified By”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Action”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“Copy Source”, SPFieldType.Text, true);

replicatorLoggingList.Fields.Add(“File Name”, SPFieldType.Text, true);

replicatorLoggingList.Update();

 // Update the default view to show the new fields

SPView spLogView = replicatorLoggingList.DefaultView;

spLogView.ViewFields.Add(“Log Date”);

spLogView.ViewFields.Add(“Modified By”);

spLogView.ViewFields.Add(“Action”);

spLogView.ViewFields.Add(“Copy Source”);

spLogView.ViewFields.Add(“File Name”);

spLogView.Update();

The code below updates the Event Receiver to also write the properties to the Replicator Logger list:

public overridevoid ItemUpdated(SPItemEventProperties properties)

{

 base.ItemUpdated(properties);

 using (SPSite spsite = newSPSite(properties.WebUrl))

 try

 {

EventFiringEnabled = false;

 if (properties.ListItem.ParentList.Title != “Replicator Logger”)

{

 SPWeb siteForLogger = spsite.OpenWeb();

 // determine target filename – the same as the source

 string targetfilename = properties.ListItem.Name.ToString();

 string SourceLib = properties.WebUrl + “/” + properties.ListItem.ParentList.ToString();

  // Copy the file to the destination library (targetlibrary)

 properties.ListItem.File.CopyTo(properties.WebUrl + “/” + “targetlibrary” + “/” + targetfilename, true

);

 // Write to the Replicator Log – in test mode…

 ReplicatorLogger replogger = newReplicatorLogger();

 // Get the current Date and Time

 DateTime dtime = DateTime.Now;

 // Create the title for the logger list item

 string title = (dtime.Date.ToString() + “_” + dtime.Hour.ToString() + “_” + dtime.Minute.ToString() + “_” + dtime.Second.ToString() + “_” + targetfilename.ToString());

 // Write the information to the logger list

 EventFiringEnabled = false;

replogger.writeToLog(title, dtime.ToShortDateString(), properties.UserDisplayName.ToString(),“New/Updated Document”, SourceLib, targetfilename, siteForLogger);

}

}

catch (SPException spEx) { }

 finally

 {

  // Enable Event Firing

 EventFiringEnabled = true;

}

}

Here is an example of the item created in the Replicator Logger list when an item is uploaded or updated:

SharePoint 2010 Document Library Replicator: Part 2

In my previous post I demonstrated how easy it was to have a document copied, on upload, to another document library with very few lines of code. This involved utilizing an Event Receiver which performed an override using the ItemUpdated method. This would also support document updates as the code utilized the ItemUpated method.

 Since then I have been working on a feature receiver which that creates a SharePoint list that defines the source and target document libraries for the copy operation.

The ideal approach is to code this so that when the Document Library Replicator feature is activated (the event receiver), we would like the replication configuration list to be created at the same time in the current Web. This has been achieved by created a Feature Receiver within the project that does the following:

1 – Create the “Replicator Configuration” list.

2 – Sets the crawl attribute for the list to none.

3 – Create two text fields for the source and target path and name

4 – Adds the two new text fields to the default view.

The feature receiver only overrides the FeatureActivated method, and does not remove the list when the Document Library Replicator feature is de-activated.

The code for the feature receiver is below:

public class Document_Library_ReplicatorEventReceiver: SPFeatureReceiver

{

.public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

try

{

using (SPWeb spWeb = (SPWeb)properties.Feature.Parent)

{

// Create the replicator configuration list

SPSite spSite = spWeb.Site;

spWeb.Lists.Add(“Replicator Configuration”, “Document Library Replicator Configuration”, spWeb.ListTemplates[“Custom List”]);

SPList replicatorConfigList = spWeb.Lists[“Replicator Configuration”];

replicatorConfigList.NoCrawl = true;

replicatorConfigList.Fields.Add(“Source Library Path and Name”, SPFieldType.Text, true);

replicatorConfigList.Fields.Add(“Target Library Path and Name”, SPFieldType.Text, true);

replicatorConfigList.Update();

// Update the default view to show the new fields

SPView spView = replicatorConfigList.DefaultView;

spView.ViewFields.Add(“Source Library Path and Name”);

spView.ViewFields.Add(“Target Library Path and Name”);

spView.Update();

}

}

catch (SPException spEx)

{

}

finally

{

}

}

}

SharePoint 2010 Document Library Replicator: Part 1

I have been recently working on coding a SharePoint document library replicator. Everytime an item is updated in one library, I wanted to ensure a copy of the updated document is written to another library within the same Web.

Even though I am still working in the final solution, I wanted to share a small code snippet which is a SharePoint 2010 Event Receiver that copies a file from one library to a specified target document library named “targetlibrary”. To perform this basic function the code was very straight forward, and any libraries that get updated would get the file copied to the target library within the Web.

The properties are hard-coded in this sample, but in my final solution I may have a list which manages source and destination library urls. It could also handle and manage SPFolders from the source to the target libraries. I’m also adding a log writer to show the copied files with a timestamp that shows properties such as the last user who edited the file. The log writer will write the information to a SharePoint list.

*** You may want to add some code to skip the block if an update is made to the target library ***

using System;

using System.Security.Permissions;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Security;

using Microsoft.SharePoint.Utilities;

using Microsoft.SharePoint.Workflow;

using System.IO;

namespace DocLibraryReplicator.Document_Library_Receiver

{

///<summary>

/// List Item Events///</summary>

publicclass Document_Library_Receiver : SPItemEventReceiver

{

///<summary>/// An item was added.///</summary>

publicoverridevoid ItemAdded(SPItemEventProperties properties)

{

base.ItemAdded(properties);

}

///<summary>/// An item was updated.///</summary>

publicoverridevoid ItemUpdated(SPItemEventProperties properties)

{

base.ItemUpdated(properties);

using (SPSite spsite = newSPSite(properties.WebUrl))

try

{

// determine target filename – the same as the source

string targefilename = properties.ListItem.Name.ToString();

// Disable Event Firing as the target will try to copy to itself

EventFiringEnabled = false;

 // Copy the file to the destination library (targetlibrary) ** BEWARE ** Target file overwritten with true directive

properties.ListItem.File.CopyTo(properties.WebUrl + “/” + “targetlibrary” + “/” + targefilename, true);

 // Enable Event Firing

EventFiringEnabled = true;

}

catch (SPException spEx) { }

finally { }

}

}

}

Visual Studio 2010 Training – Creating your first Visual WebPart

I’ve created a video to demonstrate how to create a SharePoint 2010 solution with a Visual WebPart in Visual Studio 2010.

The video covers the following training:

1) Creating a SharePoint 2010 Project
2) Creating a Visual Web Part
3) Adding WebPart Controls
4) Adding the WebPart to a Page
5) Enabling some Basic Ajax Extensions in the Web Part

I welcome your feedback, and if you would like to see additional training videos on SharePoint Development I’ll do my best to accommodate your requirements.

SharePoint 2010: Writing User Profile Properties Programatically

Recently I’ve been working on an application which writes custom properties to the User Profile Manager. If you try write profile properties, you may get an error stating that you must allow unsafe updates. The main issue here is the HttpContext needs to be null, but we must store the HttpContext for the session, prior to updating the changes to the user profile manager, and then set the HttpContext back to the original context.

The C# code below enables you to write a user profile property without recieving the error:

currentUser = SPContext.Current.Web.CurrentUser.ToString().Substring(SPContext.Current.Web.CurrentUser.ToString().IndexOf(“\\”) + 1);

SPSite spSite = SPContext.Current.Site;

SPSecurity.RunWithElevatedPrivileges(delegate()

{

System.Web.

HttpContext currentContext = System.Web.HttpContext.Current;System.Web.

HttpContext.Current = null;

try

{

// Set the context of the site to the SPSite site

SPServiceContext context = SPServiceContext.GetContext(spSite);

//Create and instance of the UserProfileManager

UserProfileManager profileManager = newUserProfileManager(context);

UserProfile userProfile = profileManager.GetUserProfile(userName);

UserProfile[propertyName].Value = propertyValue;

userProfile.Commit();

}

catch (SPException ex)

{

}

finally

{

System.Web.HttpContext.Current = currentContext;

}

});

Part 1: Silverlight with a DataGrid – An example for beginners

I have recently been working with a Microsoft Silverlight Visual Studio 2010 project. I wanted to share a very basic Silverlight application as an example for beginners. This example includes a simple button that loads a list of cars into the DataGrid. The car list date is hard coded in a class.  In each additional post I will add more features to the DataGrid. I also intend to move the car list over to SharePoint in the final example and also host the Silverlight application in SharePoint 2010 utilizing the SharePoint Client Object Model.

This is the XAML MainPage.XAML Code:

<UserControl x:Class=”SPSilverlightList.MainPage”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d=”http://schemas.microsoft.com/expression/blend/2008
    xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006
    mc:Ignorable=”d”
    d:DesignHeight=”272″ d:DesignWidth=”462″ xmlns:data=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data” HorizontalAlignment=”Center”>

    <Grid x:Name=”LayoutRoot” Background=”#FF77CEF5″ Height=”264″ Width=”358″>
        <Button Content=”Load Car Data from Cars List” Height=”23″ HorizontalAlignment=”Left” Margin=”90,12,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”180″ Click=”button1_Click” />
        <data:DataGrid AutoGenerateColumns=”True” Height=”180″ HorizontalAlignment=”Left” Margin=”12,52,0,0″ Name=”dataGrid1″ VerticalAlignment=”Top” Width=”324″ Background=”#FF25A4DD”>
        </data:DataGrid>
    </Grid>
</UserControl>

 This is the MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SPSilverlightList
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            dataGrid1.ItemsSource = loadCarListData();
        }

        public class Cars
        {
            public string manufacturer { get; set; }
            public string carModel { get; set; }
            public double engineSize { get; set; }
            public int horsepower { get; set; }
        }

        private List&lt;Cars&gt; loadCarListData()
        {
            List&lt;Cars&gt; cars = new List&lt;Cars&gt;();

            cars.Add(new Cars()
            {
                manufacturer = "Ferrari",
                carModel = "F355",
                engineSize = 3.5,
                horsepower = 375
            });

            cars.Add(new Cars()
            {
                manufacturer = "Porsche",
                carModel = "911",
                engineSize = 2.7,
                horsepower = 130
            });

            cars.Add(new Cars()
            {
                manufacturer = "Astin Martin",
                carModel = "Vanquish",
                engineSize = 6.0,
                horsepower = 520
            });

            cars.Add(new Cars()
            {
                manufacturer = "Lamborghini",
                carModel = "LP700-4",
                engineSize = 6.5,
                horsepower = 700
            });

            return cars;
        }

    }
}

This is the running silverlight application which loads the list on the button click event: