Monday, February 28, 2011

Initial Best Practices & Lessons Learned from Microsoft IT's SharePoint 2010 Upgrade

A pretty good video, should check it out-

Initial Best Practices & Lessons Learned from Microsoft IT's SharePoint 2010 Upgrade


http://technet.microsoft.com/en-us/edge/gg552996
 

Thursday, December 23, 2010

SharePoint 2010 REST services and Silverlight Impersonation

New with SP 2010 comes a Client Object Model, but what makes it tick?  There is a new service layer exposed WCF services.  There are some limitations to the Client Object Model, one of these is the inability to run with elevated privileges.  To avoid this, we are going to connect directly to the services under the Client Object Model, REST services in this case. 

In this example, I will request tasks from a SharePoint Task list in Silverlight.  Nothing fancy, just to show the technique, and also how to connect with impersonated credentials.  This post came from an answer I posted on the MSDN forums.

Silverlight and security – what you should know

Starting with a simple Silverlight Application – The Main View XAML

<StackPanel Orientation="Vertical" x:Name="LayoutRoot">
<Button Content="Click Me" Click="Button_Click"></Button>
<TextBox x:Name="textResults"></TextBox>
</StackPanel>




And the code behind:

private void Button_Click(object sender, RoutedEventArgs e)
{
WebRequest.RegisterPrefix("http://", System.Net.Browser.WebRequestCreator.ClientHttp);
var client = new WebClient();
client.Credentials = new NetworkCredential("user", "password", "domain");
client.UseDefaultCredentials = false;
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://sp2010/_vti_bin/ListData.svc/Tasks"));
}

private void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
Dispatcher.BeginInvoke(() => textResults.Text = e.Result);
}




Now, if you look @ the Uri specified,


“http://sp2010/_vti_bin/ListData.svc/Tasks” – You should be able to browse directly there and get the subscribe/ATOM page.


When the above Silverlight file is run as a SharePoint web part, get the following back.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://sp2010/_vti_bin/listdata.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<title type="text">Tasks</title>
<id>http://sp2010/_vti_bin/ListData.svc/Tasks/</id>
<updated>2010-12-23T04:57:17Z</updated>
<link rel="self" title="Tasks" href="Tasks" />
<entry m:etag="W/&quot;1&quot;">
<id>http://sp2010/_vti_bin/listdata.svc/Tasks(2)</id>
<title type="text">Test 2</title>
<updated>2010-10-30T16:54:55-04:00</updated>
<author>
<name />
</author>
<link rel="edit" title="TasksItem" href="Tasks(2)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CreatedBy" type="application/atom+xml;type=entry" title="CreatedBy" href="Tasks(2)/CreatedBy" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ModifiedBy" type="application/atom+xml;type=entry" title="ModifiedBy" href="Tasks(2)/ModifiedBy" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Attachments" type="application/atom+xml;type=feed" title="Attachments" href="Tasks(2)/Attachments" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Predecessors" type="application/atom+xml;type=feed" title="Predecessors" href="Tasks(2)/Predecessors" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Priority" type="application/atom+xml;type=entry" title="Priority" href="Tasks(2)/Priority" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Status" type="application/atom+xml;type=entry" title="Status" href="Tasks(2)/Status" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AssignedTo" type="application/atom+xml;type=entry" title="AssignedTo" href="Tasks(2)/AssignedTo" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/TaskGroup" type="application/atom+xml;type=entry" title="TaskGroup" href="Tasks(2)/TaskGroup" />
<category term="Microsoft.SharePoint.DataService.TasksItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">2</d:Id>
<d:ContentTypeID>0x0108008CF743378A195C4D9AC3C5A5D0168D42</d:ContentTypeID>
<d:ContentType>Task</d:ContentType>
<d:Title>Test 2</d:Title>
<d:Modified m:type="Edm.DateTime">2010-10-30T16:54:55</d:Modified>
<d:Created m:type="Edm.DateTime">2010-10-30T16:54:55</d:Created>
<d:CreatedById m:type="Edm.Int32">6</d:CreatedById>
<d:ModifiedById m:type="Edm.Int32">6</d:ModifiedById>
<d:Owshiddenversion m:type="Edm.Int32">1</d:Owshiddenversion>
<d:Version>1.0</d:Version>
<d:Path>/Lists/Tasks</d:Path>
<d:PriorityValue>(2) Normal</d:PriorityValue>
<d:StatusValue>Not Started</d:StatusValue>
<d:Complete m:type="Edm.Double" m:null="true" />
<d:AssignedToId m:type="Edm.Int32">6</d:AssignedToId>
<d:TaskGroupId m:type="Edm.Int32" m:null="true" />
<d:Description>&lt;div&gt;Testing&lt;/div&gt;</d:Description>
<d:StartDate m:type="Edm.DateTime">2010-10-30T00:00:00</d:StartDate>
<d:DueDate m:type="Edm.DateTime" m:null="true" />
</m:properties>
</content>
</entry>
</feed>
 

Tuesday, August 31, 2010

Development Servers

I recently built a home development environment, basically an upgrade from what I had. 

The new setup includes 3 physical machines:

  1. Domain Controller / Hyper-V server
    • Intel i7 920 @ 2.67 Ghz
    • Asus P6T – had to install newest Bios update to get the RAM to post
    • Currently 18GB DDR3 1333Mhz Ram (Going to be 24 GB soon enough)
    • OCZ 12 GB Kit – OCZ3G1333LV12GK
    • Corsair 6GB kit
    • RAID 5 – 500 GB WD 7200 rpm drives
    • 2 x 1.5 TB Seagate Data drives
    • Windows Server 2008 R2 x64
      • Domain Controller
      • Hyper V Role
        • Exchange 2010
        • SharePoint 2007 Development Box
        • SharePoint 2010 Development Box
        • CRM
  2. SQL Server
    • Intel Q6600 @ 2.8Ghz
    • Abit Ip35 Pro
    • 8 GB Corsair DDR2 800Mhz RAM
    • RAID 5 – 500 GB WD 7200 rpm drives
    • Windows Server 2008 R2 x64
    • SQL Server 2008 R2
      • Instance for SP2007
      • Instance for SP2010
      • Instance for CRM
      • SSRS/SSIS enabled for each
  3. Workstation
    • AMD FX64 @ 2.6 GHz
    • Asus MB
    • 8 GB Corsair DDR2 800MHz RAM
    • Single 250 GB Seagate 7200 rpm HD
    • Windows 7 x64

The nice thing about the setup? Nothing really has to run on my local machine.  I occasionally run Visual Studio to look at files, or sync my phone with it, etc.  It is a powerful enough dumb terminal for me though.  I browse web pages on it, and really just remote desktop into the dev server I am going to work on.  Another great thing is that I have not really invested all that much into it.  Each time I feel the itch to build a new system (about every year to two) I get a solid motherboard, decent processor, fill half the banks of RAM(depending on price I might fill in all the banks), cheap video card, 1 to 2  hard drives (a 500 GB drive at the time of this article is ~50-60 bucks), a cheap OEM CD/DVD drive, Case (if I need one) and beast of a power supply (usually spend about $100 on a PSU even if it is only 500-600W).  All in all, I am usually only out 500-750 dollars and will reuse some lesser important components from the machine being trashed, or clear it and donate it to a local school/church.  Hard drives are cheap enough these days, I would highly recommend that you replace primary drives every year.  $50 bucks goes a long way to save your photos/documents/etc. 

Rundown of costs to build a new machine from scratch
100-150 Motherboard
100-200 Proc
100-200 Memory
100 – Power Supply
50-100 Hard drive(s)
30-50 Video Card
50 – Case
25 – CD/DVD

Range $555 - $875, again if you save a case, CD/DVD, video card, etc.  you get a decently new machine for a pretty good price.

Thursday, June 3, 2010

SharePoint 2010 Custom Columns now with XSL

If you are familiar with Custom Columns or Custom Fields in SharePoint 2007, they will feel very similar in 2010.  They follow the same basic steps for creating a column/field.  The one big change is that the Rendering template has been deprecated, and replaced with XSL to perform the same task.  This provides much more flexibility, and with a little jQuery, you can accomplish things that were not possible before.

Problem:

I want a list to hold configuration values for my web parts and read the values in when a web part is rendered.  One of the columns/fields in this list would need to be the web part type.  I could have the user type the web part type, but this is too prone for errors.  I want to show a drop down of items of available web parts in the site collection, storing the type, but displaying a user friendly value.  I am going to use SPFieldText for storage, but when looking at the list in a view, I want to show something meaningful.

Solution:

Create a custom field/column definition, add this type to my list to expose currently available web parts.  Create an XSL view to show my field, inserting an ID that I can use with jQuery and the SharePoint JavaScript\ECMA Client Object Model to lookup a friendly name.

Steps:

Create a new Visual Studio SharePoint Project:

image

Select Farm Solution:

image

Add a reference to System.Web:

image

image 

Now we need to add some “Mapped” folders.  Visual Studio 2010 with the addition of SharePoint project types also adds options for mapping to SharePoint folders.  These map to the 14 hive within the WSP and SharePoint will handle placing the files on the filesystems for you.

image

For the first folder, select “Template\XML” - This will house the field definition file.

image 

Add another Mapped folder for “Template\Layouts\XSL” – This will contain the XSL files for rendering our field.

image

Now we need to add a couple of classes. 

1. WebPartField.cs and WebPartFieldControl.cs

image

image

In the WebPartField class mark the class as public, derive from SPFieldText, and add the following:

using Microsoft.SharePoint;



using Microsoft.SharePoint.WebControls;



public class WebPartField : SPFieldText



{



    public WebPartField(SPFieldCollection fields, string fieldName)



        : base(fields, fieldName)



    {



    }



 



    public WebPartField(SPFieldCollection fields, string typeName, string displayName)



        : base(fields, typeName, displayName)



    {



    }



 



    public override BaseFieldControl FieldRenderingControl



    {



        get



        {



            BaseFieldControl fieldControl = new WebPartFieldControl(this);



            fieldControl.FieldName = InternalName; return fieldControl;



        }



    }



}





Save the file.




In the WebPartFieldControl.cs file, mark the class public, derive from BaseFieldControl, and add the following:





using System.Web.UI.WebControls; 



using System.Web.UI; 



using Microsoft.SharePoint; 



using Microsoft.SharePoint.WebControls; 



 



private WebPartField field;                



private DropDownList ddlWebParts;         



public WebPartFieldControl(WebPartField parentField)         



{             



this.field = parentField;             



this.ddlWebParts = new DropDownList();         



}         



 



protected override void CreateChildControls()         



{             



base.CreateChildControls();              



if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)                 



return;              



ddlWebParts = new DropDownList();             



ddlWebParts.CssClass = "ms-long";             



ddlWebParts.ClearSelection();             



ddlWebParts.Items.Clear();              



// we need to fill the drop down list with the values for sites in this site collection.             



foreach (SPListItem webpart in SPContext.Current.Site.GetCatalog(SPListTemplateType.WebPartCatalog).Items)



{                 



ddlWebParts.Items.Add(new ListItem(webpart.Title, webpart.Properties[""].ToString()));       



}            



this.Controls.Add(ddlWebParts);    



}         



public override object Value    



{             get       



{                 EnsureChildControls();    



return this.ddlWebParts.SelectedItem.Value;        



}          



set         



{           



EnsureChildControls();   



ListItem item = ddlWebParts.Items.FindByValue(Convert.ToString(value));  



if (item != null)         



{                  



ddlWebParts.SelectedIndex = ddlWebParts.Items.IndexOf(item);  



}      



}      



}      



public override void UpdateFieldValueInItem()  



{       



this.EnsureChildControls();   



try         



{           



string value = this.ddlWebParts.SelectedItem.Value;      



this.Value = value;                          



this.ItemFieldValue = Value;            



}          



catch (Exception)     



{            



}        



}          



protected override void Render(HtmlTextWriter output) 



{          



try            



{            



// If we are not in edit mode.                 



if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display) 



{                  



if (!String.IsNullOrEmpty(this.ItemFieldValue.ToString()))    



{ 



output.WriteLine(SPContext.Current.Site.GetCatalog(SPListTemplateType.WebPartCatalog).GetItemById(Convert.ToInt32(this.ItemFieldValue.ToString())).Title);



}              



}            



else           



{          



ddlWebParts.RenderControl(output);  



}           



}           



catch (Exception) 



{             



}   



}




You can see in the code above, we are using a DropDownList control to render the web parts for us.  In the Render method, we are only showing the control if the item is in edit mode, otherwise we are showing the Title.



Now we have the fields ready to go in code, but we need to add the definition for SharePoint to pickup.



Right click on the mapped XML folder and select add new item, here we want a descriptive XML file “fldtypes_Custom.WebPartsList.xml”



image



Make sure the name is fldtypes_ or SharePoint will not pickup the field.



In the XML file, we are going to define things like what we want to call the column, description, where to show the column, but most importantly the class that defines it.  Notice in this case, we have the Namespace + Class name, then the token for the assembly name.  This token will gather the Public Key Token, culture, assembly name, etc. so we don’t have to.





<?xml version="1.0" encoding="utf-8" ?>



<FieldTypes>



  <FieldType>



    <Field Name="TypeName">WebPartList</Field>



    <Field Name="ParentType">Text</Field>



    <Field Name="TypeDisplayName">WebPart List</Field>



    <Field Name="TypeShortDescription">WebPart List</Field>



    <Field Name="UserCreatable">TRUE</Field>



    <Field Name="FieldTypeClass">CustomColumn.WebPartList.WebPartField, $SharePoint.Project.AssemblyFullName$</Field>



  </FieldType>



</FieldTypes>




Save the file. 



We are basically done. Notice that RenderingTemplate that was used in previous versions is not included.  We will now create the template to render the item in lists.



Right click on the XSL mapped folder and select add.  We want to create an XSLT file that matches the name of the xml file, just with the XSL extension. fldtypes_Custom.WebPartsList.xsl”



image



In the file add the following:





<?xml version="1.0" encoding="utf-8"?>



<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"



                xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"



                version="1.0"



                exclude-result-prefixes="xsl msxsl ddwrt"



                xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"



                xmlns:asp="http://schemas.microsoft.com/ASPNET/20"



                xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"



                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"



                xmlns:msxsl="urn:schemas-microsoft-com:xslt"



                xmlns:SharePoint="Microsoft.SharePoint.WebControls"



                xmlns:ddwrt2="urn:frontpage:internal">



  <xsl:template match="FieldRef[@Name = 'WebPart']" mode="Text_body">



    <xsl:param name="thisNode" select="." />



    <span class="customWebPartID">



      <xsl:value-of select="$thisNode/@*[name()=current()/@Name]" />



    </span>



  </xsl:template>



</xsl:stylesheet>




You may notice that I have included the class=”customWebPartID”, we will use this in our jQuery to replace the ID that would normally be displayed with the WebPart Title.



Now, let’s go ahead and deploy. Right click on the project and select deploy.



After it has completed, let’s create a list, and assign our field.  It is important to note that the Field added to the list must match the FieldRed[@Name = ‘’] in the XSL above to have it render properly.



image



And let’s add our field.



image



Notice the name of the Field matches the XSL and the new column is shown, this value displayed comes from the TypeShortDescription in the field definition XML file. 



I am going to use the title to store the key, and I am going to create another column for the value of the property. 



Now let’s add an item.



image



image



Obviously there is one issue here, and that is this will only work for your own web parts, but you get the idea.  Now hit save.  You can now see the item you created in your list.



image 



If you inspect the HTML, you will see that the value is contained within a span with out css class defined.



image



So at this point, we have a custom column, where we only store the ID, and in the edit and display forms we show the web part title.  The next step is add  a little jQuery.  Check out my next post to find out how.