none
SharepointContextFilter Download RRS feed

  • Question

  • In a recent presentation @ Build, Maxim Lukiyanov used a handy filter to use with MVC applications while developing Sharepoint 2013 Apps named SharePointContextFilter.

    Does anyone know where can I download it?

    Thanks in advance.



    • Edited by cas.mendes Monday, November 12, 2012 4:02 PM typo
    Monday, November 12, 2012 4:01 PM

Answers

  • Hi Cas,

    We are working on publishing the filter on msdn. In the mean time please see below the code of the filter "as is" in the demo. There is no support for this code from Microsoft, use it as a sample to start your own implementation. Also please note that it uses session state to store SharePoint context token, this may not be appropriate for all scenarios. While there is no official support feel free to provide your feedback on the filter or ask questions in this thread. I will try to answer them as best as I can.

    using KudosMVC;
    using Microsoft.SharePoint.Client;
    using Microsoft.SharePoint.Client.Utilities;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace KudosMVC
    {
        public class SharePointContextFilterAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                SharePointContext spContext = new SharePointContext(HttpContext.Current.Request);
    
                if (spContext.IsValid)
                    filterContext.HttpContext.Session["spContext"] = spContext;
                else
                    spContext = filterContext.HttpContext.Session["spContext"] as SharePointContext;
    
                if (RedirectBackToSharePointIfNeeded(filterContext, spContext))
                    return;
    
                base.OnActionExecuting(filterContext);
            }
    
            private bool RedirectBackToSharePointIfNeeded(ActionExecutingContext filterContext,
                                                  SharePointContext spContext)
            {
                if (spContext == null)
                    spContext = SharePointContext.Current;
    
                if (!spContext.IsValid)
                {
                    // No context token, try to redirect through SharePoint to get a new one
                    // This works for book marks and expired context tokens
                    if (spContext.SPHostWebUrl != null)
                    {
                        filterContext.Result = new RedirectResult(
                            spContext.GetRedirectUrl(
                                filterContext.HttpContext.Request.Url.AbsoluteUri)
                        );
                    }
                    // No redirect information either, this should not happen during normal use of the app.
                    // Could be a bug or a hacking attempt
                    else
                    {
                        filterContext.Result = new ViewResult { ViewName = "Error" };
                    }
                    return true;
                }
    
                // Ensure Urls have SPHostUrl query parameter
                if (filterContext.HttpContext.Request.QueryString["SPHostUrl"] == null)
                {
                    BookmarkifyUrl(filterContext, spContext);
                    return true;
                }
    
                return false;
            }
    
            private void BookmarkifyUrl(ActionExecutingContext filterContext, SharePointContext spContext)
            {
                RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
                foreach (var item in filterContext.RouteData.Values)
                {
                    redirectTargetDictionary.Add(item.Key, item.Value);
                }
                redirectTargetDictionary.Add("SPHostUrl", spContext.SPHostWebUrl);
    
                filterContext.Result = new RedirectToRouteResult(redirectTargetDictionary);
            }
        }
    
        public class SharePointContext
        {
            public string ContextTokenString { get; set; }
            public SharePointContextToken ContextToken { get; set; }
            public string ServerUrl { get; set; }
            public string SPHostWebUrl { get; set; }
            public string AppRedirectBaseUrl { get; set; }
    
            string _dbConnectionString;
            public string DBConnectionString
            {
                get
                {
                    if (_dbConnectionString == null)
                    {
                        _dbConnectionString = GetDBConnectionString();
                    }
                    return _dbConnectionString;
                }
            }
    
            public bool IsValid
            {
                get
                {
                    return ServerUrl != null && ContextTokenString != null && ContextToken != null && SPHostWebUrl != null;
                }
            }
    
            public SharePointContext(HttpRequest request)
            {
                // Url of this site
                ServerUrl = request.Url.Authority;
    
                // Get context token from the request
                string contextToken = TokenHelper.GetContextTokenFromRequest(request);
                if (contextToken != null)
                {
                    try
                    {
                        ContextToken = TokenHelper.ReadAndValidateContextToken(contextToken, ServerUrl);
                    }
                    catch (Exception e)
                    {
                        ContextToken = null;
                    }
                    ContextTokenString = contextToken;
                }
    
                // Store SharePoint host web url
                SPHostWebUrl = request["SPHostUrl"];
            }
    
            public static SharePointContext Current
            {
                get
                {
                    SharePointContext spContext = HttpContext.Current.Session["spContext"] as SharePointContext;
                    if (spContext == null)
                        spContext = new SharePointContext(HttpContext.Current.Request);
                    return spContext;
                }
            }
    
            public string GetRedirectUrl(string returnUrl)
            {
                string clientId = WebConfigurationManager.AppSettings["ClientId"];
                return SPHostWebUrl +
                            "/_layouts/15/appredirect.aspx?client_id=" + clientId +
                            "&redirect_uri=" + returnUrl;
            }
    
            public ClientContext GetClientContext()
            {
                return TokenHelper.GetClientContextWithContextToken(SPHostWebUrl, ContextTokenString, ServerUrl);
            }
    
            /// <summary>
            ///  Retrieve connectionstring for app database from SharePoint
            ///  or from web.config if the app is in debug mode
            /// </summary>
            private string GetDBConnectionString()
            {
                string dbConnectionString = null;
    
                if (ContextTokenString != null)
                {
                    // retrieve DB connection string from SharePoint
                    using (var clientContext = TokenHelper.GetClientContextWithContextToken(SPHostWebUrl, ContextTokenString, ServerUrl))
                    {
                        // Use CSOM API RetrieveAppDatabaseConnectionString() to get the current connection string from SharePoint
                        ClientResult<string> connStr = AppInstance.RetrieveAppDatabaseConnectionString(clientContext);
                        clientContext.ExecuteQuery();
                        if (connStr.Value != null)
                        {
                            dbConnectionString = connStr.Value;
                        }
                        else
                        {
                            // If SharePoint doesn't have a connection string we might be in debug mode
                            // Visual Studio will store the (LocalDB) connection string in web.config
                            // under AppSettings.LocalDBInstanceForDebugging
                            dbConnectionString = WebConfigurationManager.ConnectionStrings["LocalDBInstanceForDebugging"].ConnectionString;
                        }
                    }
                }
                else
                {
                    dbConnectionString = WebConfigurationManager.ConnectionStrings["LocalDBInstanceForDebugging"].ConnectionString;
                }
    
                return dbConnectionString;
            }
        }
    }

    Best regards,

    Maxim

    • Marked as answer by cas.mendes Tuesday, November 13, 2012 3:17 PM
    Monday, November 12, 2012 7:51 PM
    Answerer

All replies

  • Hi Cas,

    We are working on publishing the filter on msdn. In the mean time please see below the code of the filter "as is" in the demo. There is no support for this code from Microsoft, use it as a sample to start your own implementation. Also please note that it uses session state to store SharePoint context token, this may not be appropriate for all scenarios. While there is no official support feel free to provide your feedback on the filter or ask questions in this thread. I will try to answer them as best as I can.

    using KudosMVC;
    using Microsoft.SharePoint.Client;
    using Microsoft.SharePoint.Client.Utilities;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Mvc;
    using System.Web.Routing;
    
    namespace KudosMVC
    {
        public class SharePointContextFilterAttribute : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                SharePointContext spContext = new SharePointContext(HttpContext.Current.Request);
    
                if (spContext.IsValid)
                    filterContext.HttpContext.Session["spContext"] = spContext;
                else
                    spContext = filterContext.HttpContext.Session["spContext"] as SharePointContext;
    
                if (RedirectBackToSharePointIfNeeded(filterContext, spContext))
                    return;
    
                base.OnActionExecuting(filterContext);
            }
    
            private bool RedirectBackToSharePointIfNeeded(ActionExecutingContext filterContext,
                                                  SharePointContext spContext)
            {
                if (spContext == null)
                    spContext = SharePointContext.Current;
    
                if (!spContext.IsValid)
                {
                    // No context token, try to redirect through SharePoint to get a new one
                    // This works for book marks and expired context tokens
                    if (spContext.SPHostWebUrl != null)
                    {
                        filterContext.Result = new RedirectResult(
                            spContext.GetRedirectUrl(
                                filterContext.HttpContext.Request.Url.AbsoluteUri)
                        );
                    }
                    // No redirect information either, this should not happen during normal use of the app.
                    // Could be a bug or a hacking attempt
                    else
                    {
                        filterContext.Result = new ViewResult { ViewName = "Error" };
                    }
                    return true;
                }
    
                // Ensure Urls have SPHostUrl query parameter
                if (filterContext.HttpContext.Request.QueryString["SPHostUrl"] == null)
                {
                    BookmarkifyUrl(filterContext, spContext);
                    return true;
                }
    
                return false;
            }
    
            private void BookmarkifyUrl(ActionExecutingContext filterContext, SharePointContext spContext)
            {
                RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
                foreach (var item in filterContext.RouteData.Values)
                {
                    redirectTargetDictionary.Add(item.Key, item.Value);
                }
                redirectTargetDictionary.Add("SPHostUrl", spContext.SPHostWebUrl);
    
                filterContext.Result = new RedirectToRouteResult(redirectTargetDictionary);
            }
        }
    
        public class SharePointContext
        {
            public string ContextTokenString { get; set; }
            public SharePointContextToken ContextToken { get; set; }
            public string ServerUrl { get; set; }
            public string SPHostWebUrl { get; set; }
            public string AppRedirectBaseUrl { get; set; }
    
            string _dbConnectionString;
            public string DBConnectionString
            {
                get
                {
                    if (_dbConnectionString == null)
                    {
                        _dbConnectionString = GetDBConnectionString();
                    }
                    return _dbConnectionString;
                }
            }
    
            public bool IsValid
            {
                get
                {
                    return ServerUrl != null && ContextTokenString != null && ContextToken != null && SPHostWebUrl != null;
                }
            }
    
            public SharePointContext(HttpRequest request)
            {
                // Url of this site
                ServerUrl = request.Url.Authority;
    
                // Get context token from the request
                string contextToken = TokenHelper.GetContextTokenFromRequest(request);
                if (contextToken != null)
                {
                    try
                    {
                        ContextToken = TokenHelper.ReadAndValidateContextToken(contextToken, ServerUrl);
                    }
                    catch (Exception e)
                    {
                        ContextToken = null;
                    }
                    ContextTokenString = contextToken;
                }
    
                // Store SharePoint host web url
                SPHostWebUrl = request["SPHostUrl"];
            }
    
            public static SharePointContext Current
            {
                get
                {
                    SharePointContext spContext = HttpContext.Current.Session["spContext"] as SharePointContext;
                    if (spContext == null)
                        spContext = new SharePointContext(HttpContext.Current.Request);
                    return spContext;
                }
            }
    
            public string GetRedirectUrl(string returnUrl)
            {
                string clientId = WebConfigurationManager.AppSettings["ClientId"];
                return SPHostWebUrl +
                            "/_layouts/15/appredirect.aspx?client_id=" + clientId +
                            "&redirect_uri=" + returnUrl;
            }
    
            public ClientContext GetClientContext()
            {
                return TokenHelper.GetClientContextWithContextToken(SPHostWebUrl, ContextTokenString, ServerUrl);
            }
    
            /// <summary>
            ///  Retrieve connectionstring for app database from SharePoint
            ///  or from web.config if the app is in debug mode
            /// </summary>
            private string GetDBConnectionString()
            {
                string dbConnectionString = null;
    
                if (ContextTokenString != null)
                {
                    // retrieve DB connection string from SharePoint
                    using (var clientContext = TokenHelper.GetClientContextWithContextToken(SPHostWebUrl, ContextTokenString, ServerUrl))
                    {
                        // Use CSOM API RetrieveAppDatabaseConnectionString() to get the current connection string from SharePoint
                        ClientResult<string> connStr = AppInstance.RetrieveAppDatabaseConnectionString(clientContext);
                        clientContext.ExecuteQuery();
                        if (connStr.Value != null)
                        {
                            dbConnectionString = connStr.Value;
                        }
                        else
                        {
                            // If SharePoint doesn't have a connection string we might be in debug mode
                            // Visual Studio will store the (LocalDB) connection string in web.config
                            // under AppSettings.LocalDBInstanceForDebugging
                            dbConnectionString = WebConfigurationManager.ConnectionStrings["LocalDBInstanceForDebugging"].ConnectionString;
                        }
                    }
                }
                else
                {
                    dbConnectionString = WebConfigurationManager.ConnectionStrings["LocalDBInstanceForDebugging"].ConnectionString;
                }
    
                return dbConnectionString;
            }
        }
    }

    Best regards,

    Maxim

    • Marked as answer by cas.mendes Tuesday, November 13, 2012 3:17 PM
    Monday, November 12, 2012 7:51 PM
    Answerer
  • Thank you Maxim.

    I wasn't being able to use this code but I found that the problem was that my Sharepoint Tools for VS2012 version was Preview1 (that didn't include the AppInstance.RetrieveAppDatabaseConnectionString).

    I will give it a try and get back to you with my feedback. 

    Tuesday, November 13, 2012 3:19 PM