SharePointContextFilter属性无法重建SharePoint上下文

时间:2017-05-24 13:04:23

标签: c# asp.net-mvc azure sharepoint sharepoint-online

我开发了一个SharePoint加载项(SharePoint Online),它托管在Azure中。该加载项是一个ASP.NET MVC应用程序。

以下是这种情况:

  1. /主页/索引:用户在应用程序的登录页面上启动,然后转到Actions部分。

  2. 操作/索引:在此页面上,用户必须选择一些参数并选择要编辑的操作

  3. 操作/编辑/ 123 :系统会打开一个表单,其中会显示一个表单,其中包含有关操作的信息。

  4. 发布:更改某些字段后,或者没有,用户点击保存按钮。

  5. 我没有在列表中显示它,但所有网址都包含SPHostUrlSPAppWebUrlSPLanguageSPClientTag& SPProductNumber参数。

    这一切都运行正常,除非用户没有与应用程序/页面进行数分钟的交互,然后保存按钮。按下按钮时,应用程序无法传递SharePointContextFilter属性。 SharePointContext没有"存在"了。以下行返回 null

    SharePointContext spContext = LoadSharePointContext(httpContext); 
    

    通常情况下,如果它不存在或不存在,代码将尝试根据请求创建它。在CreateSharePointContext方法中,contextTokenString始终为 null

    string contextTokenString = TokenHelper.GetContextTokenFromRequest(httpRequest);
    

    这是方法的代码:

    public static string GetContextTokenFromRequest(HttpRequestBase request)
    {
        string[] paramNames = { "AppContext", "AppContextToken", "AccessToken", "SPAppToken" };
        foreach (string paramName in paramNames)
        {
            if (!string.IsNullOrEmpty(request.Form[paramName]))
            {
                return request.Form[paramName];
            }
            if (!string.IsNullOrEmpty(request.QueryString[paramName]))
            {
                return request.QueryString[paramName];
            }
        }
        return null;
    }
    

    因此,如果失败,则创建和保存上下文失败,应用程序返回默认错误页面。

    这是调用控制器的jQuery代码:

    var request = $.ajax({
        url: '@Url.Action("Edit", "Actions")' + window.buildSpAppParameters(),
        data: $("#updateForm").serialize(),
        cache: false,
        type: "POST"
    });
    

    这是buildSpAppParameters函数的代码:

    function buildSpAppParameters() {
        var spHostUrl = getQueryStringParameter("SPHostUrl");
        var appWebUrl = getQueryStringParameter("SPAppWebUrl");
        var spLanguage = getQueryStringParameter("SPLanguage");
        var spClientTag = getQueryStringParameter("SPClientTag");
        var spProductNr = getQueryStringParameter("SPProductNumber");
    
        return "?SPHostUrl=" + spHostUrl +
               "&SPAppWebUrl=" + appWebUrl +
               "&SPLanguage=" + spLanguage +
               "&SPClientTag=" + spClientTag +
               "&SPProductNumber=" + spProductNr;
    }
    

    为什么这最初有效,但如果用户等了一段时间,代码就无法再次获取/创建上下文?有什么我想念的东西,怎么能解决这个问题?

    注意:我知道以下问题:Sharepoint 2013 MVC 5 provider-hosted app. Fails to authenticate on HttpPost using [SharePointContextFilter]虽然有一些有用的信息需要阅读,但它并没有帮助我。

1 个答案:

答案 0 :(得分:1)

  

这一切都很好,除非用户没有与应用程序/页面进行数分钟的交互

会话已过期且SharePointContext已丢失。所以我们需要重新生成上下文。

根据GetContextTokenFromRequest方法,应在查询字符串或表单中传递上下文标记。但是从buildSpAppParameters方法中,我们发现上下文令牌是从查询字符串传递的。查询字符串参数应命名为AppContext或AppContextToken或AccessToken或SPAppToken。

要解决此问题,您可以检查浏览器中的当前URL是否包含名为AppContext或AppContextToken或AccessToken或SPAppToken的查询参数。如果是,您可以从URL读取此参数的值,并在buildSpAppParameters方法中传递它。例如,如果您的URL包含名为AppContextToken的查询参数,则可以按如下方式修改代码。

function buildSpAppParameters() {
    var spHostUrl = getQueryStringParameter("SPHostUrl");
    var appWebUrl = getQueryStringParameter("SPAppWebUrl");
    var spLanguage = getQueryStringParameter("SPLanguage");
    var spClientTag = getQueryStringParameter("SPClientTag");
    var spProductNr = getQueryStringParameter("SPProductNumber");

    var appContextToken = getQueryStringParameter("AppContextToken");

    return "?SPHostUrl=" + spHostUrl +
        "&SPAppWebUrl=" + appWebUrl +
        "&SPLanguage=" + spLanguage +
        "&SPClientTag=" + spClientTag +
        "&SPProductNumber=" + spProductNr +
        "&AppContextToken=" + appContextToken;
}

如果您的网址不包含此类查询参数,则需要修改代码,以便在第一次获取上下文令牌时将上下文令牌存储在Cookie中。

string contextTokenString = TokenHelper.GetContextTokenFromRequest(httpRequest);
if (!string.IsNullOrEmpty(contextTokenString))
{
    HttpCookie cookie = new HttpCookie("AppContextToken", contextTokenString);
    cookie.HttpOnly = true;
    Response.Cookies.Add(cookie);
}

之后,如果令牌没有通过查询字符串传递,则可以从cookie获取上下文令牌。

public static string GetContextTokenFromRequest(HttpRequestBase request)
{
    string[] paramNames = { "AppContext", "AppContextToken", "AccessToken", "SPAppToken" };
    foreach (string paramName in paramNames)
    {
        if (!string.IsNullOrEmpty(request.Form[paramName]))
        {
            return request.Form[paramName];
        }
        if (!string.IsNullOrEmpty(request.QueryString[paramName]))
        {
            return request.QueryString[paramName];
        }
    }
    if (request.Cookies["AppContextToken"] != null)
    {
        return request.Cookies["AppContextToken"].Value;
    }
    return null;
}