Introduction
This article discusses the approach I used to develop a mobile version for a 
Sharepoint 2010 publishing portal, after a lot of research I found that 
Sharepoint out of the box features will not fit my business needs, so you will 
find in this article the approach I used.
Note: I'm not sure that this is the best way to develop a mobile version for 
sharepoint portal so feel free to send me your feedback and comments if you have 
a better approach.
Sharepoint 2010 Mobile support limitations
Sharepoint 2010 has a mobile support but after research we found the following 
limitations
- Sharepoint 2010 doesn't allow to create a 
	custom master page for your mobile site
  - Sharepoint doesn't allow creating custom 
	style sheet and classes for mobile
  - Publishing portal template is not 
	supported
  - Any layout or any customization in the 
	master pages will affect all other sites on the same farm
 
The Approach Used in My project
- Disable SharePoint default mobile 
	redirection feature to stop the redirection to the mbllists.aspx page.
  - Create Http Module which detects that the 
	request is coming from a Mobile device and redirect to the Mobile home page.
  - Create a new sub site for mobile with an 
	optimized master page and layouts for mobile. (Physical pages and user 
	controls).
  - Multilanguage support
  - Create the Search Control and search 
	result page from scratch (Querying the Crawler results).
  - Create optimized style sheets and 
	Masterpage for mobile.
 
Limitations of this approach
- The customer will not be able to create 
	any pages for the mobile site from the back end
  - The customer will not be able to create 
	any subsites for the mobile site from the back end
  - Will not be able to use SharePoint search, 
	and the way around is to use SharePoint API and create the search controls 
	and the result page from scratch.
 
The following sections will explain how to 
implement each point
1. Disable SharePoint default mobile 
redirection feature to stop the redirection to the mbllists.aspx page
a. Open compat.browser file you will find it in the following directory
C:\inetpub\wwwroot\wss\VirtualDirectories\[port number]\App_Browsers
b. change isMobileDevice for each browser from True to False and save the file.
Example
<capabilities>
<capability name="isMobileDevice" value="false" />
<capability name="platform" value="WinCE" />
<capability name="supportsTouchScreen" value="true" />
</capabilities>
2. Create Http Module which detects that the request is coming from a Mobile 
device and redirect to the Mobile home page
This is a normal Http Module which detects that the request is coming from a 
mobile phone and redirect to the mobile site
Sample function used in the Module
public
static bool 
isMobileBrowser()
        {
            //GETS THE CURRENT 
USER CONTEXT
            
HttpContext context = HttpContext.Current;
            
//FIRST TRY BUILT IN ASP.NT CHECK
            if (context.Request.Browser.IsMobileDevice)
            {
                return
true;
            }
            //THEN TRY CHECKING 
FOR THE HTTP_X_WAP_PROFILE HEADER
            if (context.Request.ServerVariables["HTTP_X_WAP_PROFILE"]
                != null)
            {
                return
true;
            }
            //THEN TRY CHECKING 
THAT HTTP_ACCEPT EXISTS AND CONTAINS WAP
            if (context.Request.ServerVariables["HTTP_ACCEPT"] 
!= null &&
                context.Request.ServerVariables["HTTP_ACCEPT"].ToLower().Contains("wap"))
            {
                return
true;
            }
            //AND FINALLY CHECK 
THE HTTP_USER_AGENT 
            //HEADER 
VARIABLE FOR ANY ONE OF THE FOLLOWING
            if (context.Request.ServerVariables["HTTP_USER_AGENT"] 
!= null)
            {
                //Create a list 
of all mobile types
                string[] 
mobiles =
                    new[]
                {
                    "midp",
"j2me",
"avant",
"docomo", 
                    "novarra",
"palmos",
"palmsource", 
                    "240x320",
"opwv",
"chtml",
                    "pda",
"windows ce",
"mmp/", 
                    
"blackberry", "mib/",
"symbian", 
                    
"wireless", "nokia",
"hand","android",
"mobi",
                    
"phone", "cdm",
"up.b",
"audio", 
                    "SIE-",
"SEC-",
"samsung",
"htc", 
                    
"mot-", "mitsu",
"sagem",
"sony"
                    ,
"alcatel",
"lg",
"eric",
"vx", 
                    "philips",
"mmm",
"xx", 
                    "panasonic",
"sharp",
"wap",
"sch",
                    
"rover", "pocket",
"benq",
"java", 
                    
"pt", "pg",
"vox",
"amoi", 
                    
"bird", "compal",
"kg",
"voda",
                    "sany",
"kdd",
"dbt",
"sendo", 
                    "sgh",
"gradi",
"jb",
"dddi", 
                    "moto",
"iphone"
                };
                
//Loop through each item in the list created above
                //and 
check if the header contains that text
                foreach 
(string s in 
mobiles)
                {
                    if (context.Request.ServerVariables["HTTP_USER_AGENT"].
                                                        
ToLower().Contains(s.ToLower()))
                    {
                        return
true;
                    }
                }
            }
 
            return
false;
        }
We call this function in the OnBeginRequest event handler as the following
public void 
OnBeginRequest(Object s,
EventArgs e)
        {
 
            
HttpApplication app = s as
HttpApplication;
            
HttpRequest request = HttpContext.Current.Request;
            
if (isMobileBrowser())
            { 
                if (!request.Url.ToString().ToLower().Contains("/mobilesite/"))
                {
                   app.Context.Response.Redirect("/mobilesite/default.aspx");
                }
            }
        }
3. Create a new sub site for mobile with an optimized master page and layouts 
for mobile
a. To do this you create the pages and user controls using the normal ASP.NET
b. To deploy you have to options
1. Create a physical folder for the mobile site under the virtual directory then 
copy the pages and user controls and master page into it
2. Create the folder under the Sharepoint â€" using sharepoint designer â€" then 
copy the pages and user controls into it (what we implemented)
The benefit of this way is that you don't have to copy the physical files every 
time you restore the portal, it will be included in the backup file.
![moca2.jpg]()
c. Web.config
1. Each name space must be registered as safe in web.config file
Example
<SafeControl
Assembly="MOCA.VideoGallery, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=25c226a5c87bfac0"
Namespace="MOCA.VideoGallery.VideoGallery"
TypeName="*"
Safe="True"
SafeAgainstScript="False" 
/>
<SafeControl
Assembly="MOCA.UserControls, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=737b390bc690dbba"
Namespace="Linkdev.SharePoint.Search.Controls"
TypeName="*"
Safe="True"
SafeAgainstScript="False" 
/>
4. Multilanguage support
The portal saves the selected language by the user in a cookie then reads this 
value and changes the culture accordingly
Example:
Save the culture
protected void 
btnEnglish_click(object sender,
EventArgs e)
        {
            if (Request.Cookies["PMOMobileCulture"] 
== null)
            {
                
HttpCookie CultureCookie = new
HttpCookie("PMOMobileCulture");
                CultureCookie.Value =
"en";
                Response.Cookies.Add(CultureCookie);
            }
            else
            {
                Response.Cookies["PMOMobileCulture"].Value 
= "en";
            }
        }
Read the culture
if 
(Request.Cookies["PMOMobileCulture"] 
!= null)
            {
                
HttpCookie CultureCookie = Request.Cookies["PMOMobileCulture"];
                if (!String.IsNullOrEmpty(CultureCookie.Value))
                {
                    if (CultureCookie.Value.ToLower().Contains("en"))
                        selectedLanguage =
"en";
                    else
                        selectedLanguage =
"ar-AE";
                }
                else
                {
                    selectedLanguage =
"ar-AE";
                }
            }
            else
            {
                selectedLanguage =
"ar-AE";
            } 
            
Thread.CurrentThread.CurrentCulture 
=
                
CultureInfo.CreateSpecificCulture(selectedLanguage);
            Thread.CurrentThread.CurrentUICulture 
= new
	
	                
	CultureInfo(selectedLanguage);
 
5. Create the Search Control and search result 
page from scratch (Querying the Crawler results).
1. Site Crowling
a. From Central Administration Create a new content source under the Search 
Service Application
b. Select the type of content to be crawled to be (web sites)
c. Add the URL of the portal you want to crawl
![search.jpg]()
Very Important Note: All links in the site must be normal HTML anchors otherwise 
the crawler won't be able to crawl the content
d. Start the Crawler
2. Search Controls and the result page
a. The following code querying the crawling results using the keywords entered 
by the user
private
DataTable Search(string 
Keywords, out int 
totalCount)
        {
 
            DataTable 
resultsDataTable = new
DataTable();
            
SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                
SearchQueryAndSiteSettingsServiceProxy settingsProxy =
SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsServiceProxy>();
                
SearchServiceApplicationProxy searchProxy = 
settingsProxy.ApplicationProxies.GetValue<SearchServiceApplicationProxy>("MOCA_Search_Service_Application");
                
string squery = 
string.Empty;
                
StringBuilder sb = new
StringBuilder();
                sb.Append("SELECT 
Title, Path, Description, Write, Author,Rank, Size FROM Scope() WHERE 
ContentSource = 'Mobile Content Source' and FREETEXT(DEFAULTPROPERTIES,'" 
+ Keywords + "') ORDER BY Rank desc");
                
FullTextSqlQuery sqlQuery =
new 
FullTextSqlQuery(searchProxy);
                sqlQuery.ResultTypes =
ResultType.RelevantResults;
                sqlQuery.EnableStemming =
true;
                sqlQuery.TrimDuplicates =
true;
                sqlQuery.QueryText = sb.ToString();
                
ResultTableCollection resultsTableCollection = sqlQuery.Execute();
                
ResultTable searchResultsTable = 
resultsTableCollection[ResultType.RelevantResults];
                
resultsDataTable.TableName = "Results";
                resultsDataTable.Load(searchResultsTable,
LoadOption.OverwriteChanges);
            });
 
return 
resultsDataTable;