Pages

Friday, April 15, 2011

SharePoint Read Only Databases and me as Developer

While working with SharePoint 2010 or SharePoint 2007, there are some scenarios when you want to take your content database of your web application to read only state.
For example when?
That’s a usual question one can ask , and answer is , when you / IT administrators are doing some migrations of your content database to some other system (like we do SharePoint 2007 upgrade to SharePoint 2010 by using database attach upgrade process) , or you / IT administrators are doing some maintenance of your SQL server
Practically doing this, you are making sure that end users are not adding contents to your site while you are working / migrating with content database
and good thing about SharePoint is , when you set your content database to read only state then SharePoint recognizes that and removes / hides all controls which cause any “Add” action to site
Well, you can do this in three ways :
a.    by using stsadm
b.    by using visual studio
c.     by using SQL Server Management Studio (easy for IT admins)
How to do this using stsadm?
Here is simple command which will put your site collection to read only mode and users wont be able to add new content
For read only site:
stsadm.exe –o setsitelock –url http://yoursite/ -lock readonly
for bringing site back to normal :
stsadm.exe –o setsitelock –url http://yoursite/ -lock none


How to do this using Visual Studio? (I love this J )     

static void Main(string[] args)
{
 try
 {
   using (SPSite site = new SPSite("http://yoursite/"))
   {
     site.AllowUnsafeUpdates = true;
     site.ReadOnly = true;
     Console.WriteLine(site.ReadOnly.ToString());
   }
 }
 catch (Exception ex)
 {
     Console.WriteLine(ex.Message);
 }

   Console.ReadLine();
 }


How can I do this as IT administrator?

·         Well that’s a pretty simple task if you having SQL Server Management Studio installed. Here are steps to do this
·         Open SQL Server Management Studio (for example for SQL Server 2008) and connect to the instance of database which is having your SharePoint content databases
·         Once you find your web application’s content database, right click on it and then select properties, now a small pop up window should open
·         in this new window , select Options from left menus and find option Database Read only and set that to true and you are done

Ok this is good so far but what’s in it for me as developer??
Yes interesting question, and obvious answer
while working with SharePoint and customizing / developing on top of SharePoint platform we usually create some web controls, web parts and so on , but one thing we should always consider in aspect of read only databases is , we should disable any “Add” functionality to site when database is in read only state
For example, I have a web part which adds some data to SharePoint list when clicked , and suppose site database is in read only state for some instance ,what will happen? Error isn’t it?
So to avoid this, we should always check database status of site like this

if (!site.WebApplication.ContentDatabases[0].IsReadOnly)
{
  if (!site.ReadOnly)
  {
    //Enable Add/Edit functionality
  }
}
else
{
    //Disable Add/Edit functionality
}

SharePoint 2010 List Events Enhancements

Have you ever worked with SharePoint 2007 List Item Events? If yes then you would have probably noticed that when we attach any event receiver with list then it gets attached at the template level
what I mean is suppose I have created an event receiver for say Calculations List which is basically a custom list (template id = 100) , so in SharePoint 2007 all events will be called for all lists which are created by using  custom list template id = 100
and workaround was that , we were taking help of code to avoid this in SP 2007 , like we can check the name of list every time event receiver gets called and make execution only for desired list
Sample Code:
public override void ItemAdded(SPItemEventProperties properties)
{
  if (properties.ListTitle.Equals("YourList"))
  {
     //here you go          
  }
}
Now to avoid this in SharePoint 2010, framework comes with some enhancements done in Event Receivers section
Now we can associate particular event receiver at Site / Web / List levels and so this is more granular now
 Basically there are three more attributes are added for <Receivers> element and those are
Scope: we can define the scope of Event Receiver to SiteCollection (Site) or Web level
RootWebOnly: event receiver will be attached to all lists under root web created using particular template
ListUrl: we can specify particular list on which Event Receiver will be active (/Lists/MyList/)
Example:
<Receivers ListTemplateId="100" ListUrl="/Lists/CustomList/">
    <Receiver>
      <Name></Name>
      <Type></Type>
      <Assembly></Assembly>
      <Class></Class>
      <SequenceNumber></SequenceNumber>
    </Receiver>
 </Receivers>

Tuesday, March 29, 2011

Export SharePoint List Programmatically

If you try to search on internet on this topic, there are many posts available and each one uses different technique to achieve this
last week, one of my colleague asked me how they can export the SharePoint list content (they were accessing sites remotely) , well answer was quite simple , click on actions tab on list and then select export to spread sheet and save file , but what really puzzled me is , what are other OOB ways available by SharePoint to achieve this other than this option?
I tried searching for this for few hours and ended up with writing a sample console application which exports the list’s default view and write list contents to spreadsheet
Major disadvantage of this is, you cannot run this application when you are not directly working with SharePoint Server, because we are using Server side object model to achieve this
I am keen to see this in SharePoint 2010 environment because we can use Client Object Model to achieve this
But for now here is code I created
I know this code is little heavy (due to those foreach loops) but I thought this is ok as this won’t be running continuously on server


class Program
{

  private static DataTable dataTable;
  private static SPList list;

  static void Main(string[] args)
  {
   try
   {
    Console.WriteLine("Site Url: ");
    string _siteUrl = Console.ReadLine();
    if (!string.IsNullOrEmpty(_siteUrl))
    {
     SPSecurity.RunWithElevatedPrivileges(delegate()
     {
       using (SPSite site = new SPSite(_siteUrl))
       {
         if (site != null)
         {
          SPWeb web = site.RootWeb;

          if (web != null)
          {

            #region Export List

            Console.WriteLine("List Name:");
            string _listName = Console.ReadLine();
             if (!string.IsNullOrEmpty(_listName))
             {
               list = web.Lists[_listName];

               if (list != null)
               {
                 dataTable = new DataTable();

                 //Adds Columns to SpreadSheet
                  InitializeExcel(list, dataTable);

                  string _schemaXML = list.DefaultView.ViewFields.SchemaXml;

                  if (list.Items != null && list.ItemCount > 0)
                  {
                   foreach (SPListItem _item in list.Items)
                   {
                     DataRow dr = dataTable.NewRow();
                     foreach (DataColumn _column in dataTable.Columns)
                     {
if (dataTable.Columns[_column.ColumnName] != null   && _item[_column.ColumnName] != null)
                      {
dr[_column.ColumnName] = _item[_column.ColumnName].ToString();
                      }
                     }
                     dataTable.Rows.Add(dr);

                    }
                   }

                 }
              }

System.Web.UI.WebControls.DataGrid grid = new System.Web.UI.WebControls.DataGrid();

          grid.HeaderStyle.Font.Bold = true;
          grid.DataSource = dataTable;
          grid.DataBind();

          using (StreamWriter streamWriter = new StreamWriter("C:\\" + list.Title + ".xls", false, Encoding.UTF8))
          {
           using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(streamWriter))
           {
             grid.RenderControl(htmlTextWriter);
           }
          }

             Console.WriteLine("File Created");

            #endregion
           }
          }
        }
        });
       }
      }
      catch (Exception ex)
      {
         Console.WriteLine("Error: " + ex.Message);
      }

      Console.ReadLine();
    }

   public static void InitializeExcel(SPList list, DataTable _datatable)
   {
    if (list != null)
    {
     string _schemaXML = list.DefaultView.ViewFields.SchemaXml;
     if (list.Items != null && list.ItemCount > 0)
     {
      foreach (SPListItem _item in list.Items)
      {
       foreach (SPField _itemField in _item.Fields)
       {
        if (_schemaXML.Contains(_itemField.InternalName))
        {
          if (_item[_itemField.InternalName] != null)
          {
           if (!_datatable.Columns.Contains(_itemField.InternalName))
           {
             _datatable.Columns.Add(new DataColumn(_itemField.StaticName, Type.GetType("System.String")));
           }
          }
         }
        }
       }
      }
     }
    }
   }

Wednesday, March 23, 2011

Change PublishingPageLayout of Page Programmatically

After launch of SharePoint 2010 we all came to know that platform is improved heavily in all aspects and some enhancements in web content management too
We can easily change the layout of any Publishing Page using a ribbon in SharePoint 2010
But many of us are still in confusion that how we can achieve this using MOSS 2007? Rather some people think that we cannot change the page layout of page using MOSS 2007, but this is not true
Well, to know how to do this in MOSS 2007, here are some steps
1.    Browse the page for which you want to change page layouts (of course this should be a publishing page)
2.    If you are working with Publishing Site, click on Site Actions and select Show Page editing toolbar (If you are working with custom master pages , and see that this option is grayed out then make sure that you have added PublishingConsole control entry on master page)
3.    Now you will be able to see Page Editing tool bar, now select Page option , a drop down will appear , there you have to select Page Settings and Schedule option
4.    After selecting this you will see a page will be opened, scroll down and find option Page Layout
5.    Now this is where you can apply page layouts to page , select different page layout from dropdown and click ok
I hope now your previous page layout for page gets changed J
but there are some cases I faced where I wanted to change the layout of the page but after doing all these steps when I reached to the page where we can change page layouts , I didn’t find the dropdown filled with other page layouts , so I was not able to change
Now what to do in this case?
Well as developer, we always have code to help us , so decided to do these all using SP object model
And here is the code what I have done, this works for me at least J
Code just tries to open root web, gets collection of pages created with given page layout, searches the given page in this collection, and applies new given page layout the page and done
There can be multiple ways to do this, and code can be modified for more flexibility and according to need


static void Main(string[] args)
{
 #region Variables

 string _siteUrl = string.Empty;
 string _pageName = string.Empty;
 string _pageLayouts = string.Empty;
 string _newPageLayout = string.Empty;
 string _responce = string.Empty;
 PublishingPageCollection _pages = null;

 #endregion

 try
 {
   Console.WriteLine("Site Url: ");
   _siteUrl = Console.ReadLine();

   if (!string.IsNullOrEmpty(_siteUrl))
   {
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
      using (SPSite site = new SPSite(_siteUrl))
      {
        using (SPWeb web = site.RootWeb)
        {
          if (web != null)
          {
           if (PublishingWeb.IsPublishingWeb(web))
           {
             PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
             Console.WriteLine("Search Pages with Layout: ");
             _pageLayouts = Console.ReadLine();

             if (!string.IsNullOrEmpty(_pageLayouts))
             {
string query = @"<Where><Contains><FieldRef   Name='PublishingPageLayout' /><Value Type='URL'>" + _pageLayouts + "</Value></Contains></Where>";
                 
_pages = pWeb.GetPublishingPages(query);
             }

             do
             {
              if (_pages != null)
              {
               Console.WriteLine();
               Console.WriteLine("Search Page With Name: ");
               _pageName = Console.ReadLine();

               //LINQ to get actual page for processing
PublishingPage _desiredPage = _pages.Where(p => p.Name.ToLower().Contains(_pageName.ToLower())).FirstOrDefault();

                                              

   if (_desiredPage != null)
               {
                if (_desiredPage.ListItem.File.Level != SPFileLevel.Checkout)
                {
                                                        Console.WriteLine("Processing.." + _desiredPage.Name);
                                                        _desiredPage.ListItem.File.CheckOut();

                  Console.WriteLine("which Page Layout to apply?");
                  _newPageLayout = Console.ReadLine();

_desiredPage.ListItem["PublishingPageLayout"] = @"/_catalogs/masterpage/" + _newPageLayout;
                                                        _desiredPage.ListItem.Update();

_desiredPage.ListItem.File.CheckIn(string.Empty);

                  if (pWeb.PagesList.EnableMinorVersions)
                  {
_desiredPage.ListItem.File.Publish("Page Layout Changed..");
                  }
                   if (pWeb.PagesList.EnableModeration)
                   {
_desiredPage.ListItem.File.Approve("Approved by Console Application");
                   }

                   Console.WriteLine("Page Layout Updated");

                   Console.WriteLine("do you want to continue?");
                    _responce = Console.ReadLine();

                  }
                else
                {
Console.WriteLine("Page is already Checked out to user " + _desiredPage.ListItem.File.CheckedOutBy.Name);
                }
               }
               else
               {
                 Console.WriteLine("Page Not Found!!");
               }
              }
             }
while (_responce.ToLower().Equals("y") || _responce.ToLower().Equals("yes"));

            if (pWeb != null)
            {
              pWeb.Close();
            }

           }
          }
        }
       }
      });
     }
     else
     {
      Console.WriteLine("Invalid Site Url");
     }

    }
    catch (Exception ex)
    {
      Console.WriteLine("{0}:{1}", "Error", ex.Message);
    }

     Console.ReadLine();
   }