Pages

Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

Tuesday, May 13, 2014

SharePoint: Safe Control Entry using elements file

Recently I’ve discovered that it’s possible to add safe control entries through elements.xml file. To do this, add an elements.xml file (or use an existing xml file). Then select the elements.xml file and open the properties window as shown below:

image

Then click the ... button next to (Safe Control Entries) as shown in the above image. Then in the safe control entries dialog click ‘Add’ and edit the namespace as shown below:

image

Finally, add the element xml file to a web/site scoped feature. As you will deploy the WSP, the safe control entry will be added in web.config file.

Sunday, October 27, 2013

Upgrade SharePoint 2010 Visual Studio Solution to SharePoint 2013

With every new version of SharePoint, we need to upgrade our Visual Studio solution. There’s no easy way or tool out there that can automate these upgrade. So I’ll just describe few points you need to consider when you’ll upgrade the Visual Studio 2010 project for SharePoint 2010 to Visual Studio 2012 project for SharePoint 2013. First of all, you need to upgrade your Visual Studio pre-VS2012 solution to Visual Studio 2012.

Change Target .NET Framework

SharePoint 2010 uses .Net Framework 3.5 with SharePoint 2013 uses .Net Framework 4.5. So you need to change the target framework for the project. To change the target framework version, unload the project and then edit the project file in Visual Studio and change the property as shown below:

<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

 

Change SharePoint Version

Unload the project and edit in Visual Studio, then add/edit the section to ensure the following entry near to the <TargetFrameworkVersion>

<TargetOfficeVersion>15.0</TargetOfficeVersion>

Then load the project and replace all SharePoint 2010 specific DLLs with SharePoint 2013 specific DLLs (version 15). Also find out any reference of SharePoint 2010 DLLs/Controls  version ‘14.0.0.0’ and replace with ‘15.0.0.0’

 

Change Generic Setup Path in code

In SharePoint 2013, you can deploy your solution in SharePoint 2010 more or SharePoint 2013 mode or both. For example to deploy your solution to both 2010 and 2013 mode, you can use the following command:

Install-SPSolution -Identity my_solution.wsp -GACDeployment -CompatibilityLevel {14,15}

If you skip the CompatibilityLevel (and we usually skip), then the solution is deployed default compatibility level included in the WSP manifest file – which is based on Visual Studio project’s target SharePoint Version. But since we are targeting to upgrade Visual Studio solution to SharePoint 2013, we need to make sure code looks for artifacts in 15 hive, instead of 14 hive. To ensure that code looks in 15 hive, we need to find all use of ‘SPUtility.GetGenericSetupPath()’ and need to replace it with ‘SPUtility.GetVersionedGenericSetupPath()’ passing parameter 15 as shown below:

SPUtility.GetVersionedGenericSetupPath(‘/_Layouts/myproject/script/test.js’,15)

Note – If you are still deploying your solution in compatibility 14 mode, then you should also replace the ‘GetGenericSetupPath()’ with ‘GetVersionedGenericSetupPath()’ passing parameter 14, but instead of hardcoding the version inline, you can use a constant so that you can replace the version number in one place to change it to 15. You can use constant ‘Microsoft.SharePoint.Utilities.SPUtility.ContextCompatibilityLevel’ which returns the current compatibility level of the SPSite. Your code then will look like:

SPUtility.GetVersionedGenericSetupPath(‘/_Layouts/myproject/script/test.js’,Microsoft.SharePoint.Utilities.SPUtility.ContextCompatibilityLevel)

However, if you want to use the same code both for SharePoint 2010 and SharePoint 2013, then you can code block like below to run code in different version of SharePoint:

//if SharePoint site collection is running in 2013 (15) mode
if (SPUtility.ContextCompatibilityLevel==SPUtility.CompatibilityLevel15)
{
    //Code needs to be executed in SharePoint 2013
}
else if (SPUtility.ContextCompatibilityLevel==14)
{
  // Code needs to executed in SharePoint 2010
}
//You can also use SPSite.CompatibilityLevel to find out site collection compatibiltiy mode

Change Reference to Layouts, ControlTemplates

Finally all references to ‘_Layouts/’ and ‘_ControlTemplates/’ needs to be changed to ‘_Layouts/15/’ and ‘_ControlTemplates/15/’ to ensure the artifacts are loaded from 15 hive. Either SharePoint will try to load files from 14 hive. However if you deploying the solution in SharePoint 2010 mode, (compatibility level is 14), then you don’t need to update the reference.

 

Conclusion

After making all the above changes, finally compile the solution. However, my suggestion would be to deploy the WSP in SharePoint 2010 mode first, test the deployment and adjust/modify code to comply with SharePoint 2010 object model. Once you are comfortable with changes, then upgrade code as described in the post and then deploy/test.

Wednesday, July 24, 2013

SharePoint Reporting Service and Bing Map – Unable to connect to Remote Server

We’ve RDL reports running in SharePoint using SQL Server Reporting Service. The reports were using Bing Map to display some BI information. Reports were working fine in our development box but as soon as we moved the reports in UAT, Bing map was failed to rendered and the error was ‘Unable to Connect to Remote Server’.

After Googling it comes out that we need to configure proxy settings and we’ve a proxy in UAT. So we configured proxy settings for Reporting Service web.config file (which usually exists in Reporting Server location at Drive:\Program Files\Microsoft SQL Server\MSRS10_50.[instance name]\Reporting Services\ReportServer\web.config) as shown below. You need to add the following section in between <Configuration> section (possibly after </Runtime>):

<system.net>
    <defaultProxy enabled="true">
        <proxy bypassonlocal="True" proxyaddress="http://server:port" /> 
     </defaultProxy>
</system.net>

But it didn’t solve our problem. Still we were getting the error Unable to connect to remote server.

 

Solution

After investigating it turned out that we also need to configure SharePoint Reporting Services Service Application’s web.config file. You can find the Reporting Service Application by browsing the ‘SharePoint Web Service’ in IIS as shown below (in SharePoint 2013 box):

image

Figure : SharePoint Service Application – SQL Server Reporting Services in IIS

 

So you need to configure the proxy settings for both:

  • SQL Server Reporting Service (Drive:\Program Files\Microsoft SQL Server\MSRS10_50.[instance name]\Reporting Services\ReportServer\web.config)
  • as well as SharePoint Reporting Service Application’s web.config file (shown in above image).

Sunday, October 14, 2012

SharePoint: Manipulate Audience Programmatically

Audience is a nice feature in SharePoint but only available in MOSS/SharePoint Server. Generally speaking, Audience is group of users that can be used to target contents. The class ‘Microsoft.Office.Server.Audience.AudienceManager’ is the main entry point for accessing Audience feature in SharePoint. Audience values are of three different types which are separated by ‘;;’:

  • Global audience represented by GUIDs. Multiple global audience values are separated by commas.
  • Distinguished names represented by Fully Qualified Domain Name. Multiple distinguished names are separated by ‘\r\n’.
  • SharePoint Group IDs. Multiple sharepoint groups are separated by commas.

An example of audience field value is given below:

A88B9DCB-5B82-41E4-8A19-17672F307B95, B88B9DCB-5B82-41E4-8A19-17672F307B95 ;; cn=all developers,ou=distribution lists,dc=redmond,dc=corp,dc=microsoft,dc=com \r\n cn=all testers,ou=distribution lists,dc=redmond,dc=corp,dc=microsoft,dc=com \r\n ;; 1,12,21,37

I’ve found many times that people are manipulating these audience field values manually by parsing the text. However there’s SharePoint server object model support to manipulate Audience field programmatically.

Find Audience Field in List/Library

Audience field is of type ‘Microsoft.Office.Server.WebControls.FieldTypes.SPFieldTargetTo’. You can find out the field types from list fields’ as shown below (using any of the two described):

var audienceFields = list.Fields.OfType<Microsoft.Office.Server.WebControls.FieldTypes.SPFieldTargetTo>();

//Alternatively you can use the following code snippet also:
foreach (SPField field in list.Fields)
{
if (field is SPFieldTargetTo)
{
//found audience field
}
}

Code 1: Get Audience fields

 

Read/Parse Audience Values

You can manipulate the audience values as shown below. To read value from a list/library audience field, pass the value in the AudienceManager.GetAudienceIDsFromText method. The method will parse the audience field value and populate three out variables: Global Audience, Distinguished Name and SharePoint Group.

string[] globalAudienceIds;
string[] distinguisedNames;
string[] sharepointGroupNames;

var audienceFieldValue = listItem["AudienceField"] == null ? string.Empty : listItem["AudienceField"].ToString();
AudienceManager.GetAudienceIDsFromText(audienceFieldValue, out globalAudienceIds, out distinguisedNames, out sharepointGroupNames);

Code 2: Read Audience Field values

 

Once you have the global audience values you can get three different types of audience-details as shown below:

var audienceManager = new AudienceManager(ServerContext.GetContext(SPContext.Current.Site));
//get global audience
Audience globalaudience = audienceManager.GetAudience(globalAudienceGuid);
//get distinguished name audience
Audience distinguisedNameAudience = audienceManager.GetAudience(distinguisedName);
//get sharepoint group audience
SPGroup sharepointGroupAudience = web.SiteGroups.GetByID(sharepointGroupId);

Code 3: Get audience based on audience id or name

If you have global audience id (which is valid guid), please convert the guid string to GUID type variable and then pass in the GetAudience method.

 

Update Audience Field Value

To update audience field value programmatically you need to use following code snippet. You need pass the global audience IDs, distinguished names and sharepoint group names to Audience Manager’s GetAudienceIDsAsText method which will combine the values as text to save in audience field.

listItem["AudienceField"] = AudienceManager.GetAudienceIDsAsText(globalAudienceIds, distinguisedNames, sharepointGroupNames);

Useful links

The following links might be useful for you to read.

Sunday, August 12, 2012

SharePoint: Too much customization is not good for health

SharePoint allows developer/architect to customize it’s power in numerous ways. You can write event receivers, timer jobs, webparts, application pages and so on. But what I’ve found with my years of experience in working with SharePoint is that sometimes developers/architects make too much customization which is not good from maintenance point of view.

If you are senior SharePoint developer or architect or you have the responsibility to design a solution for SharePoint, first focus on out-of-the-box way to solve the problems. If possible, try to compromise features talking to clients.

Real world Example

Let’s consider a simple example. You have a database which is used by other LOB systems. SharePoint reads and writes data to the database and then other LOB systems (like SAP or some custom applications) use (only read) the data in the database for it’s own use.

image

Now client requirement is to show the data in the database as SharePoint list so that clients get the feelings that the tables in the database are kind of List in the SharePoint. Now what options do you have? I think we have two options:

  • Option 1: Use Business Connectivity Service to show Database tables as SharePoint list
  • Option 2: Create custom SharePoint list and then write event receivers to synchronize data between database and List.

Different architect/developer under different circumstances, may use first option or second. But the first option is more out-of-the-box way of implementing the requirements. However some situations demand the second option where you need to  write custom code and need to sync data between SharePoint list and table in database manually. So as an architect/developer I would prefer the first option using Business Connectivity Service. If I need to choose second option then I should have explanation why I need to use second option. The explanation might be Business Connectivity Service has some limitations that we need to overcome with second option, or the requirements are too complex to implement with Business Connectivity Service.

 

But Why?

Now you may ask why it’s matter if I do more customization (I would prefer to say unnecessary customization). I bet it’s matter. The more customization you do, the more difficult to manage codebase, more time to develop, more possible to generate more bugs, more difficult to upgrade to newer version of SharePoint and many more. SharePoint is a rich application framework and we need to utilize it in best possible ways.

 

conclusion

The idea I wanted to share here not to say that you should not do any customization rather make sure your customization really needed. If you do unnecessary customization then you might paving the way for more customizations (maybe for error fixing or features related to customizations). As I read somewhere, “A single bad developer creates job for more developers”. Let’s not create more customizations by an unnecessary customizations.

Saturday, June 16, 2012

SharePoint: Package your external dependencies to another solution

Sometimes we use some third party tools that create external dependencies to our SharePoint projects. For example if you use Pattern and Practice SharePoint Guidance Library in your SharePoint project in visual studio and build WSP, then  WSP package will include these SharePoint Guidance libraries also. However, this might create problems related to deployment. To explain the issue, let’s consider how SharePoint solution retraction/removal might affects other WSP package deployed in the same SharePoint environment.

 

Scenario: Two WSPs sharing Common Dependency

Let’s consider you have two Visual studio SharePoint project: SharePoint Project 1 and SharePoint Project 2. Both projects are using (i.e., referencing) a third party dll (i.e., thirdparty.dll). Now if you generate WSP from two different Visual Studio projects, both WSP will include the thirdparty.dll in their WSP package.

image

Figure 1: A single thirdparty.dll is shared by two WSP solutions

 

As shown in the image above, a single third party dll is referenced by two Visual studio SharePoint projects. Now when you 'will build two different WSP solutions the same third party dll will be included to two different WSPs. If these two WSPs are deployed in a single SharePoint server/farm with GAC deployment, then both WSP will deploy the same ThirdParty.dll in the GAC. Everything will work fine till now.

 

Problem: retracting/removing one solution will fail other WSP to work

Now consider a scenario. After deploying the two WSPs in the production with GAC deployment, you have found a problem with Project 2 WSP. So you want to remove the Project 2 WSP while you will keep Project 1 WSP. So you will remove the Project 2 WSP. Removing the Project 2 WSP will remove all the assemblies from GAC/BIN related to the WSP. So removing the Project 2 WSP will remove thirdparty.dll from GAC. As soon as you remove the Project 2 WSP from SharePoint server/farm, Project 1 WSP will fail to work as it’ll not find the referenced thirdparty.dll in GAC. So removing Project 1 WSP (or project 2 WSP) will remove the thirdparty.dll from GAC and other WSPs which are using the same dll will fail to work.

 

Solution: Package your external dependency to new WSP

The solution to this problem is to exclude thirdparty.dll from both WSPs and create a new WSP dependency/prerequisite solution for thirdparty.dll. You can do it easily with SharePoint 2010 Package editor. As a result the thridparty.dll will not be included in any of the two WSPs.To package a new WSP for the thirdparty.dll you need to create another new Visual Studio SharePoint projects which will just include the thirdparty.dll (or any other prerequisites). The new architecture is shown below:

image

Figure 2: Shared thirdparty.dll is included in separate WSP

 

As shown in the figure 2, now the shared dll (thirdparty.dll) is excluded from Project 1 and Project 2 WSP. Whether you use WSPBuilder or SharePoint 2010 project template in Visual studio, you can exclude one more dlls from the WSP. Then create a new Visual Studio project (WSPBuilder or SharePoint) which will include the thirdparty.dll and the output WSP package will include the shared/external dll. Now you will have three WSPs and the new WSP will be prerequisite WSP for other two WSPs.

Now with this model, you can remove Project 1 WSP or Project 2 WSP from your server without affecting each other. Even if you remove Project 1 WSP from the Farm/Server, the thirdparty.dll will not be removed from GAC as it’s not deployed as part of Project 1 WSP. Later if you want to redeploy the Project 1 WSP again then you don’t need to redeploy the prerequisite WSP as it’s already deployed in the server. If needed you can package your external dependency in more than one WSP packages.

 

Conclusion

If you are developing a SharePoint custom product that will be deployed in some client’s environment, then you should care about creating one or more dependency WSP packages. If your SharePoint solution is developed for a specific client or as an in-house product then you might not face the problem even if you don’t create a prerequisite WSP package. However if you are developing a SharePoint solution as a custom product and you don’t know the client yet, you should create prerequisite WSP package. And then when you will deploy your product in client server, you can deploy the perquisite or not depending on if the client has the prerequisite dlls install or not. If the client has the dlls/prerequisites installed in the farm, you don’t need to deploy the prerequisite WSP. This will make your SharePoint product more independent and will have less impact on other SharePoint solution deployed in the farm.

Thursday, May 17, 2012

SharePoint Tips: Iterating through All the webs in the site

Sometimes we need to process all webs in a site collection, as you want to do some quick fixes in the web. Few weeks back my manager asked me to do some fixes in the list items exists in all the webs in the site collection. There were about 30,000 webs in the site collection and I was looking for some kind of script that will be efficient. The usual way of looping through all webs might be using some recursive way, as shown below.

//Starting point
public void ProcessAllWeb(SPSite site)
{
    using (var web = site.RootWeb)
    {
        ProcessWebRecursive(web);
    }

}

//Recursive method
private static void ProcessWebRecursive(SPWeb web)
{
    //do some processing
    //web.Lists["listName"].ItemCount

    foreach (SPWeb subWeb in web.Webs)
    {
        using (subWeb)
        {
            ProcessWebRecursive(subWeb);            
        }
    }

}

Code Snippet 1: Recursive way of processing all webs in the site collection (Not optimized)

In the recursive way of processing all webs, there will be more than one SPWeb instance alive in memory. In the above code snippet, when the method ProcessAllWeb is invoked it’ll call the recursive method ProcessWebRecursive. The recursive method will keep calling the subwebs while keeping the parent web alive.

 

While I was writing the code, I was wonder if there’s any way of processing only one web non-recursively. So my intention was to open only one web in memory at once. And then I found it. You can get all web Url(including all subwebs at all level) using SPSite.AllWebs.Names. The following code snippet shows the efficient way of processing all webs in the site collection:

public void ProcessAllWeb(SPSite site)
{
    string[] allWebUrls = site.AllWebs.Names;
    foreach (string webUrl in allWebUrls)
    {
        using (SPWeb web = site.OpenWeb(webUrl))
        {
            //process web
        }
    }
}

Code Snippet 2: Process all webs one by one (Optimized for large number of webs)

Using the code snippet shown in figure 2, you just open one web at a time in memory for processing. The trick here is ‘SPSite.AllWebs.Names’ which will return all the (I mean it!) subwebs (including children and their children and so on) as a result. If you have thousands of webs under a site collection (and if it’s production), you should care about performance issue.

Thursday, May 3, 2012

SharePoint Tips: List.ItemCount vs List.Items.Count

If you need to know the total items in the list, how do you write code? The usual way to write code is shown below:
var itemCount = list.Items.Count;
Code Snippet 1: Usual (not suggested) way to get items count
However this will fetch all the records from database and apply the count in memory.

SharePoint object model provides an easiest way to find the items count without fetching all records and you can use the following code snippet to do so:
var itemCount = list.ItemCount;
Code Snippet 2: Suggested way to get items count

Saturday, April 21, 2012

SharePoint Tips: Object Mode provides Built-in Field and Content type Ids

Sometimes we need to access SharePoint built-in fields from list. You may find code to access list item value as shown below:

listItem["Title"] = "value";

Code Snippet 1: Usual approach

 

The title field is SharePoint built-in field and you don’t need to hard-code the field name . SharePoint Object Model provides a class ‘SPBuiltInFieldId'’ where you can find most of the SharePoint built-in field’s IDs. So you can write the above code snippet as shown below:

listItem[SPBuiltInFieldId.Title] = "value";

Code snippet 2: Suggested approach to access built-in fields

 

The class ‘SPBuiltInFieldId’ also provides many built-in fields Ids like ‘created by’ (known as owner), modified by etc.

Similarly you can get built-in content type Ids using the class ‘SPBuiltInContentTypeId’. I would recommend you to use these classes to access built-in fields and content types.

Friday, March 9, 2012

Managing a single codebase for both SharePoint 2007 and 2010

Sometimes we need to work on source code that needs to be maintained for both SharePoint 2007 and 2010. There’s no built-in support from Microsoft to manage two versions of same Visual Studio solution for multiple versions of SharePoint. The problem is more complicated as the SharePoint assembly details are hard-coded in markup (ascx, aspx).

Anyway, I worked on a project where my team was developing a SharePoint custom product and some of our clients are still using SharePoint 2007 while some others are already moved to SharePoint 2010. So we had a challenge to support all clients (both SharePoint 2007 and 2010) but maintaining a single codebase. I am not demanding that the solution I’ll provide in this post is the best but the approach might be helpful to minimize code duplication. The sample Visual studio project can be download from skydrive.

 

Introduction

I’ve used Model View Presenter (MVP) to separate the presenter logic from view. Also, code that not dependent on SharePoint assembly directly are put in presenter layer. If for any reason, presenter is dependent on SharePoint assembly (for example SPGridView is used in code-behind) then the SharePoint assembly dependent code is implemented in individual (2007 or 2010) SharePoint project where common non-SharePoint presenter logic is kept in Presenter layer. For explaining the solution, I would like to introduce you to the Visual Studio projects (can be downloaded from here)I’ve been used.

  • Sohel.Blogging.Common: This is common project where interfaces, data contracts, common utilities etc are declared.
  • Sohel.Blogging.Presenter: This is the presenter layer where all non-SharePoint related presenter logic is kept. Since there’s no SharePoint-dependent logic is places, no reference to SharePoint dll is needed. As a result this project (or more specifically, presenter logic) can be reused by both SharePoint 2007 and 2010.
  • Sohel.Blogging.Wss: This is SharePoint 2007 (wss) project from where we’ll generate WSP file. Only SharePoint 2007 project structure, Views (aspx, ascx etc.) and Site artifacts (site definition, columns etc.) are placed in this project. As code-behind is replaced by presenter (which resides in Presenter layer), only views are need to duplicated between SharePoint 2007 and 2010.
  • Sohel.Blogging.Foundation: This is SharePoint 2010 project from which we’ll generate WSP solution file. Only views (aspx, ascx), site structure and site artifacts (site definitions, site columns etc.) are maintained in this project

To plug presenter/view to each other, Dependency Injection is used and for that purpose, Microsoft Patterns & Practices SharePoint Guidance is used. The Guidance Library for both SharePoint 2007 and 2010 can be downloaded from CodePlex (http://spg.codeplex.com/). For more information on how to use the Guidance Library for Dependency Injection please follow another post SharePoint Service Locator in my blog.

The overall architecture of the Visual Studio solution is presented below:

image

Figure 1: Visual Studio Project Dependency

The overall goal of the architecture is to move aspx/ascx code behind to presenter layer. As a result the code-behind logic is reused in two different views (SharePoint 2007 and 2010).

 

Views

The view (aspx, ascx) files are slimmed by removing code to presenter. View files (aspx,ascx etc) are placed in Sohel.Blogging.Foundation or Sohel.BLogging.Wss project. An interface is extracted from view to make Controls (like TextBox, Dropdown etc) available to Presenter. This is done by exposing View’s controls as the interface properties of the view. Though this is not the real Model View Presenter (MVP) but it works and faster to develop. The only problem is that the view interface/presenter is tightly coupled to asp.net controls.

public interface IProductListview
{
    Panel CreateListPanel { get; }
    Panel AddItemListPanel { get; }
    HtmlGenericControl MessageDiv { get; }
    HyperLink ViewAllProductLink { get; }
    Product GetProduct();
    string GetProductListUrl();
}

However if you use SharePoint controls (like SPGridView), then instead of exposing them in View interface, keep the logic related to the control in View and use a method in view. For example if you use SharePoint DateTime control, a method in view/code-behind can be used to put the logic related to SharePoint control. The following view interface declares SetDate method that set the date value of SharePoint DateTime control.

public interface IProductListview
{
    //Panel CreateListPanel { get; }
    //Panel AddItemListPanel { get; }
    //HtmlGenericControl MessageDiv { get; }
    //HyperLink ViewAllProductLink { get; }
    //Product GetProduct();
    //string GetProductListUrl();
    void SetDate(DateTime dateTime);
}

The view (say UserControl) below implement the SetDate method.

public partial class ProductList : UserControl, IProductListview
{
    public void SetDate(DateTime dateTime)
    {
        uiSpDateTimePicker.SelectedDate = dateTime;
    }
..............
..............
}

 

Presenter

All Presenters are kept in Sohel.Blogging.Prensenter project. Presenter access View controls through view interface. As I’ve mentioned already, this is not the right for MVP pattern to use web control directly inside view interface. SharePoint Service Locator is used as shown below:

public class CurrentSharePointServiceLocator : IBloggingServiceLocator
{
    public T ResolveInstance<T>()
    {
        return SharePointServiceLocator.Current.GetInstance<T>();
    }
}

The interface to the service locator (IBloggingServiceLocator) is passed to the Presenter constructor inside view, as shown below:

public partial class ProductList : UserControl, IProductListview
{
    private ProductListPresenter _presenter;
    public ProductListPresenter Presenter
    {
        get
        {
            if (_presenter == null)
            {
                _presenter = new ProductListPresenter(this, CurrentSharePointServiceLocator.GetInstance<IBloggingServiceLocator>());
            }
            return _presenter;
        }
    }
.....
.....
}

As presenter get access to the IBloggingServiceLocator, presenter can access any object that is registered through service locator. The presenter gets access to the view and service locator through constructor as shown below:

public class ProductListPresenter:APresenter
{
    public IProductListview View { get; set; }

    public ProductListPresenter(IProductListview view,IBloggingServiceLocator serviceLocator):base(serviceLocator)
    {
        View = view;
    }
.....
.....
}

 

New development Consideration

Once the project architecture is in place and if you need to develop new control, application pages etc, you should develop new control for any version of SharePoint first. For example if I need to develop a new application page, I would go and develop the page for SharePoint 2010. Then I would refactor the code to move the code-behind logic to Presenter class. Then I’ll create a new page in SharePoint 2007 copying the similar file from SharePoint 2010 (but surely with modifications). Now while you’ll create new page for SharePoint 2007, you may fine more refactoring needed to generalize code more for both SharePoint 2007 and 2010. The only duplication needs to be made in this approach is resources like markup/xml/css/jss etc. need to be duplication. But I think its possible to minimize the duplication by putting most of the resources in separate web project and on post-build event, you can copy the resources in individual SharePoint projects.

 

Conclusion

As more and more clients are adopting SharePoint and more and more Independent Software Vendor (ISV) are developing custom SharePoint products, ISVs need to support more than one version of their product. Since Microsoft doesn’t provide any out-of-the box solution for this multiple-version support for Visual Studio Solution, it takes extra efforts for developers to use the same codebase for different version of SharePoint and increase the possible of code duplication which in turn make maintenance difficult. You can download the sample code from skydrive.

Disclaimer: The solution provided in this post is not the best solution but a workaround. If anybody has any better idea, you are welcome to share.

Sunday, November 20, 2011

SharePoint 2010: Configure Kerberos Authentication

SharePoint 2010 supports two authentication mode: Classic mode and Claims based. Today I’m going to explain how to configure Kerberos authentication for an web application with classic mode Authentication. I’ll try to explain how to configure Kerberos for an web application with Claims based authentication later.

 

Step 1:  Create/Configure Web Application

In this step you need to create an web application with required configurations. However, you can convert an existing web application to use Kerberos authentication if the web application app pool user is a domain user. But as mentioned already, the configuration explained in this post applies for an web application with Classic Mode Authentication.

Create a new web application

In creating new web application for using Kerberos Authentication you need to consider the following options:

  • Use classic mode Authentication as shown below (You can use Claims Based Authentication but then the steps described in this post might not work. For Claims Based Authentication you need different sets of configuration):

    image
    Figure 1: Create site with ‘Classic Mode Authentication’

  • Use Negotiate (Kerberos) as Authentication Provider in ‘Create Web Application’ page as shown below:

    image
    Figure 2: Create site with Negotiate (Kerberos) Authentication provider selected.

  • Use domain username for app-pool account. Don’t use Predefined (like Network Service, Local System etc) user account. This is important to use domain user name as you will configure Kerberos against this app-pool username.

    image
    Figure 3: User domain user name for App-pool account.

  • One recommendation. Make the site url to be Fully Qualified Domain Name. For example, my server name was sohel-server and domain name was sohel.com. I’ve modified my full site name from default http://sohel-server:5000 to http://sohel-server.sohel.com:5000. This will help you identifying if the Only Kerberos is used for authentication instead of NTLM.

 

Configure an existing web application

If you have an existing web application that you want to move to Kerberos from NTLM you need to make sure your site meets the following criterion:

  • The web application uses a domain user in application pool account instead of predefined account like Network Service, Local System. If your web application doesn’t use domain user then you can create a new web application with domain user name as application pool account. Changing the application pool account might make your web application malfunctioning.
  • If you existing web application uses Classic Mode Authentication then configuration in this post should work. However, if you are using Claims based Authentication then you need to configure Security Token Service (STS) which in not mentioned in this post. If you are using Classic Mode, then you can continue this post as this post describes Kerberos for an web application with Classic Mode Authentication.

If you meet the above mentioned criterion, then you can change the authentication of the site to Kerberos. To change the Authentication Provider to Kerberos, navigate to Central Admin site then click “Application Management” => Manage Web Applications => Select your web application => Click Authentication Provider from ribbon button as shown below:

image

Figure 4: Change Authentication Provider

In the Authentication provider windows click on the zone you want to configure the Kerberos Authentication. Then you will be shown ‘Edit Authentication’ window. If your web application is using NTLM you can change the Authentication to Kerberos as shown below:


image

Figure 5: Change NTLM to Kerberos

When you change the authentication type from NTLM to Kerberos you will be prompted with message saying “” as shown below. You don’t need to worry, we’ll configure other settings to use Kerberos. So just click ok button when the message appears and then save the settings.

image

Figure 6: Warning appears during Authentication changes from NTLM to Kerberos

 

Step 2: Configure Service Principal Name (SPN) in Active Directory

So your web application is configured for Kerberos Authentication but you need to configure Service Principal Name (SPN). Simply SPN is an unique identifier for each service (HTTP, SQL, AD etc) running in the server. An SPN is a combination of service name, host name and port name. The original format for SPN is

<Service Name>/<DNS Host>:Port

To know more about SPN, you can follow the link: http://technet.microsoft.com/en-us/library/cc961723.aspx. For our web application we need to create SPN. The SPN format for our web application is as shown below:

  • HTTP/<DNS Host Name>:Port
  • HTTP/<DNS FQDN>:Port

In my case the SPN are:

  • HTTP/sohel-server:5000
  • HTTP/sohel-server.sohel.com/5000

However, if you are using any port other than 80, you need to add four SPNs (two for 80 port and two for your non-80 web application port). Whether you use Kerberos for 80 port, you need to add SPNs for default port. So though I’m configuring Kerberos for HTTP port 5000, I need to configure Kerberos for 80 port also. The following SPNs are need to configured for my example.

  • HTTP/sohel-server
  • HTTP/sohel-server.sohel.com
  • HTTP/sohel-server:5000
  • HTTP/sohel-server.sohel.com:5000

How to set SPN?

  1. Make sure you installed ‘Active Directory Lightweight Directory Services’ from Server Role to get the ADSI Edit UI for editing SPN values. You can add the  ‘Active Directory Lightweight Directory Services’ from Server Manager => Add Roles  as shown below:

    image
    Figure 7: Install ‘Active Directory Lightweight Directory Services’ from ‘Add Server Role’

  2. To setup SPN, Run the command “adsiedit.msc” in either command prompt or from Run. You will get the ADSI Edit window.
  3. In ADSI Edit window, expand the ‘Default naming context’ and expand CN=Users and find the user you used for application pool in web application.
  4. Right click on the user entry CN=UserName and select properties window. Then find the property ‘servicePrincipalName’ and click edit as shown below:

    image
    Figure 8: Set SPN through servicePrincipalName

  5. Finally add the SPNs in the edit window as shown below:

    image
    Figure 9: Add SPN values as value of attribute ‘servicePrincipalName’.

  6. Press OK and then apply to close the dialog.

 

Step 3: Enable delegation

In some cases you may need to enable delegation of credentials. To enable delegation, open the Active Directory users and Computers from ‘Administrative Tools’ menu. Find the user used in Application pool under ‘Users’ node. Right click on the user and click Properties to get the properties window. Then in the properties window go to ‘Delegation’ tab and select ‘Trust this user for…’ as shown below:

image

Figure 10: Enable delegation

 

Step 4: Configure Internet Explorer

Finally you need to configure Internet Explorer (IE) to use current windows user to access the SharePoint site.

  1. Go to Tool => Internet Options. Then select ‘Local Intranet’ and click Sites as shown below:

    image
    Figure 11: Setup IE for adding the SharePoint site to local Intranet

  2. After ‘Local Intranet’ dialog select ‘Advanced’ and then you’ll find the way to add sites to local intranet. Add ‘*.yourdomain’ in the local intranet zone as shown below:
    image
    Figure 12: Adding my domain (sohel.com) to local intranet.

  3. Now close the Internet Options dialog. Then open the ‘Internet Options’ dialog from Tools => Internet Options. Then go to Security tab and select ‘Local Intranet’ and select ‘Custom Level’. Then At the end of the ‘Security settings’ window, select ‘Automatic login only in Intranet zone’ as shown below:
    image
    Figure 13: Enable automatic login for Intranet zone

 

Conclusion

Configuring Kerberos authentication may depends on many factors. So I can’t guarantee than each and every steps described here will work for everybody. But the overall sets of configurations are same. You need to configure SharePoint site, You need to configure SPN, You need to enable delegation (if required), you n need to configure Internet Explorer.  You can get elaborate description of configuring Kerberos Authentication with SharePoint 2010 from the link: http://www.microsoft.com/download/en/details.aspx?id=23176.

Sunday, October 9, 2011

SharePoint 2010: Get Full or Relative Url of web using EcmaScript

Sometimes from client side, you need to know the current web url. And for this little information you don’t want to call EcmaScript’s load function to get information from server side. Actually the information can be found without any server call. You can access the information from ClientContext as shown below.

var context = new SP.ClientContext();
var relativeWebUrl = context.get_url();

Remember the get_url method will only return relative url of the site. As shown in the following table:

Site Collection Url Site Url context.get_url() response
http://mysite.com http://mysite.com /
http://mysite.com http://mysite.com/site1 /site1
http://mysite.com/sites http://mysite.com/sites/site1 /sites/site

 

So if you need to know the full url of the site you can do so easily with the following script:

function getFullWebUrl() {
var context = new SP.ClientContext();
var relativeWebUrl = context.get_url();
var fullWebUrl = window.location.protocol + '//' + window.location.host + relativeWebUrl ;
alert(fullWebUrl);
}

Saturday, September 17, 2011

SharePoint 2010: Access WCF Service with jQuery

In one of my earlier post I described how to develop a custom WCF service. Today I’ll cover how you can invoke the SharePoint WCF Service from jQuery. In my last post I described to develop a SOAP web service but for using WCF service from jQuery I’m going to use REST web service. For the list of service types and factories supported in SharePoint you can visit the link in MSDN. You can download source code from the link given at the end of the post.

Prepare the service to call from jQuery

Consider developing a service as described in my earlier post with the following changes:

  • For  using json I’ve used REST service factory ‘Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory’ as shown below. You can use SOAP factory but you then need to parse data in different way.
    <%@ ServiceHost Language="C#" Debug="true"
    Service="AccessSPServiceFromJQuery.MyService, $SharePoint.Project.AssemblyFullName$"
    CodeBehind="MyService.svc.cs"
    Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0,
    Culture=neutral, PublicKeyToken=71e9bce111e9429c"
    %>


  • Next you need to specify the return type to json in the service interface as shown below. I’ve specified both request and response type to json in WebInvoke attribute:

    [ServiceContract]
    public interface IMyService
    {
    [OperationContract]
    [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    List<Product> SearchProduct(string productName);


    [OperationContract]
    [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    bool Save(Product product);
    }

One thing to notice here is that you can’t access the service in browser with mex endpoint. For example if you service is http://myserver/myservice.svc, then the url http://myserver/myservice.svc/mex will not work for service created with MultipleBaseAddressWebServiceHostFactory.
 

Call Service with jQuery

The next step is to call the service with jQuery. The url of the service to be used in jQuery will be service url and method name. For example if you service url is ‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc’ and the method name you want to invoke is ‘Search’ then the full url will be ‘/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/Search’. As shown in the code below, you can invoke the service Search by passing the parameter in data field of ajax call of jquery

function getProductFromService(searchText) {
try {
$.ajax({
type: "GET",
url: '/_vti_bin/AccessSPServiceFromJQuery/MyService.svc/SearchProduct',
contentType: "application/json; charset=utf-8",
data: { "productName": searchText },
dataType: 'json',
success: function (msg) {
WCFServiceGetSucceeded(msg);
},
error: WCFServiceGetFailed
});
}
catch (e) {

alert('error invoking service.get()' + e);
}
}
function WCFServiceGetSucceeded(result) {
alert('success');
}
function WCFServiceGetFailed(error) {
alert('Service Failed.');
}

Download and use code

I’ve uploaded the code for this post in my skydrive. You can download the code from the link below. To use the code please ensure you have internet connection as I’ve used jqery from Microsoft CDN. The search functionality get all products matching name. You can try to search just by typing a single character. You can debug and test the code. In save I’ve just shown you can pass value from browser to service using POST method.

Wednesday, August 24, 2011

SharePoint 2010: Postback to the same page from Ribbon

Most of the examples related to ribbon button actions involve opening dialog. However, if you need to send post back request to the same page/dialog where the ribbon exists, you need to trick a bit. Let’s explain how you can do so.

Define Ribbon XML

You can define the postback action in the command action in Ribbon xml file. To do so, you can use javascript function _doPostBack(‘token’,’’). This will send a postback request to the same page.

<CommandUIHandler
Command="MyButton.Command"
CommandAction="javascript:__doPostBack('MyButtonPostback','');"
EnabledScript="true" />
Figure 1: PostBack action defined in Ribbon xml

 

Identify the PostBack request in the page

The second step is to identity from code behind file, if the postback occurred from ribbon button’s action. From the page load, you can check if the postback occurred due to the command “MyButton.Command”. To do so we can have a check shown below in the page load method.

if (Page.Request["__EVENTTARGET"] == "MyButtonPostback")
{
//The ribbon button initiated the postback
}

 

 

Though this is very simple trick but might be helpful for someone.

Tuesday, August 23, 2011

SharePoint 2010: Modifying and Deploying Ribbon doesn’t update the ribbon

Recently I’ve been working extensively with Ribbon. So what I did, I developed a ribbon and attached the ribbon to a feature. Then after modifying the ribbon in Visual Studio I deployed the ribbon again to see the changes. But interestingly the modification was not working. The ribbon was deployed successfully for the first time. But later I updated the ribbon xml in Visual studio and redeployed and the update to the ribbon was not showing in the site though the deployment was successful. Event I tried to deactivate/activate the ribbon feature but no luck. So the problem was ribbon update was not showing in effect in the site event after successful deployment.

 

Solution

Finally I found the solution from Sandrino Di Mattia’s post here. Basically, You need to modify the feature version every time you modify the ribbon and redeploy. First find which feature the ribbon is associated with. Then open the feature properties window and modify the feature version as shown below:

image

Figure 1: Change Feature Version

Another solution might be to clear your browser cache.

 

Conclusion

So changing the feature version or clearing the browser cache or private browsing might be solution for getting ribbon update in browser.

Sunday, June 26, 2011

SharePoint 2010: Approve/Reject dialog customization, show changed values

SharePoint provide rich support for approval process. You can maintain version of changes, you can use built-in workflows or develop your own for approval process. You can even create custom workflow activities and use it in SharePoint Designer to create your own approval workflow. Unfortunately, SharePoint doesn’t provide a nice UI where approver can get a snapshot of what’s changes he’s going to approve/reject. What we are familiar with the following UI:

image

Figure 1: Very generic UI to approve/reject

 

What if we could have a dialog as shown below:

image

Figure 2: Custom Approve/Reject dialog with modification highlighted

As shown in figure 2, the approver will have the better look of what’s the changes he’ll approve/reject. As shown in figure 2, the person who will approve/reject, can get a snapshot of what changes are waiting for his/her approval.

 

What’s the cost of custom approve/reject dialog?

Now the question comes what’s the development cost of such a custom approve/reject dialog? I’ve just developed few classes for returning a list of items with three fields (Field Name, Old Value and new Value) which can be bound to a grid. I’ve already provide the source code in here. But the development process is described below:

Create a custom action menu: You can hide the custom approve/reject menu or you can keep it in place. What I’ve done is included a new custom action menu ‘Approve/Reject Single’ as shown in the image below.

image

Figure 3: Custom action menu (Approve/Reject Single)

 

Create custom Application Page: Next you need to develop a custom application page which will be shown in the dialog when the custom action menu (show in figure 3) will be clicked. The custom application page will show the changes (field name, old value and new value) as shown in figure 2.

Download and test the code

If you have downloaded my last code from blog “Approve/Reject Multiple Items” please uninstall the solution first. Either you may find conflict as I’ve used the source code from that post and modified for this post. You can download the code for this post from my MSDN code gallery http://archive.msdn.microsoft.com/SP2010ApproRejectExt. Then from download tab download the second file “SharePoint.ApproveRejectTestWithVisual”.

Conclusion

The provided code is not something that you can just download and deploy in production. The code is just for can-do sample which shows such a nice view of changed items possible.

Wednesday, June 15, 2011

SharePoint 2010: Customize SharePoint Add/Edit/Display Form

When you create a SharePoint list the default SharePoint add/edit/display form get its looks by its own. For example the fields appears in the add/edit/display form based on the sequence you added the fields. Also by default all fields of the list are shown in the forms. Sometimes you may need to give a hand to customized that look and feel. I’ll try to give some light on how you can customize the default add/edit/view form of SharePoint list.

 

Enable Content type Management First

To customize the List forms you need to enable ‘content type management’. You can do so from List settings Page and then click ‘Advance Settings’. Then select yes for “Allow management of content types” as shown below:

image

Figure 1: Enable content type management.

 

Once you have enabled the content type for a list you will find a available content types associated with the lists under ‘content types’ section of list settings page as shown below:

image

Figure 2: Content type management section in list settings page

 

Hide fields from add/edit/display form

Sometimes you may want to hide some fields from add/edit/display form. Scenario might be you don’t want users to edit the field directly, rather the hidden field’s data will be populated differently (maybe from event receiver or timer job). To do so click on the Content Type (usually Item) and then you will be landed in a page as shown below:

image

Figure 3: Item Content Type editing page

 

As you see from figure 3, the content type page is showing all my field but only Product Name (internally the field name is Title) is coming from Item content type. Other fields are added by myself. Now let’s say you want to hide the launchDate field from add/edit/view form. To do so click the field link ‘Launch Date’ and you will be taken to a page as shown below. From that page you can hide a field.

image

Figure 4: Hide fields if needed

 

For your information, the hidden field will not appear in add/edit/display from but you can still access the field in list views.

 

Reorder Fields in add/edit/display form

You can reorder how the fields will appear in the list add/edit/display from. To do so take a look a the figure 3. You will find a link “Column Reorder” at the bottom of the item. Click the link and you will be moved to a page as shown below where you can reorder the presence of the fields in add/edit/display form.

image

Figure 5: Reorder fields in add/edit/view forms

 

Want more customization?

If you are not even happy you can create your own custom add/edit/display from as described my another post. Also you can even edit the add/edit/display from in infopath. To do so open the site in IE browser and the navigate to list settings page. And then click “Form Settings” as shown below:

image

Figure 6: From settings option in list settings page.

 

Clicking on the form settings page, you will be navigated to a page as shown below:

image

Figure 7: Form settings page.

 

Clicking ok in the page as shown in figure 7, you will be asked to open the page in InfoPath editor as shown below. However you need to use IE browser to open the InfoPath editor directly from browser:

image

Figure 8: Edit form in InfoPath.

 

I’m not going to bring InfoPath in today’s discussion as this can be more complex. However If I get chance I’ll come back to you with a post on “how to use InfoPath to edit the form”.