Thursday, October 16, 2008

improve speed of development for SharePoint (part2)

Stop continuously copying your files from your project directory to SharePoint 12

This is one of the chapter of the series Improve speed of development for SharePoint. You will find a complete summary in Improve speed of development for SharePoint Part(1).
When you are developping pages for SharePoint using Visual Studio, you always have to copy it somewhere in the SharePoint 12 directory in order to test it. It would be great if, while working on your project file, your code would be automaticaly copied to the operationnel file in the SharePoint 12 of your development machine when you type a Ctrl + S. So I did it.
Here is the VB .Net code for a Macro you can add to Visual Studio.
Prerequisites: As in a WSPBuilder project, create a 12 directory in your Visual Studio project, and respect the directories you will have in your post deployment environments.
This Macro will test if the file you are going to save is somewhere under the 12 directory, and if so, will save it in your project context of course, but will also copy it to the corresponding directory under the SharePoint 12 of your development machine.
How to install it? Create a Macro in visual studio then replace the module code by the following code, then attach the Ctrl + S Keyboard shorcut to it.
cf.: How to: Record Macros (MSDN)

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module Module1
    Sub SaveTo12()
        Dim myFile As String = DTE.ActiveDocument.Path
        MsgBox(myFile)
        DTE.ActiveDocument.Save()
        Dim maTable() As String
        maTable = myFile.Split("\")
        'MsgBox("matebleLength : " & maTable.Length)
        Dim copyPath As String
        Dim is12Found As Boolean = False
        For i As Integer = 0 To maTable.Length - 2
            If maTable(i) = "12" Then
                is12Found = True
            End If
            If is12Found Then
                copyPath &= maTable(i) & "\"
            End If
        Next i
        Dim _12Path As String = "C:\Program Files\Common Files\Microsoft Shared\web server extensions\"
        copyPath = _12Path & copyPath
        'MsgBox(copyPath)
        If is12Found Then
            'MsgBox(copyPath)
            If Not System.IO.Directory.Exists(copyPath) Then
                System.IO.Directory.CreateDirectory(copyPath)
            End If

            System.IO.File.Copy(myFile & "\" & DTE.ActiveDocument.Name, copyPath & DTE.ActiveDocument.Name, True)
        End If
    End Sub

End Module


Improve speed of development for SharePoint (Part1)

Listenning most of customers I work for, one of the bad point of SharePoint is the time that developments require to customize sites or extend SharePoint in order to give it more complete functionalities.
Customers often forget that if they had to do a SharePoint site from scratch using Asp .Net they would have had to rewrite some of the most appreciated SharePoint functionnalities like document libraries, security manager that can connect to company Active Directory, and so on. Anyway, it is right that sometimes, for a single functionality, it takes much more time to add it to a SharePoint site than to an Asp .Net site.
Why ?
I start writing this post looking for the reasons that makes sometimes a SharePoint project take so long time to be delivered, and in the same time looking for solutions that can improve development speed.
I will write later a chapter about deployment of SharePoint sites and explain that deployment tasks can sometimes take 30 % of the project full time even if you prepare your deployment, and that may take much more time if you don't do, with enormous risks to postpone the planned delivery date.
I also will write about graphical customosation, html + css and javaScript, that is also a big cost of time especially if you don't start well.
However, I prefer for the moment to focus on developement and try to look for practices to improve development speed in SharePoint.

First of all, why development are sometimes taking so much time in SharePoint project comparing to Asp .Net ones?

There is two main reasons:
  1. Most of the server code you will have to write will have to be built before having to be tested.
  2. You will have to deploy the code you've just written on your development machine before testing it.
These numerous operations of building and deployment set a lot of time especially if they come along with IIS reset. If you compare with a Asp .Net project, the developer in the case of a pure Asp .Net, write his client and server code, and test it by just pressing F5 !
So I will try to think about way of developping SharePoint code in order to be as close as possible to the Asp .Net developper experience.
So to avoid the two noticed previous points, there is obvious things to do :
  • using scripts
  • working directly on pages that are below the 12 directory.

- Using Scripts
You can program against WSS Object Model writting in line code in all the pages:
Master Pages
Layout Pages
Applicative Pages
Of course, for the two first type of Pages, it is a temporary solution, because it is not a best practice to use in line code in these pages since this code won't be able to execute if the page is customized.
Anyway, starting writiing your functionality using in line code will make you save a lot of time since you won't have to build your code before testing it. You won't have neither to deploy your dll an have to wait for IIS Reset or Pool Recycling.

So, I post something about script in SharePoint here.

- Avoiding deployment
To avoid deployment you have to develop code on files that are in the 12 directory. Files inside features for master pages and layout pages, file inside Layouts directory for applicative pages.
It would be great if, while working on your project file in Visual Studio, your code would be automaticaly pasted to the operationnel file in the SharePoint 12 of your development machine when you type a Ctrl + S.
So I did it.

Here is the VB .Net code for a Macro you can add to Visual Studio.

Monday, October 13, 2008

Resolve Error : The resource cannot be found

I hope this post will be very usefull for anybody who have to use it because I was so happy myself when I discovered this SharePoint trick completely by chance, and it made me save so much time since this day.
You have sometimes this error while developping a SharePoint application :
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.


Even if you have activated the possibility to see errors and trace in SharePoint (Web application web.config --> callstack="true", customerror="off", debug="true") you won't have a precise indication of what ressource is missing.
So just right click your page and choose "view source".
Bingo! :

Sunday, October 12, 2008

Hide the “Sign in” link in the client web browser for anonymous users


Do you want to hide the sign-in link on your SharePoint sites for your internet users that access it in anonymous authentication mode?
Well, there is one simple and very quick way to do this with 2 scripts in your master page using C# + JavaScript. The effect will be that the link will not be present for anonymous user, but authenticated users will see Welcome and Action menus.

In the head section of your master page place this code :
 <head>
     <script>
      <% 
         Response.Write("var isAuthenticated =" +System.Web.HttpContext.Current.User.Identity.IsAuthenticated.ToString().ToLower() +";");
      %>
     </script>
 </head>
Wrap your menu elements with a container and give it an Id :

         <td id="MenuElements" class="ms-MenuElements"> 
             <wssuc:Welcome id="IdWelcome" runat="server" EnableViewState="false"></wssuc:Welcome>
             <PublishingSiteAction:SiteActionMenu runat="server" />
        </td>

At the end of your master page place this javaScript code :

        <script>
        if(!isAuthenticated){
         document.getElementById('MenuElements').style.display="none";
        }
        </script>
And it's done !
Warning :
Don't forget to replace the in line code in the master page later, by an User Control or a Custom control, as the in line code will fail if the master page is customized...

Choose between the two ways of upgrading a SharePoint solution (.wsp)

There is no question about using or not using a solution (.wsp file) to deploy or upgrade a SharePoint solution. You must use a .wsp.
Anyway, using a .wsp to deploy a solution, there is some points you need to pay attention to :

The way to deploy when upgrading a solution.

There is only one way to deploy the fisrt time, with the stsadm instruction:
  stsadm -o deploysolution ...
But when you want to upgrade a solution there is two ways to do :
  1. With the stsadm instruction stsadm -o upgradesolution
  2. By retracting the solution, removing it, and redeploying it again.

What's the difference ?

  • Renaming your solution in order to make a .wsp versionning
    The second way for instance allow you to rename your solution in the solution store in order to be able to make a versioning of your .wsp.
    With the first way, you will have to keep always the same name for your solution in the solution store.

  • .wsp deployment and feature installation
    Deploying a .wsp make all the features inside to be installed in the farm. Upgrading, not necessary so...
    Asume you deploy a solution. Then you uninstall a feature that was deployed, thus installed with this deployment.
    If you uninstall this feature, it will be NOT reinstalled when upgrading the solution with "upgradesolution" stsadm command.
    However, it will be reinstalled when retracting the solution, removing it, and redeploying it.

Solution files that are shared between several solutions

There is no difference between the two ways of upgrading a solution regarding solution files management. When you upgrade a solution using " upgradesolution" stsadm command, all the files prevously deployed with the solution will be removed, and will be copied again in the required directories if they always are present inside the .wsp. So, what's happenig if two solutions share the same file ?
Asume you have a solution that have deployed a site definition. If you make an other solution to make changes to this site definition and deploy it, the site definitions files will belong to the new soltuion. If you retract and remove this solution, all the site definition files will be removed from your farm !
So you will have to redeploy the first solution to recover your farm originale state.

Sunday, October 5, 2008

Read an XML File inside a SharePoint Feature with simplified XPath using a C# Class

While working with SharePoint Customization using WSS object model, we sometimes need to read XML files. A good way to do it is to use XPath. It is more much usable if you simplify its use by writing a C# Class like the following one :
This class allows you to retrieve a single node value or multiple nodes values :
      public class XMLExplorateur
    {
        protected XPathDocument docNav;
        protected XPathNavigator nav;
        protected XPathNodeIterator xit;
        protected bool initpath = true;
        public XMLExplorateur() { }

        public XMLExplorateur(String path)
        {
            try
            {
                docNav = new XPathDocument(path);
                nav = docNav.CreateNavigator();
            }
            catch
            {
                docNav = null;
                nav = null;
            }
        }
        public bool Init(String path)
        {
            try
            {
                docNav = new XPathDocument(path);
                nav = docNav.CreateNavigator();
            }
            catch
            {
                docNav = null;
                nav = null;
                return false;
            }
            return true;
        }

        public List<string> ValuesOf(String Item)
        {
            List<string> myList = new List<string>();
            if (nav == null) return null;
            String tmp = "descendant::" + Item;
            try
            {
                xit = nav.Select(tmp);
                while (xit.MoveNext())
                {
                    myList.Add(xit.Current.Value);
                }
            }
            catch
            {
                myList = null;
            }
            return myList;
        }

        public String ValueOf(String Item)
        {
            if (nav == null) return "Erreur Navigateur null";
            String tmp = "descendant::" + Item;
            try
            {
                xit = nav.Select(tmp);
                if (xit.MoveNext()) tmp = xit.Current.Value;
                else tmp = "null";
            }
            catch
            {
                tmp = "null";
            }
            return tmp;
        }
    }
And here is the way to use it : I asume the xml file is inside a feature directory and I want to get informations from this file in my feature FeatureActivated method :
                protected XMLExplorateur xe=new XMLExplorateur();
                public override void FeatureActivated(SPFeatureReceiverProperties properties)
                {
                        string[] myDirectoryTable = System.IO.Directory.GetFiles(properties.Definition.RootDirectory + @"\Files");
                        String myFileCompletePath = myDirectoryTable[0];
                        xe.Init(myFileCompletePath);

                        myCustomer.FirstName = xe.ValueOf("Customer/FirstName"));
                        myCustomer.LastName= xe.ValueOf("Customer/LastName");

                        List<string> SalesComments = xe.ValuesOf("Customer/SalesComment");
                        foreach (string aComment in SalesComments)
                        {
                            myCustomer.SalesComments.Add(aComment);
                        }
                }
And of course the used xml file content.
<Customer>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
    <LatestPurchasseDate>05/10/2008 13:37</LatestPurchasseDate>
    <SalesComment id="1">To be called back next week</SalesComment>
    <SalesComment id="2">was very interested by Mr. Smith porposal</SalesComment>
</Customer>
You will find MSDN link to study XPath syntax : here.

Create a SPlist and its SPView in SharePoint writing C# code against WSS object model

How to create a SPlist and its SPView in SharePoint writing C# code against the WSS object model ?

Assume you want to create the list and its view when activating a SharePoint Feature.

        public class myFeatureReceiver : Microsoft.SharePoint.SPFeatureReceiver

        {

            public override void FeatureActivated(SPFeatureReceiverProperties properties)

            {

                using (SPWeb web = properties.Feature.Parent as SPWeb)

                {

                    System.Diagnostics.Debug.WriteLine("Creating the list");

                    //web.AllowUnsafeUpdates = true; //use this in an application page no need in a dll

                    web.Lists.Add("Customers", "Store informations about my Company Customers", SPListTemplateType.GenericList);

                    web.Update();

 

                    System.Diagnostics.Debug.WriteLine("Creating the Fields");

                    SPList myNewList = web.Lists["Customers"];

                    myNewList.Fields.Add("First Name", SPFieldType.Text, false);

                    myNewList.Fields.Add("Last Name", SPFieldType.Text, false);

                    myNewList.Fields.Add("Adress", SPFieldType.Text, false);

                    myNewList.Fields.Add("City", SPFieldType.Text, false);

                    myNewList.Fields.Add("Latest Purchase Date", SPFieldType.DateTime, false);

                    myNewList.Fields.Add("Sales Comments", SPFieldType.Note, false);

                    myNewList.Update();

 

                    System.Diagnostics.Debug.WriteLine("Creating the view");

                    System.Collections.Specialized.StringCollection strColl = new System.Collections.Specialized.StringCollection();

                    strColl.Add("Title");

                    strColl.Add("First Name");

                    strColl.Add("Last Name");

                    strColl.Add("Adress");

                    strColl.Add("City");

                    strColl.Add("Latest Purchase Date");

                    strColl.Add("Sales Comments");

                    myNewList.Views.Add("Summary", strColl, @"", 100, true, true, Microsoft.SharePoint.SPViewCollection.SPViewType.Html, false);

                    myNewList.Update();

                }

            }

        }



References

SPViewCollection.Add Method (MSDN - Microsoft.SharePoint)

Views.AddView Method (MSDN - Views Web Services)