Monday, January 19, 2015

Deploying PowerPivot and PowerView for SharePoint 2013 in Single- and Multi-Server farms

Hi! I recently had to deploy PowerPivot and Power View on our SharePoint and found that although single server deployments are well documented, multi-server deployments are not. So I put together a how-to with multi-server (dual-server, in fact) install instructions to PowerPivot and Power View. Hope it helps!

GB 
_________________

Deploying PowerPivot and PowerView for SharePoint 2013 in Single- and Multi-Server farms

Introduction

How to get SharePoint 2013 to show that workbook full of beautiful Power View reports on the browser, with all the nice interactive features?

For that, you need to install and configure Power Pivot (that opens reports in Data Model based workbooks through Excel Services and Analysis Services on SharePoint) and Power View (who displays interactive Power View reports on the browser, also using Excel Services).

The goal of this document is to clarify the "where's" and "why's" to components installation on a dual server farm (1 Web server + App server and 1 DB server), which I suppose it's the most common initial production farm deployment around.

Single-Server Deployment

For single-server deployments there's a MSDN post that covers it completely; it was the base source to my dual server installation:
http://blogs.msdn.com/b/querysimon/archive/2012/11/26/installing-the-bi-features-of-sharepoint-2013.aspx

Multi-Server Deployment

Example Topologies

From [1]:

  1. Single-server: for development and testing.
  2. Separate SQL Server: the most common “adoption topology”.
  3. Shared SQL Server: several small farms can share the same SQL Server/Analysis Services
  4. Large Farm: a large farm.
You can see a natural evolution from 1 to 4 as your farm load increases. The install we will be performing is the Separate SQL Server. The other multi-server topologies are extensions to this one.

What to Install, and Where

We start from an already installed dual server SharePoint farm: the "SharePoint (SP) Server" which acts as Web server and also as an Application server, and the "SQL Server (DB) server", in my case a SQL Server 2012 SP1 cluster.
In The DB Server
Besides SQL Server DB Engine, we will need Analysis Services in SharePoint, or PowerPivot, mode. 
Before the step-by-step, some useful things you may need to know:
  1. To install Analysis Services in SharePoint Mode you need to run SQL Server setup with SP1 or higher slipstreamed. SQL Server 2012 installation media without slipstreamed SP1 supports SharePoint 2010, not SharePoint 2013.
  2. If you, like me, do not have a slipstreamed installation media at hand, you can “slipstream on the fly”: download SP1 (or higher) and follow instructions in [5]. Short version is:
    - Download SP1
    - Run *SQL Server* (not SP1!) setup.exe like this:
    Setup.exe /Action=Install /UpdateEnabled=TRUE /UpdateSource="C:\SQLSP1"
    where “C:\SQLSP1” is the folder where you saved SP1.
  3. If you have a clustered SQL Server instance: SQL Server 2012 cluster does *not* supports PowerPivot for SharePoint ([4]: “SSAS Cluster Design Considerations | SSAS Server Modes”). How do you achieve high availability? SSAS for SharePoint must be installed on several machines (eg: the cluster nodes), as a standalone instance, and your Excel Services, which uses SSAS in SharePoint mode to process Data Models in PowerPivot, must be configured to use those instances, thus balancing the load.
The step-by-step: install Analysis Services in SharePoint mode according to [2], observing the following:
  • In “Step1: Install PowerPivot for SharePoint”, item #14: the account used as Analysis Services service account must have read-only access to the Power View reports or Excel Services will throw a “we cannot locate a server to load the workbook data model” exception when reports are loaded.
  • In “Step 2: Configure Basic Analysis Services SharePoint Integration | Grant Excel Services Server Administration Rights on Analysis Services”, item #3: the login must be added to the Administrators group.
  • In “Step 2: Configure Basic Analysis Services SharePoint Integration | Configure Excel Services for Analysis Services integration”, item #7: the messages will be logged on ULS log only after you try to load a Data Model-based report.
In The SharePoint Server

In our dual-server topology, the SharePoint Server will host the SharePoint Web server component and the Reporting Services Application server as well. Reporting Service is needed as Power View is an add-in to it.
 
Pre-requisites: you need Excel Services up and running on your farm.

The setup on the SharePoint Server is:
  1. Install SQL Server Reporting Services in SharePoint Integrated Mode. Although my farm was not a single server farm, I followed the instrunctions on [6].
  2. Download and install the PowerPivot for SharePoint add-in as in [3].

Conclusion

And that’s it. You can now upload a workbook containing some Power View reports and use them through the browser on your SharePoint site. It’s fairly common the error “"This workbook is larger than the maximum workbook size allowed to be opened in the browser”, because PowerPivot workbooks store a snapshot of the data when reports are first loaded; is this is the case, you can increase the maximum workbook size following [7].

References

[2]   “Install Analysis Services Server in SharePoint Mode for SharePoint 2013 (SQL Server 2012 SP1)”
http://msdn.microsoft.com/en-us/library/jj219067(v=sql.110).aspx
[3]   “Install or Uninstall the PowerPivot for SharePoint Add-in”
http://msdn.microsoft.com/en-us/library/jj218792(v=sql.110).aspx
[5]   “SQL Server 2012 Slipstream Updates Has Changed”
http://cecildt.blogspot.com.br/2012/08/sql-server-2012-slipstream-updates-has.html
[6]   “Install Reporting Services SharePoint Mode as a Single Server Farm”
http://msdn.microsoft.com/en-us/library/47efa72e-1735-4387-8485-f8994fb08c8c%28v=sql.110%29
[7]   “Configure Maximum File Upload Size (PowerPivot for SharePoint)”
http://msdn.microsoft.com/en-us/library/ff487972%28v=sql.110%29.aspx
 


Monday, August 25, 2014

SSRS cmdlets not available: The term 'Install-SPRSService' is not recognized as the name of a cmdlet...

If you get "Install-SPRSService : The term 'Install-SPRSService' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again." trying to enable Reporting Services on SharePoint 2013, the following are possible causes:
  1. You are on a "regular" Windows PowerShell window instead of a SharePoint Management Shell one, or Reporting Services in SharePoint integrated mode is not installed ("Install Reporting Services SharePoint Mode for SharePoint 2013").
  2. Service Pack 1 for SQL Server 2012 is not installed on Reporting Services. According to "Software requirements for business intelligence in SharePoint Server 2013" SP1 is needed for Reporting Services in SharePoint integrated mode on SharePoint 2013.Only after I installed SP1 on SSRS the SSRS cmdlets became available.

Friday, April 11, 2014

My SharePoint PowerShell Scripts

  1. Get the template name and ID for a web site:
    (Get-SPWeb http://website) | select WebTemplate, WebTemplateID
    A list of templates names and ID's can be found here: http://technet.microsoft.com/en-us/library/ff607979(v=office.14).aspx.

Thursday, April 10, 2014

How to Install SharePoint 2013 Project Templates on Visual Studio 2012


  1. Download and install Web Platform Installer: http://www.microsoft.com/web/downloads/platform.aspx.
  2. Close all VS instances or the setup will fail.
  3. On the Web PI select "Microsoft Office Developer Tools for Visual Studio 2012".
After that open VS and the SharePoint 2013 templates should be on the New Project dialog, under Installed | Templates | <language> | Office/SharePoint | SharePoint Solutions.

Monday, March 24, 2014

SharePoint 2013: Configure user profile synchronization service

On the default SharePoint 2013 configuration, the User Profile Synchronization Service (UPSS) is not enabled, so alerts are created but don't work because users don't have a valid e-mail address. Supposing user e-mails are somehow already loaded on AD, here what's you gonna do to configure user profile synchronization:
  1. Follow the article "Synchronize user and group profiles in SharePoint Server 2013" (http://technet.microsoft.com/en-us/library/ee721049(v=office.15).aspx). Notice that the synchronization account must be Farm Admin, and local admin on the box running the UPSS instance.
  2. Use ADSI Edit on the DC to give "Replicate Directory Changes" permission to the synchronization account on the container where your users are.
  3. My test domain had no Exchange or other similar mail server program, so the AD attribute "proxyAddress" was blank. By default SharePoint loads an user e-mail address from this attribute, so I had to remap SharePoint "Work E-Mail" property to the "mail" attribute on AD (which I already had filled). Then run a full synchronization (an incremental one did not load the values).
Cheers,

GB

Wednesday, November 13, 2013

Saving InfoPath form back to subfolder in SharePoint library


Recently I needed to save an InfoPath 2007 ( :-P ) form back to its original location. The original location was on a subfolder inside a SharePoint form library, and the subfolder was created dynamically during form creation time, named based on some data that was not available on the form itself. So there was no way (at least I didn’t see one) I could create a form submit connection that enabled me to save the form back to where it was.

I’ve Googled for a solution and the only one that looked ok was to include the form URL as a field on the form itself, so I could retrieve it later when saving the form back to the SharePoint library. But since the form is running inside SharePoint, and it is an item in a list, I thought I might give it a try to the SharePoint Server API inside the form code behind, and it worked! I used SPWeb.GetListItem() to retrieve the item in SharePoint corresponding to the form, and then used the item’s properties to retrieve its location:

     public void FormEvents_Submit(object sender, SubmitEventArgs e)
     {
         // Retrieves reference to the form in the SharePoint library based on its URL
         SPListItem item = SPContext.Current.Web.GetListItem(this.Uri);
         // Saves the form. There must be a connection on the form named “SaveFile”, pointing to the
         // SharePoint library. In the following code the connection generates the file name, but if the file
         // name must be generated at run-time, it can be set through FileSubmitConnection.FileName
         FileSubmitConnection spConnection = (FileSubmitConnection)this.DataConnections["SaveFile"];
         spConnection.FolderUrl = item.Web.Url + item.File.ParentFolder.ServerRelativeUrl;
         spConnection.Execute();
         e.CancelableArgs.Cancel = false; // Tells InfoPath that form submit was ok
     }

Friday, December 23, 2011

Queue names restrictions on Azure Storage

We got the exception “One of the request inputs is out of range” using a queue to link web and worker roles on Azure. Of course my little prof-of-concept test with code copy-and-pasted from the Azure Tranning Kit ran ok, but the (almost) same code on my app did not. After some time I noticed that the exception was generated when I used upper-case letters on the queue name. Well, the rules for naming queues on Azure are here, but basically they are:

  1. Names can be made of letters, digits and the dash char (-).
  2. First and last chars must be letters ou digits. Consecutive dashes are not allowed.
  3. All letters must be lower case. (Come on, man. You have this kind of restriction and it’s not documented on the API help? Put it in the CloudQueueClient constructor, or in CloudQueueClient.GetQueueReference(), which receives the name of the queue, or at least in CloudQueue.CreateIfNotExists(), since this method creates the queue… :-P)
  4. The queue name length must be between 3 and 63 chars.

Wednesday, July 20, 2011

ReportViewer: Another Reason to “Sys.ArgumentNullException: Value cannot be null. Parameter name: panelsCreated[..]”

If you are stuck with a blank screen when using the ReportViewer control that ships with Visual Studio 2010, check if you provided values for all the parameters in the report. We created a report using {CTRL+C CTRL+V} on an existing report, and the second report used only 3 of the 4 parameters on the original report. We did not provide any value to the last parameter, and it had no default value configured, so the ReportViewer rendered a blank panel on the web form, and generated the following JavaScript error:

Sys.ArgumentNullException: Value cannot be null. Parameter name: panelsCreated[1]

When we edited the report's RDLC file (I could not find the "Report Parameters" menu option that should be under the “Report” menu in Visual Studio, so I opened the RDLC file using Visual Studio XML Editor), and took off the unused parameter defition, the ReportViewer rendered ok. Thanks to this post for pointing me to the right direction.

Wednesday, October 13, 2010

Azure Tables Error Messages

Azure Table Storage (ATS) is a REST-basead data access mechanism, and REST is based on HTTP. So, makes sense that ATS data access errors are returned as HTTP errors. But some translation is needed to understand those errors.

1. DataServiceRequestException and DataServiceClientException exceptions

When a data access error occurs in ATS, the exception returned usually is from DataServiceRequestException class, being the error message “An error ocurred while processing this request”. This exception encapsulates a more specific DataServiceClientException exception, that contains a XML document on the Message property describing the error:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <code>EntityAlreadyExists</code>
    <message xml:lang="pt-BR">The specified entity already exists.</message>
</error>

The value on the <code> element needs to be interpreted considering what the application was doing when the error ocurred. For example, the code InvalidInput is generated if you are trying to save an entity that has a property of an unsupported data type; OR if you are trying to update an entity that has no concurrency control information. Almost the same, right? ;-)

2. Error codes an possible causes

Following are the HTTP error code that we’ve bumped into, and what the application was trying do do when the error ocurred.

Error Code
(value on <code> element)
Possible Causes
ConditionNotMet - Concurrency error. The app read some entity; when trying to modify or delete the entity, it had already been modified by a command from another data context.
EntityAlreadyExists - Primary key violation. The app is trying to insert an entity, but there’s an entity on the table with the same values for PartitionKey and RowKey properties on the entity being inserted.
InternalError - Use of unsupported Linq operators on ATS. (We found this one trying to recover rows that had a string property starting with some value. There’s no string support for like, >, <, and neither string.StartsWith() – the one that generated the error. You have to use string.CompareTo() – :-P)
InvalidInput - Storing an entity that has properties of types not supported by ATS.
- Updating an entity that was attached to the context (TableServiceContext.AttachTo()), but has null on it’s
ETag property.
- Linq queries on a table with no structure defined. We received this error when trying to query a table that had just been created; if you insert some entities, even if you erase all the entities on table later, it seems that the table holds the entity structure and you can use it on Linq queries.
- Linq queries using
anonymous types. The workaround was to make the query return the “whole” entity, and build a second query using anonmymous types on the data returned by ATS.
- Batch save operation (SaveChanges(SaveOptions.Batch)) with 2 or more entities having the same Partion and Row Keys.
ResourceNotFound - Linq query that returns no entitites using equality conditions on PartitionKey and RowKey (where entity.PartitionKey == “…” && entity.RowKey == “…”). (Queries with conditions using other attributes return a 0-sized list)
- Concurrency error. The app read some entity; when trying to modify or delete the entity, it had already been deleted by a command from another data context.
- Linq query on a table that does not exist on ATS.
TableAlreadyExists Found on calls to CloudTableClient.CreateTablesFromModel(). It seems that concurrent calls to this method may end up generating this exception. We placed a call to CreateTablesFromModel() on the data access context static constructor. When we raised the number of role instances to 2, one of them started ok, and the other one generated the exception.
TableBeingDeleted Same as TableAlreadyExists above.
OutOfRangeInput Generated when saving an entity with an uninitialized DateTime property. The minimum allowed value for a DateTime property on ATS is Jan 01, 1601, and an uninitialized DateTime in C# holds Jan 01, year 1. We didn’t detected it on tests against DevStorage because it changes dates before Jan 01, 1753 to Jan 01, 1753, but ATS does not.

3. How to extract the HTTP error code from DataServiceClientException objects

The code is based on an enum that has members named exactly as the error codes returned by ATS:


public enum ATSError
{
    EntityAlreadyExists,
    ConditionNotMet,
    InvalidInput,
    ResourceNotFound, 
    Unknown  // This one is the "generic" error code 
}

The following method extracts the error code from the XML returned by ATS, and converts it on the correspondent ATSError enum value:

/// <summary>
/// Translates an ATS exception to one of the ATSErrors values.
/// </summary>
/// <param name="error">Exception returned by ATS.</param>
/// <returns></returns>
public static ATSError ExtractATSError(Exception e)
{
    // Searches for a DataServiceClientException exception
    while (!(e is System.Data.Services.Client.DataServiceClientException) && (e != null)) 
        e = e.InnerException;
    if (e == null) return ATSError.Unknown;

    // At this point "e" contains a DataServiceClientException object,  
    // and the Message property contains a valid XML document describing the error
    ATSError code;
    try
    {
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(e.Message);
        // The XML document uses namespace http://schemas.microsoft.com/ado/2007/08/dataservices/metadata, so 
        // we have to use a XmlNamespaceManager to represent this namespace
        XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xml.NameTable);
        namespaceManager.AddNamespace("n", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
        // Retrieves the "<code>" element 
        string s = xml.SelectSingleNode("/n:error/n:code", namespaceManager).InnerText;
        // Converts the element value to the corresponding ATSError value
        code = (ATSError)Enum.Parse(typeof(ATSError), s);
    }
    catch
    { 
        code = ATSError.Unknown;
    }
    return code;
}

And that’s it. If you bump into another error code, just add the corresponding member on the ATSError enum, so that the ExtractATSError() method will recognize it.

Tuesday, August 24, 2010

Error on Azure Development Storage startup

Right after you install Azure Tools for Visual Studio, if you try to start the Development Storage service, a command prompt window pops up, then shows a error message in red, then closes so fast you can't even start to read the error message. I've tried to start the Development Storage from a command prompt to see what was the error. But the .lnk file to Dev Storage does not show what is the command to start it.
Tip 1: To start Azure Development Storage from a command prompt, open an Azure Command Prompt (Start > All Programs > Windows Azure SDK > Windows Azure SDK Command Prompt), and then run csrun /devstore.
Ok. Then I could see the error message:
Encountered an unexpected error from the devstore: Unable to start Development Storage.
Error Details: Failed to start Development Storage: the SQL Server instance 'localhost\SQLExpress' could not be found. Please configure the SQL Server instance for Development Storage using the 'DSInit' utility in the Windows Azure SDK.
Nothing like being able to read the error message when you're trying to fix some error. That leads to
Tip 2: After you install Azure Tools for Visual Studio, run dsinit /sqlinstance:sql_instance_name to create the database needed to run Development Storage.
Since I already have a non-named default SQL Server instance, I ran dsinit /sqlinstance:. (dsinit /sqlinstance "colon" "dot"), as "dot" is the name for a default SQL Server instance. Then Dev Storage started up ok.

Thursday, June 17, 2010

Test machine using boot from VHD

Another option to my last post on SharePoint test machine setup is to boot from a VHD file. A VHD is a Virtual Hard Disk, a file that is used as a hard disk on a Virtual PC or Hyper-V Virtual Machine.

I followed the instructions on Marin Frankovic's blog about it, and it was very easy to create an easy-to-rollback, boot-from-vhd test environment. That's what I did:
  1. I used Marin's post to install a fresh Windows 2008 boot.
  2. I then created a differencing vhd based on the new W2K8 boot, using diskpart and running the diskpart command create vdisk file=c:\testdiff.vhd parent=c:\test.vhd maximum=size_in_mb type=expandable (or fixed). This is nice because you can create a initial differencing VHD from a base VHD, put aside a copy of this differencing VHD, and "destroy" your new boot with tests. When you want to rollback the "destruction", just throw away the differencig file your were using, and start with a fresh new copy from the VHD you put aside before.
  3. Next I added the boot entry to this differencing vhd. On a command prompt:
    a. bcdedit /copy generates boot entry copies. There's plenty of references on this, google for some.
    b. Run the following to point the new boot entry to the differencing VHD:
    bcdedit /set {boot_identifier} device vhd=[c:]\path_to_vhd\vdhfile.vdh
    bcdedit /set {boot_identifier} osdevice vhd=[c:]\path_to_vhd\vhdfile.vhd
    bcdedit /set {boot_identifier} detecthal yes
    (the boot identifier is shown when you generate the boot copy with bcdedit /copy. It can also be seen f you run bcdedit with no params)
And that's it. Your tests boots now can use the full power of your machine, RAM & CPU, instead of sharing the (precious) hardware with the host OS, as VM's do. Just remember: boot from VHD is supported only if your OS is W7 Ultimate or Enterprise, or W2K8 R2.

Thursday, March 25, 2010

SharePoint 2010 Test Machine Setup

Some facts on my SharePoint 2010 test environment setup:

1. Some useful links
2. The SharePoint Demonstration Virtual Machine
  • It's a complete test environment for SharePoint 2010, comes pre-loaded with SharePoint Server 2010, Office 2010, SharePoint Designer 2010, an Active Directory domain, Visual Studio 2010, SQL Server 2008 + Analysis & Reporting Services, Exchange Server 2010 (Exchange on a second VM), and several sample sites with data on it. It saves a lot of work.
  • SharePoint 2010 is a *64-bit only* software, so you can't create its VM's on Virtual Server or Virtual PC, since they don't support 64-bits VM's.
    • Since the VM guest operationg system has to be 64-bit, you will have to user Hyper-V, wich only runs on Windows 2008 machines.
    • If you have a desktop that has been more off than on since you got that notebook you are using now, a "lighter" option is to download (free) and intall Hyper-V Server 2008 R2. It's a stripped down version of Windows 2008 designed solely to run VM's and with support for remote VM management (so you will work from the new note ;-). My 3GHz Pentium D (yes, Dual Core, not Core2 Duo) with 6GB RAM could handle the SharePoint 2010 VM reasonably.
Aside from that, you do can install SharePoint 2010 Beta on Windows 7 and Vista (provided that they are 64-bit installations), but it seems too much trouble just for setup a test machine. If you have a Windows 2008 machine, create the VM on Hyper-V, attach the VHD, and that´s it. If not and you have a second machine at hand, go for Hyper-V Server. It took far more time for me to download the Hyper-V Server setup than to get the SharePoint VM running, so that's my suggestion for you.

Note: the only thing I had to change on MS SharePoint Demonstration VM was to fix the virtual network adapter IP address to 192.168.150.1, wich is the address the DNS entries are setup to. and that's it. That took some time to figure out, but not that much... ;-)

Note2: Check out this post too: "Test Machine Using Boot From VHD". Booting from a VHD improves the performance of your test machine, because there's only one operating system running - instead of two, as when you use virtual machines.

Friday, February 26, 2010

SharePoint: The site theme is not applied to my custom page

If you created and/or customized pages in a SharePoint 2007 site, and when changing the site theme this change does not appears on the customized pages, one possible cause is the absence of the ASP.NET server tag that includes site themes on the page. Try placing the following markup on the <head> session of the page:

<SharePoint:Theme runat="server">

This server control writes the <link> tag that includes the selected theme CSS styles on the generated HTML.

Tuesday, February 2, 2010

Using Microsoft.SharePoint.dll to find out the ID of a list

When moving a site between web applications using SharePoint Designer backup (Site > Administration > Backup Web Site menu), several web parts wich had been converted to XSLT were displaying a "strange" message:

The server returned a non-specific error when trying to get data from the data source. Check the format and content of your query and try again. If the problem persists, contact the server administrator.

When an web part is converted to XSLT, SharePoint Designer places on the page a control of type WebPartPages:DataFormWebPart to display the data. This control uses the list ID to specify wich list is the data source (each list in a SharePoint site is given a GUID as its identifier, wich is stored in the list's ID property). Well, when the site was recreated at the destination, so were its lists, and that generated new ID's to them. And the web parts could not find their lists anymore, so they stopped working.

Being a restless geek, I decided to test the classes on Microsoft.SharePoint.dll by coding a little console app that listed the ID's from a SharePoint site lists. The code is bellow, and can be used as an intro to classes in namespace Microsoft.SharePoint. If you want just the app, just download the following file and run it from a command prompt on your SharePoint machine: SPListId.zip.

Imports Microsoft.SharePoint

Module Module1

Sub Main()
Try
Console.WriteLine()
If My.Application.CommandLineArgs.Count = 0 Then
Console.WriteLine("SPListId - Lists IDs from lists in a SharePoint site")
Console.WriteLine("Copyright (c) 2010 SrNimbus. No rights reserved ;)")
Console.WriteLine("Usage: SPListId site_url")
Return
End If
' The System.Uri class helps manipulating network addresses
Dim urlSite As Uri = New Uri(My.Application.CommandLineArgs(0))
' The Microsoft.SharePoint.SPSite class represents a site collection on SharePoint
Dim siteCollection As New SPSite(urlSite.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped))
' The Microsoft.SharePoint.SPWeb class represents a site on a site collection
Dim site As SPWeb = siteCollection.OpenWeb(urlSite.AbsolutePath)
Console.WriteLine("Lists on {0}:", urlSite.OriginalString)
Console.WriteLine("------------------------------------")
' The SPList class represents a SharePoint list
For Each lista As SPList In site.Lists
Console.WriteLine("{0}: {{{1}}}", lista.Title, lista.ID.ToString().ToUpper())
Next
Console.WriteLine("------------------------------------")
Catch erro As Exception
Console.WriteLine("Ooops:")
Console.WriteLine("{0} - {1}", erro.Source, erro.Message)
Finally
Console.WriteLine()
End Try
End Sub

End Module

Remember to add a reference to Microsoft.SharePoint.dll in order to compile the project. It is located on the SharePoint server, at %ProgramFiles%\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI.

Monday, January 25, 2010

SharePoint 2007 Content Deploy Quick Start Guide

And there was I working my 455 off preparing for teach Microsoft´s 50149 SharePoint Operations training when...
A word of advise: stay away from this training. The author tries to show EVERYTHING about SharePoint operations but there's no details on *any* of the topics shown. The result is frustrated and/or distracted students, and that's a saddening thing to me as an instructor - not to mention to the students...
Well, there I was studying the module on Content Deployment when I stumbled upon this guide from Stefan Gossner (great SharePoint blog!). It gives a quick and straightforward view on the main points about Content Deplyment on SharePoint 2007. Nice reading if you are new to the subject. Till now, the guide covers the following:

Part 1 - The Basics
Part 2 - The Basics continued
Part 3 - Configuration
Part 4 - Communication
Part 5 - Quick Deployment
Part 6 - Logging
Part 7 - Change Token Basics
Part 8 - Job and Change Token

Part 1 has an link index to the other parts. Enjoy!

Tuesday, December 29, 2009

Windows Virtual PC: Where is it?

Windows Virtual PC is Microsoft Virtual PC next version. It runs on Windows 7, but it is NOT part of it - you have to download it. The download page is http://www.microsoft.com/windows/virtual-pc/download.aspx, although the page title is "Download Windows XP Mode". You have to fill in the two dropdowns, and the page shows you two links. If you don't want Windows XP Mode, just click the second link, download and install the update to Windows 7 - it's Windows Virtual PC that's being installed.



Before you download it, you have to check if your's computer processor supports hardware virtualization technology (check out the links on Intel and AMD on the article). Most of the newer processors (post 2006-) ship with it. Some don't (for example, the T6670 on my Dell Vostro 1310 does not :-P). You can run the Hardware-Assisted Virtualization Detection Tool from Microsft to confirm that your processor supports VT (virtualization technology). If it doesn't, download Virtual PC 2007, the previous Windows Virtual PC version. It has less features, but it's disks are compatible with Windows VPC.

Thursday, December 24, 2009

Disk space used by an Windows 2003 Clean Install

Old one, but just for the record: a fresh Windows 2003 Standard + IIS + SP2 takes 5.74 Gb on the disk. In case you need to build a VM with that.

Friday, December 18, 2009

SELECT * FROM Table JOIN... ListBox???

A Linq way to retrive rows from one table based on rows from a related table whose lines are loaded into a listbox.

The ASP.NET test WebForm:



I want all products related to the selected categories (ListBox.SelectionMode = Multiple). The project is an ASP.NET Web App on VS 2010 Beta 2, and it contains an Entity Data Model on the Northwind sample database.

The LinkButton code:

    Protected Sub LinkButton1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles LinkButton1.Click
Dim data As New NorthwindEntities
Dim selectedCategoriesProducts As New List(Of Products)
selectedCategoriesProducts = _
(From line As Products In data.Products
Join item As Integer In (From x In ListBox1.Items Where x.Selected = True Select x.value)
On line.CategoryID Equals item
Select line).ToList()
GridView1.DataSource = selectedCategoriesProducts
GridView1.DataBind()
End Sub
The Linq (to Entity) query joins the Products table (data.Products) to a integer list (Join item As Integer). The integer list is generated by a Linq (to Objects) query that selects the values (Select x.value) from the listbox options (ListBox1.Items) that are checked (Where x.Selected = True). The returned Products object list is then shown on the GridView.

In other words, we joined the Products table on Nortwind database with the ListBox selected items from an webform. Well, talk about data source abstraction... :-)

"Linq Is Fun!!!"
Buda On Using Linq To Query Data

Monday, November 9, 2009

Visual Studio: how to target different .NET Framework versions

We are creating a WPF application on Visual Studio 2010 (beta 1), but Blend 3 doesn’t load .NET Framework 4.0 assemblies. So on the designer’s machine we had to compile the solution targeting .NET Framework version 3.5.

(quick thought: our development team is made up of one designer, one product manager, and one project manager. So, WHO IS CODING???)

We found an article on MSBuild – Microsoft’s build engine – about the /toolsversion option, that targets specific .NET Framework versions. We built a .bat file that recompiles all projects in the solution. Following is some of it:

msbuild StorageClient\StorageClient.csproj /toolsversion:3.5 /verbosity:quiet
if ERRORLEVEL 1 goto erro

MSBuild recognizes Visual Studio project files, and activates the corresponding compiler. The /toolsversion option selects the target .NET Framework version (allowed values are 2.0, 3.0, 3.5 and 4.0), and overrides the selected version on the project file. The following “if” checks if MSBuild returned 1, which signals an error, so you can stop the build job (using good(?) old goto).

A lot less painful than I thought. The same batch will be used to generate a 3.5 version of the solution when building the tables on Azure Development Storage, because DevTableGen – the utility that builds the tables – also does not support 4.0 .NET Framework assemblies.

MSBuild location is not included on the standard command prompt path, so use Visual Studio 2010 command prompt (VS 2010 program group > Visual Studio 2010 Tools).

Monday, October 26, 2009

INSERT's inside transactions

Are you a geek? Then read on. :-)

Reading Inside SQL Server 2005: Query Tunning and Optimization, I stumbled upon this beaultiful code sample. The guy (yes, a guy - it seems Ms. Delaney is subcontracting for some chapters...) creates a big sample table with 250,000 rows on it.


And there's not a single shred of comment about the code. He's doing 250,000 INSERT's on a table. In order to optimize it, he opens a transaction right before the loop starts, and on every 1,000 INSERT's he does a COMMIT then opens another transaction. This prevents SQL Server from opening a transaction on each INSERT. (Yes, Luke. When a data modification command to SQL Server you send, a transaction it automatically opens if the command is not already inside one. This allows you, for example, to change your mind and issue a ROLLBACK inside a trigger - even without a preceding BEGIN TRAN).

By using the explicit transactions around the INSERT's, the code runs them on 250 transactions, instead of 250 thousand ones. As I've said before, beaultiful. Simply beaultiful.

And in case you didn't notice: yes, I'm a geek. :-)