【问题标题】:How do i keep the Sharepoint context when moving around an ASP.NET MVC application without using the query string?在不使用查询字符串的情况下移动 ASP.NET MVC 应用程序时如何保持 Sharepoint 上下文?
【发布时间】:2014-05-28 08:00:40
【问题描述】:

我正在 MVC 4.5 中构建一个小型应用程序。我有一个 Azure 数据库,我首先使用代码和实体框架来设置它。该应用程序托管在我的开发共享点区域中。

Home 控制器的Index() 操作具有[SharePointContextFilter] 并加载登录用户的用户名等。调试应用程序并运行第一个操作时,Sharepoint {StandardTokens} 会附加到 url,因此 SPHostUrlAppWebUrl 以及一些其他变量会添加到查询字符串中。

如果我导航到没有[SharePointContextFilter] 的操作,它工作正常,直到我导航回操作 [SharePointContextFilter]。然后我收到一条错误消息:

Unknown User
Unable to determine your identity. Please try again by launching the app installed on your site.

我认为这是因为缺少一些 Sharepoint {StandardTokens},因为如果我像这样手动将它们附加到链接:

@Url.Action("Index", "Home", new { SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Current.Request).AbsoluteUri })

并用[SharePointContextFilter] 标记其他操作,它仍然有效。

悬停这似乎是解决这个问题的一种不必要的复杂方法。我不想用[SharePointContextFilter] 标记我的应用程序中的每一个操作,并手动将{StandardTokens} 插入到我创建的每个链接的查询字符串中。难道不能以某种方式将此信息保存到会话或 cookie 中,所以我不必这样做吗?

供参考,这里有一些代码:

HomeController.Index(),第一个运行的Action。

    [SharePointContextFilter]
    public ActionResult Index()
    {
        User spUser = null;

        var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);

        using (var clientContext = spContext.CreateUserClientContextForSPHost())
        {
            if (clientContext != null)
            {
                spUser = clientContext.Web.CurrentUser;

                clientContext.Load(spUser, user => user.Title);

                clientContext.ExecuteQuery();

                ViewBag.UserName = spUser.Title;
            }
        }

        return View();
    }

这是[SharePointContextFilter] 属性(由Visual Studio 生成):

/// <summary>
/// SharePoint action filter attribute.
/// </summary>
public class SharePointContextFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        SharePointContext currentContext = SharePointContextProvider.Current.GetSharePointContext(filterContext.HttpContext);

        Uri redirectUrl;
        switch (SharePointContextProvider.CheckRedirectionStatus(filterContext.HttpContext, out redirectUrl))
        {
            case RedirectionStatus.Ok:
                return;
            case RedirectionStatus.ShouldRedirect:
                filterContext.Result = new RedirectResult(redirectUrl.AbsoluteUri);
                break;
            case RedirectionStatus.CanNotRedirect:
                filterContext.Result = new ViewResult { ViewName = "Error" };
                break;
        }
    }
}

我使用的链接。来自 _Layout.cshtml 文件。:

<li id="Home"><a href="@Url.Action("Index", "Home", new { SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Current.Request).AbsoluteUri })">Home</a></li>
<li id="Contract"><a href="@Url.Action("Index", "Contract", new { SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Current.Request).AbsoluteUri })">Avrop</a></li>

如果我尝试使用标记为[SharePointContextFilter] 过滤器的 操作中的这些链接,则找不到SPHostUrl。如果我尝试链接到 标记有[SharePointContextFilter] 过滤器的操作,如果不包含SPHostUrl,我会收到上述错误。

这基本上创造了一种情况,我可以离开过滤的操作,但我永远无法返回它们。

我希望这已经足够清楚了。

【问题讨论】:

    标签: c# asp.net asp.net-mvc asp.net-mvc-4 sharepoint


    【解决方案1】:

    我们遇到了同样的问题 - ASP.NET MVC 4.5。有两件事对我们有用:

    1) 有一个 spcontext.js 文件(包含在解决方案中 - 您只需添加对它的引用),它将自动为您将令牌附加到 URL。但是,我们被要求 URL 必须看起来“不错”,因此我们选择了选项 2..

    2) 将上下文放入会话中。让过滤器先看看你的会话中是否有上下文,如果它在那里,然后使用它。如果没有,请尝试查询字符串并将检索到的上下文放入您的会话中。这意味着您最初必须使用附加到您的 url 字符串的令牌来访问您的站点,这也意味着您的上下文将在会话中存在多长时间 - 所以您必须确定是否可以。

    【讨论】:

      【解决方案2】:

      另一种选择是在如下所示的两个位置注释掉 SharePointContext 类中 SPHostUrl 的验证。没有它它可以正常工作,并且不需要传递 QueryString 参数,因为它只会将它从会话状态中拉出来。

      位置 1 位于 public SharePointContext GetSharePointContext(HttpContextBase httpContext)

          /// <summary>
          /// Gets a SharePointContext instance associated with the specified HTTP context.
          /// </summary>
          /// <param name="httpContext">The HTTP context.</param>
          /// <returns>The SharePointContext instance. Returns <c>null</c> if not found and a new instance can't be created.</returns>
          public SharePointContext GetSharePointContext(HttpContextBase httpContext)
          {
              if (httpContext == null)
              {
                  throw new ArgumentNullException("httpContext");
              }
      
              // Commented out to allow it to work without the SPHostUrl being passed around
              //Uri spHostUrl = SharePointContext.GetSPHostUrl(httpContext.Request);
              //if (spHostUrl == null)
              //{
              //    return null;
              //}
      
              SharePointContext spContext = LoadSharePointContext(httpContext);
      
              if (spContext == null || !ValidateSharePointContext(spContext, httpContext))
              {
                  spContext = CreateSharePointContext(httpContext.Request);
      
                  if (spContext != null)
                  {
                      SaveSharePointContext(spContext, httpContext);
                  }
              }
      
              return spContext;
          }
      

      位置 2 位于 protected override bool ValidateSharePointContext(SharePointContext spContext, HttpContextBase httpContext)

          protected override bool ValidateSharePointContext(SharePointContext spContext, HttpContextBase httpContext)
          {
              SharePointAcsContext spAcsContext = spContext as SharePointAcsContext;
      
              if (spAcsContext != null)
              {
                  // Commented out to allow it to work without the SPHostUrl being passed around
                  //Uri spHostUrl = SharePointContext.GetSPHostUrl(httpContext.Request);
                  string contextToken = TokenHelper.GetContextTokenFromRequest(httpContext.Request);
                  HttpCookie spCacheKeyCookie = httpContext.Request.Cookies[SPCacheKeyKey];
                  string spCacheKey = spCacheKeyCookie != null ? spCacheKeyCookie.Value : null;
      
                  // Commented out to allow it to work without the SPHostUrl being passed around
                  //return spHostUrl == spAcsContext.SPHostUrl &&
                  return !string.IsNullOrEmpty(spAcsContext.CacheKey) &&
                         spCacheKey == spAcsContext.CacheKey &&
                         !string.IsNullOrEmpty(spAcsContext.ContextToken) &&
                         (string.IsNullOrEmpty(contextToken) || contextToken == spAcsContext.ContextToken);
              }
      
              return false;
          }
      

      确保将接收带有 HTTP Post 中 SPAppToken 变量的初始请求的应用程序的登录页面调用 SharePointContext,以便创建会话变量。这可以通过在 MVC 控制器类或 MVC 操作方法上方添加以下属性来完成:

      [SharePointContextFilter]
      

      或者改为从 MVC 控制器调用以下代码行:

      SharePointContextProvider.Current.GetSharePointContext(HttpContext);
      

      【讨论】:

        猜你喜欢
        • 2016-03-12
        • 1970-01-01
        • 1970-01-01
        • 2017-12-24
        • 1970-01-01
        • 1970-01-01
        • 2023-03-14
        • 2021-09-26
        • 1970-01-01
        相关资源
        最近更新 更多