Showing posts with label SP2010. Show all posts
Showing posts with label SP2010. Show all posts

Thursday, March 7, 2013

InfoPath - People Picker Control

Recently I have had the opportunity to deep dive into K2 project where the InfoPath form needed some validation for a valid user and display the current user email.

Well, after scratching my head for a long time I found that this was not something very complex.
All you need to do is the below


  1. Validate User Control :
     InfoPath 2010 comes with Out of box. To add this control in InfoPath 2003 please click here : Contact Selector - Infopath 2003





  

 

Specifying a valid SharePoint site to fetch the existing users and Sharepoint Groups

This Picker controls connects to the SharePoint site the infopath form has been published to.
If the form has not been published to a SharePoint site the settings of the the SharePoint site need to be specified as below
  1. Right-click the control in the view and select Person/Group Picker Properties from the context menu
  2. In the Person/Group Picker Properties dialog, select the SharePoint Server tab
  3. Type the URL of the SharePoint site you want to query




Mandatory field property can be set as below:






A perfect validation is all we need!

You can check for free text validations


 You can search for the user



It validates if a wrong entry is encountered similar to the SharePoint People Picker control.

Tuesday, February 26, 2013

Export to excel Link ...


Today I ran into a scenario where requirement was to NOT use the ribbon to export the list to excel but access it via the left navigation.

After some research I could find a way to do this:

http://[Server]/[Site]/([Subsite]/)_vti_bin/owssvr.dll?CS=109&Using=_layouts/query.iqy&List=[ListGUID]&View=[ViewGUID]&CacheControl=1

Replace the [Placeholders] with your specific values.

One way to get the list and view GUIDs is to go into "List settings" then scroll down to the views section and click on the view that you want to use.

Here is an example:
http://development004:100/_layouts/ViewEdit.aspx?List=%7B9B8241B3%2D7F09%2D4F45%2DBEE3%2D755E3F7C3FE4%7D&View=%7B70A055C3%2DAEAD%2D4006%2DAB79%2D93D3E700EEC4%7D

Breaking the above :

List=%7B9B8241B3%2D7F09%2D4F45%2DBEE3%2D755E3F7C3FE4%7D

View=%7B70A055C3%2DAEAD%2D4006%2DAB79%2D93D3E700EEC4%7D


Another Tip :
If you are getting the error displaying the list in Data sheet view download and install
http://www.microsoft.com/en-us/download/details.aspx?id=23734

Monday, January 28, 2013

Send email in Sharepoint - Explore Options!

Today I am going to explore options we have to send emails in SharePoint. I find it very interesting that there are a couple of ways to send emails. Sending notifications is a very frequently asked feature from the clients in any application and SharePoint has an out of box feature called alerts.

MSDN - Alerts Details



Option 1:

Store the SMTP server address in the web.config and can utilize the send email function as below:

This ensures that you get the advantages of.NET-style mail delivery while keeping your configuration at one place in your Central Administration.
 
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Net.Mail;
using Microsoft.SharePoint;

namespace Send_Email.Send_Email
{
    public partial class Send_EmailUserControl : UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            bool sentemail = SendMail("Hello", "Test Body", false, "pallavi.sharma@xyz.com", "pallavi.sharma@neudesic.com", "", "");
        }
        public static bool SendMail(string Subject, string Body, bool IsBodyHtml, string From, string To, string Cc, string Bcc)
        {
            bool mailSent = false;
            try
            {
                SmtpClient smtpClient = new SmtpClient();
                smtpClient.Host = SPContext.Current.Site.WebApplication.
                OutboundMailServiceInstance.Server.Address;
                MailMessage mailMessage = new MailMessage(From, To, Subject, Body);
                if (!String.IsNullOrEmpty(Cc))
                {
                    MailAddress CCAddress = new MailAddress(Cc);
                    mailMessage.CC.Add(CCAddress);
                }
                if (!String.IsNullOrEmpty(Bcc))
                {
                    MailAddress BCCAddress = new MailAddress(Bcc);
                    mailMessage.Bcc.Add(BCCAddress);
                }
                mailMessage.IsBodyHtml = IsBodyHtml;
                smtpClient.Send(mailMessage);
                mailSent = true;
            }
            catch (Exception) { return mailSent; }
            return mailSent;
        }

    }
}


  If the SharePoint context is not available utilize the SPWebApplication reference from a new SPSite object :

public static string GetSharePointMailService(string mysite)
 {
 string address;
 using (SPSite site = new SPSite(mysite))
 {
 address = site.WebApplication.OutboundMailServiceInstance.Server.Address;
 }
 return address;
 }


Option 2 :

Utilize the embedded SharePoint SendEmail. This has reduced capabilities, but is as straightforward as possible, and is the preferred approach if you simply want to send e-mail.

SPUtility.SendEmail(web, useHtml, htmlEncode, to, subject, htmlBody)


 Option 3 :

Sending E-Mail from a WCF Service

try
 {
 using (SPSite site = new SPSite(“http://server name”))
 {
 SPWeb myWeb = site.RootWeb;
 {
 string to = “someone@Someone.com”;
 string subject = “My Subject Message”;
 string body = “My Message Body”;
 HttpContext curCtx = HttpContext.Current;
 HttpContext.Current = null;
 bool success = SPUtility.SendEmail(myWeb, true, true, to, subject, body);
 HttpContext.Current = curCtx;
 }
 }
 }
 catch (Exception ex)
 {// handle error here!!!}

In office 365, you have ability to use SANDBOX solutions so the above classes are not supported. I used this trick to send email in the online environment using Sharepoint designer workflows


Option 4:

Use SP Designer to create email notifications. Quick and Easy and can be conditional too.



You could also create a reusable workflow for a content Type and associate with any list which contains that content type.


 

Tuesday, January 15, 2013

Performance Matters - SP2010!

I was researching about the performance in SP2010 and got this rich content of some really good to do's and not to do's which I would like to share.

Why Dispose?

Several of the SharePoint Foundation objects, primarily the SPSite class and SPWeb class objects, are created as managed objects. However, these objects use unmanaged code and memory to perform the majority of their work. The managed part of the object is much smaller than the unmanaged part. Because the smaller managed part does not put memory pressure on the garbage collector, the garbage collector does not release the object from memory in a timely manner. The object's use of a large amount of unmanaged memory can cause some of the unusual behaviors described earlier. Calling applications that work with IDisposable objects in SharePoint Foundation must dispose the objects when the applications finish using them. You should not rely on the garbage collector to release them from memory automatically.
 
Do not instantiate an SPWeb, SPSite, SPList, or SPListItem object within an event receiver.

Event receivers that instantiate these objects instead of using the instances passed via the event properties can cause the following issues:
  • Significant additional roundtrips to the database (one write operation can result in up to five additional roundtrips in each event receiver).
  • Calls to the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.
If you do not retrieve SPWeb, SPSite, SPList, or SPListItem objects from SPItemEventProperties and instead instantiate those objects within an event receiver, when you call Update on the new instances, you must clear it with the Invalidate method in the appropriate child class of SPEventPropertiesBase (for example, SPItemEventProperties.InvalidateListItem or SPItemEventProperties.InvalidateWeb).

Avoid creating and destroying objects unnecessarily in code, as this may require that extra queries be made against the database and may even involve code that is incorrect.

To return a single item from a collection, always use a Get* method when one is provided through a parent object, instead of iterating through the entire collection and using an indexer. For example, the SPWeb class provides GetFile, GetFolder, and GetListItem methods that you can use to return single items.


An SPWeb or SPSite object can occupy a lot of memory.

Avoid constructing objects of these types simply to get a reference to a parent object. Instead, to get a reference to a web application, use the static SPWebApplication.Lookup(Uri) method, and pass it a Uri object that is created with the URI of the web application. You can then get a reference to the farm by using the Farm property of the web application object. (You can get a reference to a remote farm by using the static Open(String) method.) The ContentDatabases property of the web application object contains a collection of the content databases in the web application. You can get a reference to a particular content database through this property if you know its index in the collection

 
Microsoft SharePoint Foundation 2010 and Microsoft SharePoint Server 2010 apply a default query threshold of 5,000 items. Any custom code that relies on query result sets that can exceed this maximum will not perform as expected. Queries on lists consisting of more than 5,000 items that include fields that are not indexed in their query conditions will also fail, because those queries must scan all rows in a list.
 

Do not use SPList.Items

SPList.Items selects all items from all subfolders, including all fields in the list. Use the following alternatives for each use case.
  • Adding an item
    Instead of calling SPList.Items.Add, use SPList.AddItem.
  • Retrieving all items in a list
    Instead of using SPList.Items, use SPList.GetItems(SPQuery query) . Apply filters, if appropriate, and specify only the fields you need to make the query more efficient. If the list contains more than 2,000 items, paginate the list in increments of no more than 2,000 items. The following code example shows how to paginate a large list.
  • Getting items by identifier
    Instead of using SPList.Items.GetItemById, use SPList.GetItemById(int id, string field1, params string[] fields). Specify the item identifier and the field that you want.
  • Do not enumerate entire SPList.Items collections or SPFolder.Files collections.
    The left column in Table 1 lists the methods and properties that if used will enumerate the entire SPList.Items collection, and cause poor performance and throttling for large lists. Instead, use the better-performing alternatives listed in the right column

  • Alternatives to enumerate SPList.Items

     
    Poor Performing Methods and Properties Better Performing Alternatives
    SPList.Items.XmlDataSchema Create an SPQuery object to retrieve only the items you want.
    SPList.Items.NumberOfFields Create an SPQuery object (specifying the ViewFields) to retrieve only the items you want.
    SPList.Items[System.Guid]  SPList.GetItemByUniqueId(System.Guid) 
    SPList.Items[System.Int32]  SPList.GetItemById(System.Int32) 
    SPList.Items.GetItemById(System.Int32)  SPList.GetItemById(System.Int32) 
    SPList.Items.ReorderItems(System.Boolean[],System.Int32[],System.Int32)  Perform a paged query by using SPQuery and reorder the items within each page.
    SPList.Items.ListItemCollectionPosition ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (Microsoft SharePoint Server 2010 only)
    SPList.Items.ListItemCollectionPosition ContentIterator.ProcessListItems(SPList, ContentIterator.ItemProcessor, ContentIterator.ItemProcessorErrorCallout) (SharePoint Server 2010 only)
     
     
    Using the SPList.ItemCount property is the recommended way to retrieve the number of items in a list. As a side effect of tuning this property for performance, however, the property can occasionally return unexpected results. For example, if you require the exact number of items, you should use the poorer performing GetItems(SPQuery query), as shown in the preceding code example.
     
    Whenever possible, acquire a reference to a list by using the list's GUID or URL as a key.

    Alternatives to SPFolders.Files

    Poor Performing Methods and PropertiesBetter Performing Alternatives
    SPFolder.Files.Count SPFolder.ItemCount
    SPFolder.Files.GetEnumerator() ContentIterator.ProcessFilesInFolder(SPFolder, System.Boolean, ContentIterator.FileProcessor, ContentIterator.FileProcessorErrorCallout) (SharePoint Server 2010 only)
    SPFolder.Files[System.String] ContentIterator.GetFileInFolder(SPFolder, System.String)Alternatively, SPFolder.ParentWeb.GetFile(SPUrlUtility.CombineUrl(SPFolder.Url, System.String) (SharePoint Server 2010 only)
    SPFolder.Files[System.Int32] Do not use. Switch to ContentIterator.ProcessFilesInFolder and count items during iteration. (SharePoint Server 2010 only)
      
      
      
      
      

    Thursday, April 5, 2012

    Sharepoint XML world...

    I have used XML in a variety of my earlier projects and find it very interesting concept.

    In one of my recent projects, To Read an XML file from Layouts folder to display a Megamenu which is audience targetted based on a userprofile property was pretty challenging for me... so I am sharing this with my fellow SP developement team for reference!

    Define the string constant for the path to XML file
     public const string XMLFILEPATH = "Template/Layouts/Banfield.Portal/MyFile.xml";  
    
    Let's say the XML is in the below format

    <?xml version="1.0" encoding="UTF-8"?>
    <Menu>
      <Tab Title="Tab 1">
        <Audience>Audience1,Audience2</Audience>
        <Content>
          <![CDATA[
          <ul> <!-- ul for the tab -->
            <li> <!-- li per column in the tab -->
              <ul> <!-- ul for the column -->
                <li> <!-- li per group in the column -->
                  <h3>Tab One, Column One, Group One</h3>
                  <ul> <!-- ul for the group -->
                    <li> <!-- li per link -->
                      <a href="something">Tab One, Column One, Group One, Link One</a>
                    </li>
                    <li>
                      <a href="something else">Tab One, Column One, Group One, Link Two</a>
                    </li>
                  </ul>
                </li>
                <li>
                  <h3>Tab One, Column One, Group Two</h3>
                  <ul>...</ul> <!-- ul for the group, with li's per link -->
                </li>
              </ul>
            </li>
            <li>
    
          ]]>
        </Content>
      </Tab>
      <Tab Title="Tab 2">
        <Audience>Audience1,Audience3</Audience>
        <Content>
          <![CDATA[<ul> <!-- ul for the tab -->
            <li> <!-- li per column in the tab -->
              <ul> <!-- ul for the column -->
                <li> <!-- li per group in the column -->
                  <h3>Tab 2, Column One, Group One</h3>
                  <ul> <!-- ul for the group -->
                    <li> <!-- li per link -->
                      <a href="something">Tab 2, Column One, Group One, Link One</a>
                    </li>
                    <li>
                      <a href="something else">Tab 2, Column One, Group One, Link Two</a>
                    </li>
                  </ul>
                </li>
                <li>
                  <h3>Tab 2, Column One, Group Two</h3>
                  <ul>...</ul> <!-- ul for the group, with li's per link -->
                </li>
              </ul>
            </li>
            <li>
          ]]>
        </Content>
      </Tab>
      <Tab Title="Tab 3">
        <Audience>Audience1,Audience2,Audience3</Audience>
        <Content>
          <![CDATA[<ul> <!-- ul for the tab -->
            <li> <!-- li per column in the tab -->
              <ul> <!-- ul for the column -->
                <li> <!-- li per group in the column -->
                  <h3>Tab 3, Column One, Group One</h3>
                  <ul> <!-- ul for the group -->
                    <li> <!-- li per link -->
                      <a href="something">Tab 3, Column One, Group One, Link One</a>
                    </li>
                    <li>
                      <a href="something else">Tab 3, Column One, Group One, Link Two</a>
                    </li>
                  </ul>
                </li>
                <li>
                  <h3>Tab 3, Column One, Group Two</h3>
                  <ul>...</ul> <!-- ul for the group, with li's per link -->
                </li>
              </ul>
            </li>
            <li>
          ]]>
        </Content>
      </Tab>
    </Menu>
    

    In CreateChildControls - using System.LinQ we will try to retrieve the data of the XML

      System.Xml.Linq.XDocument doc = XDocument.Load(Microsoft.SharePoint.Utilities.SPUtility.GetGenericSetupPath(XMLFILEPATH));
      
    

    Now we can safely start the process of data retrieval for the megamenu elements for the user's departrment ( this is specified as a user profile property.)

      
      XElement navElement = doc.Element("Menu");
      
             using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
      
             {
      
                 
               var AudienceCategory = GetUserProfile.GetUserProperty(SPContext.Current.Site, loginName, GetUserProfile.AudienceCategory);
      
               var newElement = from el in navElement.Descendants("TopNode")
        
                       where el.Element("Audience").Value.Contains(strDepartment)
      
                        select new
      
                          {
      
                            TopNodeTitle = el.Attribute("Title").Value,
      
                            TopNodeContent = el.Element("Content").Value 
      
                          };
      
               if (newElement != null)
      
               {
      
                 // Prepare for the rendering of megamenu classes, UL and Li's
      
                 StringBuilder sb = new StringBuilder();
      
                 foreach (var c in newElement)
      
                 {
      
                   RenderTopNodeContents(c.TopNodeTitle.ToString(), c.TopNodeContent.ToString(), sb);
      
                 }
      
                 MegaMenuUl.InnerHtml = sb.ToString();
      
               }
      
             }  
    
    HTML for the usercontrol

     <div class="Menu" runat="server" >
      
     <ul id="MenuUl" runat="server">
     </ul>
      
     </div>  
    

    RenderTabContents function :

      private void RenderTabContents(string strTabTitle, string strContent, StringBuilder sb)
      
         {
      
           sb.Append("<li>"); // Begin Li for each Tab
      
           sb.Append("<h2>"); // H2 for the Menu name
      
           sb.Append(strTabTitle);
      
           sb.Append("</h2>"); // End for H2
      
           sb.Append(strContent); // This should have the UL and Li embedded in the content from XML
      
           sb.Append("</li>"); //End Li for each tab
      
         }  
    

    Wednesday, February 8, 2012

    Sad but true facts... SP2010


    More than often we assume something will surely work in SP2010 since it behaves a certain way in scenarios... but alas! After spending hours, you finally come to know that it is a limitation....and is by Design.... here are some points worth mentioning which have kept me awake in my implementation days


    1.       Timer jobs are run from the SharePoint Timer Service also known as owstimer.exe. To debug a timer job attach the debugger to the owstimer.exe process, set a breakpoint and wait until your timer job is executed. This could take minutes for each debugging session, so be patient! The deployment of a timer job is easy if you have a Template for 2005. However, redeploying a solution involves restart of the SharePoint Timer Service and IIS leading to a session reset for connected users.


    2.      Calculated columns: Cannot use the ID column in the calculated fields. The simple truth is that the ID field does not exist before you save your new record in SharePoint list. Alternate solution could be to use a SP designer workflow, which updates the field. 

    3.    Approver/Lookup Limitation - when I tried to add a new set of approvers (10) to my List here's what we have:
    This view cannot be displayed because the number of lookup and workflow status columns it contains exceeds the threshold (8) enforced by the administrator.

    Operations that exceed the list view threshold are allowed in the following time window defined by the administrator:
    Daily, from 5:00:00 PM to 11:00:00 PM.


    Well - this can be changed easily in central admin.
    Go to you Central Admin–> Manage Web Applicaiton
    Select your webapplicaiton–> Click on the General Settings–>Select Resource throttling
                 Now look at List View Lookup Threshold and increase the number as per your requirement.
                 However, this takes a toll on the performance of Sharepoint and hence is not recommended!

    Alternate solution can be to divide your list in multiple lists so that it has just the required no. of approvers. Well, it takes some redesign effort to get this going, knowing the views need to be configured for the multiple lists!!


    4.       The 'Microsoft.ACE.OLEDB.14.0' provider is not registered on the local machine. - get this error when you have tried to access the "Excel" data source!

    I had to uninstall any office related products (office, Visio, SP designer) which were 32 bit version and then install AccessDatabaseEngine_x64.exe from the link below.


    Top of Form

    Bottom of Form