Pages

Thursday, February 10, 2011

SharePoint Variations – How they did Variation Landing Page – Part 1

When we talk about SharePoint Variation, we usually get thought of making sites multilingual. Yes that’s correct.
I will not be describing all in depth of Variations like how Variations can be set up and about installing language packs, there are many well articles which describes this in details
What I am really interested in putting forward is , how SharePoint Variation Redirections happens?
it all starts from creating Variations hierarchies
when all Variations labels are set up and one presses create site hierarchies link then SharePoint creates a timer job called as Variation Create Site Hierarchies job (SharePoint 2010) , what this job internally does is          ( I tried using reflector here for internals)  it creates variation sites in different languages referring to web temp files in 14 hive (according to language installed) and also creates a page called as VariationRoot.aspx
now this VariationRoot.aspx page is set as welcome page for the site , idea here is to expose this page to all users and do some action as soon as user visits this page and redirect them to actual variation site url , doing this we never practically see or visit VariationRoot.aspx but directly gets redirected to Variation Site
What VariatonRoot.aspx has?
Well, If we see what VariatonRoot.aspx has then I figured out that this page is provisioned by using page layout called as VariationRootPageLayout.aspx
What VariationRootPageLayout has?
Now into more deeper dive.. This page layout contains a use control called as VariationRootLanding.ascx
Actual process of redirection in done in this control
I will explain how
 This is generally a browser culture identification approach . When request comes to this page then user control tries to get the culture preferences of user’s browser and tries to redirect user to nearest available variation site




Code:
Control maintains two Dictionary objects on each page load of landing page
Dictionary<string, string> cultureCodeToUrlMapping = new Dictionary<string, string>();

Dictionary<string, string> cultureCodeStrippedToUrlMapping = new Dictionary<string, string>();
First dictionary object contains the actual language culture code as key and variation site url as value
                                                Key                        Value  
Example:                               en-US ,           http://www.test.com/English
                                             fi-FI,              http://www.test.com/Finnish
                                             de-DE ,           http://www.test.com/German
so this is primary criteria on which just a simple check is done on requesting browser’s culture and searched in dictionary object

Second dictionary object contains stripped culture code and url mapping

Example:                                en ,               http://www.test.com/English
                                              fi ,                http://www.test.com/Finnish
                                              de ,               http://www.test.com/German

Why this is needed now?
Suppose I have variation site with culture en-US and user’s browser requesting culture as en-IN then what to do in this case?
If exact key is not found in first dictionary object then SharePoint searches in second dictionary object with stripped  key to redirect users to possibly closest culture variation site
so in this case users with browser culture en-IN will be redirected to en-US variation site
so basically this is the concept used in OOB VariationRootLanding user control , in next part I will write something on how we can customize this or create our custom VariationLandingPage

Tuesday, February 8, 2011

Changing Welcome Page of SharePoint site Programmatically

While working with publishing sites, I came across the point where I wanted to change the welcome page of the site
well the first thing which comes to our mind is to use server object model and make use of Publishing APIs and yes that’s correct , now second thought we generally plan like to get Publishing Web object and set Default Page url .. But note that Default Page property of Publishing Web is read only
So I tried some googling and came across some results and tried one and modified some code
I took help from buddy reflector to see how Microsoft has done this in some cases
Here is the sample code which I made and works fine for me
namespace ChangeWelcomePage
{
 class Program
 {
  static void Main(string[] args)
  {
           
   try
   {
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
     using (SPSite site = new SPSite("http://siteName:port"))
     {
      using (SPWeb web = site.OpenWeb())
      {
       web.AllowUnsafeUpdates = true;
       if (PublishingWeb.IsPublishingWeb(web))
       {
        PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);

        if (publishingWeb != null)
        {
         SPFolder rootFolder = web.RootFolder;
         SPFolder pagesFolder = publishingWeb.PagesList.RootFolder;

         try
         {
         //Ensuring Root Folder
          if (rootFolder != null)
          {
            //Ensuring Pages Root Folder
            if (pagesFolder != null)
            {
              string newWelcomePageUrl = publishingWeb.PagesList.Title + "/" + "YourPage.aspx";
              rootFolder.WelcomePage = newWelcomePageUrl;
                                               
              if (newWelcomePageUrl.StartsWith(pagesFolder.Url, StringComparison.OrdinalIgnoreCase))
              {
                pagesFolder.WelcomePage = newWelcomePageUrl.Substring(publishingWeb.PagesList.RootFolder.Url.Length + 1);
                                                    pagesFolder.Update();
              }

                 rootFolder.Update();
                 web.Update();
                 publishingWeb.Update();
                 Console.WriteLine("done");
             }
            }
        }
     catch (Exception ex)
     {
       Console.WriteLine(ex.Message);
     }
     finally
     {
       if (publishingWeb != null)
       {
         publishingWeb.Close();
       }
     }
    }

   }

    web.AllowUnsafeUpdates = false;
   }
   }
  });
   Console.ReadLine();
 }
 catch (Exception ex)
 {
     //handle exception
 }
 }
 }
}


Thursday, January 20, 2011

Security Validation for this page is invalid......

I was working with SharePoint 2010 Modal dialogs for first time and was showing my custom application page in modal dialog
My application page was using custom master page and there were some buttons on my custom application page which were causing post back and doing some changes in user profile (basically accessing SharePoint site)
After everything was set up and I was ready to test.. and guess what .. After clicking on those buttons I was getting error like .. Security Validation of this page are invalid.. after some google I quickly got some results about this error and some post were quite useful
Firstly I got some posts which were describing about this error like, we should add web.allowunsafeupdates = true; in the code but this was not the case in my situation
After some more results I found that we should have to have <SharePoint:FormDigestControl> included on our page layout / master page and error was solved
You need to register assembly like this
<%@ Register
   Tagprefix="SharePoint"
   Namespace="Microsoft.SharePoint.WebControls"
   Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
And then add control
There is already placeholder for this control in SharePoint master page by default, but If you are using your own master page then you should make sure that you add this control
<SharePoint:FormDigest ID="MyFormDigest" runat="server"/>
What this control is all about?
Well.. msdn says that,
The FormDigest control generates a security validation, or message digest, to help prevent the type of attack whereby a user is tricked into posting data to the server without knowing it. The security validation is specific to a user, site, and time period and expires after a configurable amount of time. When the user requests a page, the server returns the page with security validation inserted. When the user then submits the form, the server verifies that the security validation has not changed.
For more Information: Here

Creating List Using List Definition Programatically



Let’s have a look at how we can create custom list by using our own List Definition
There is <ListTemplate> element using which we can easily create our own list definition.          Andrew Connel has explained this very well in this post
But this is something different approach I wanted to use with our own list definitions
After creating List Definition I didn’t want to add List Instance to the solution because if we do so, then it creates a list with based definition automatically when feature gets activated.
I wanted to have a control over creation of this list which will be based on our custom List Definition. Which puzzled me..
Then I found a way to achieve this by using object model.. I don’t know yet If there are multiple ways to do this but this one was perfect choice for me and worked very well J
When we create a List Definition then we have a feature which provisions list definition
Note that GUID used here in code is Feature Id of the feature which provisions the list definition.
Also : please take into consideration that there are some methods in server object model available for creating a list using list templates directly , but this was something different than list templates, so this approach was preferred , because List Templates are stored into the content database while list definitions resides on actual file system of the server


try
{
  SPList list = null;
  using (SPSite site = new SPSite("http://yoursite/"))
  {
     using (SPWeb web = site.RootWeb)
     {
      //List Will be Created Based on this ListDefinition
- OOB Custom List Definition
      //00BFEA71-DE22-43B2-A848-C05709900100

        foreach (SPList _list in web.Lists)
        {
          if (_list.Title.Equals("TestList"))
          {
              list = _list;
          }
        }

        if (list == null)
        {
         web.AllowUnsafeUpdates = true;
         Guid listID = web.Lists.Add("TestList", //List Title
                      "This is Test List",      //List Description
                      "Lists/TestList",         //List Url
                      "00BFEA71-DE22-43B2-A848-C05709900100", //Feature Id of List definition Provisioning Feature – CustomList Feature Id
                      100,                     //List Template Type
                     "101");      //Document Template Type .. 101 is for None

           web.Update();
           web.AllowUnsafeUpdates = false;
                           
         }
        }


     }
    }
    catch (Exception ex)
    {
      
    }

this is the way to do this and works fine :)
I hope some one finds this useful..

Monday, October 18, 2010

SharePoint Auditing – Behind Screen and Remedy



 Hi,
from past few days I was on my way (as usual) and exploring SharePoint Server 2007 Features and so came across Auditing.
as name suggests , Auditing in MOSS 2007 is basically keeping an eye over your target users actions. what I mean is you can audit the events like what end users has viewed , downloaded , checked in , checked out from your site. and more granularly this can be done at the Item Level and so you called ItemLevelAuditing in MOSS 2007. you can have a look at this link for primary idea how and what Auditing and reporting is done.
so I came to know that , the Audited data gets saved in the Content db of the site collection so I headed forward and opened SQL Server Management Studio. there you can see the db Table Name : AuditData
what was surprising me that If one configures MOSS to audit all the OOB supported events then this might blot up the size of content db and can cause some trouble for public facing sites where you don't know how many end users you going to have for your site
when you open AuditData table and try to see some entries then SharePoint adds the event types and item types in some columns as numbers
I opened up faithful buddy reflector to see what those really are and here you can find those
Item Types
    Document = 1,
    Folder = 5,
    List = 4,
    ListItem = 3,
    Site = 7,
    Web = 6
now, suppose each audit entry requires space appx 64Kb of size per request then supposing 10000 users per day, so at the end of the day content db size only for AuditData table will be at least 64000KB(64MB) which is quite large.
there need to be something to have control over this one : and Microsoft has provided a remedy
there is something called as TrimAuditLogs. this is a stsadm operation and gives control to farm administrators to maintain the audit entries. administrators can run this command and trim the audit logs older than provided date
stsadm -o trimauditlog –date 20080704 –databasename WSSContent123456 
Note that : This operation is available after the Infrastructure Update for Microsoft Office Servers is installed.
so what If you don't have installed the required update?
nothing to worry .. developer can always find a way .. :)
Microsoft’s SharePoint Server object model provides number of APIs where you can do the stuff as you want
here is something small what I tried to delete all the old audit log entries in the db


try
{
      using (SPSite site = new SPSite("http://yoursite
"))
       {
            SPAudit auditE = site.Audit;
            auditE.DeleteEntries(DateTime.Now.AddMilliseconds(1));    //Microsoft Recommended
            Console.WriteLine("Entries Deleted");
       }
}
 catch (Exception ex)
  {
       Console.WriteLine(ex.Message);
   }
 Note that : SPAudit.DeleteEntries is a audit event so delete Audit Log will be written in db even If you delete all entries and this entry will not be deleted

you can play further with these APIs and have fun :)
Refn: here

SharePoint Fields – AddingFieldAsXML strange?

Hi,

I was bit happy after knowing that we can also add FieldAsXml in SharePoint but when I came to know something strange while using this method then that made me a puzzle ..

what basically this all about is :

when we add any field using this method then SharePoint just forgets to set Internal Name of the Field ,
Bil Simser has come up with a work around which makes things OK

I also heard somewhere that this issue is still there with SharePoint 2010 APIs .. 
I would surely like to hands on it using SP2010 as soon as I touches SP 2010 (heavy Infrastructure ;)) environment

Friday, October 15, 2010

SharePoint - AddingFieldAsXML

Hi,

I was basically trying to hook up a SharePoint Field to the one of document library of my site , I know there are different approaches like using UI, writing code.. that one can follow to add desired field directly
but here is something new I came across , Adding Field as XML..:)
what this approach is all about? this is like a creating a Site Column (Field Element) by using feature (I hope I am right)
we can  create a field on the fly and provide some attributes like ID, Type, DisplayName, Name, Required….
this is what I did for attaching a Note Type Field to one of doc Lib

using (SPSite site = new SPSite(http://YourSite))
{
   using (SPWeb web = site.RootWeb)
   {
      SPList docList = web.Lists["Documents"];
      if (docList != null)
      {
         XmlDocument doc = new XmlDocument();
         XmlElement xmlElement = doc.CreateElement("Field");
         xmlElement.SetAttribute("ID", "0F7A6C90-8715-4aa7-90FE-3491DC8953C7");   //ID can be any GUID        
         xmlElement.SetAttribute("Type", "Note");
         xmlElement.SetAttribute("Name", "UserNote");
         xmlElement.SetAttribute("DisplayName", "UserNote");
         xmlElement.SetAttribute("Required", "FALSE");

         docList.Fields.AddFieldAsXml(xmlElement.OuterXml);
         docList.Update();
                           
         Console.WriteLine("Added Field As XML");
      }
   }
}