3

I have a Provider hosted app which I use to enter quote data into Sharepoint Office 365. The Host is a MVC C# Webpage.

The action in the controllers all have a similar format like this:

        [SharePointContextFilter]
    [HttpPost]
    public ActionResult SaveSOW(int id,
        string SPHostUrl,
        bool withCostings = false)
    {
        try
        {
            var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);

            using (var clientContext = spContext.CreateUserClientContextForSPHost())
            {
                var spUser = clientContext.Web.CurrentUser;
                clientContext.Load(spUser, user => user.Title);
                clientContext.ExecuteQuery();
                var sowRepo = new SOWRepository(clientContext);
                sowRep.SaveSow(data); //pseudo code 

             }
}

All the actions (besides the entry point) are callled via Jquery AJAX calls.

The problem is, after X minutes when ajax calls a action that is decorated with [SharePointContextFilter] it returns a HTTP 302 (redirect to login) error. I cant ask the usre ot re-login half way through entering a quote (which can take an hour or longer) I have tried doing clientContext:

        clientContext.RequestTimeout = Timeout.Infinite;

with no success.

I have also tried adding a loop with Javascript to keep hitting an action in the controller with [SharePointContextFilter]

    GetRefreshToken: function () {
        $.ajax({
            url: "/Refresh/RefreshToken?" + window.location.href.slice(window.location.href.indexOf('?') + 1),
            type: "GET",
            success: function (data) {
                console.log(data)
            },
            error: function (data) {
                console.log("Error refreshing token", data);
            }
        })

after a while it still sends the AJAX refresh request to appredirect.aspx

My Refresh Action is just:

[SharePointContextFilter]
[HttpGet]
public ActionResult RefreshToken()
{
    var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);


    using (var clientContext = spContext.CreateUserClientContextForSPHost())
    {
        if (clientContext != null)
        {

            return Json("Token Refreshed", JsonRequestBehavior.AllowGet);
        }
    }

    return Json("Token NOT Refreshed", JsonRequestBehavior.AllowGet);
}

}

  • Are you passing the SPHostUrl in the ajax request? – wjervis Feb 23 '17 at 12:56
  • yes I am, like so: url: "/Quote/UpdateCOS?" + window.location.href.slice(window.location.href.indexOf('?') + 1), – michael Feb 24 '17 at 10:15
  • 1
    I had this issue myself awhile back. The problem is that the SPContextToken that the ACS server returns has expiry date that's just over an hour after you get it. Since the SharePointContext class checks that token in the SharePointContextFilter, it sees that it's expired, and requires a postback to the ACS server (via the AppRedirect Url). I ended up writing my own token helper to get the Refresh and Access tokens, and I cache the Refresh token (good for 6 months at this time) in session. – wjervis Feb 24 '17 at 15:57
  • You can just modify the SharePointContext class to do the same. I went down that road initially, but was annoyed with how they wrote the class, so decided to rewrite the whole thing. – wjervis Feb 24 '17 at 15:58
  • thanks wjervis, you solved my problem. I ended up storing the refresh key in httpcontext.session and using it when contexttoken expires. i might write up a fulll answer when i finish – michael Feb 25 '17 at 0:47
2

Thanks to wjervis for giving me the solution. The problem was because the Oauth2 Access token was expiring and to my suprise the supplied SharePointContext classes do not rerfresh.

I hacked together a solution and blogged it here. Its definitely not the most elegant solution, but it'll point you in the right direction.

URL REMOVED

update Thanks to Microsoft closing SharePoint Public sites (which is what I used to host my blog on) I have now moved my blog to here:

http://www.sharepointpro.com.au/sharepoint-provider-hosted-app-redirects-after-timeout/

  • 1
    I think that this problem should be reported to Microsoft and they should fix SharePointContext class, because it seems that refresh token is not used properly. – Paweł Hawrylak Feb 25 '17 at 15:39
  • I ended up writing my own set of classes to handle the entire OAUTH dance and caching of the tokens. If I was more confident with my abilities, I'd post them here. – wjervis Feb 26 '17 at 18:28
  • this is the route I will go down eventually. half way through editing the SharePointContext I realised how much cleaner it would be to just start from scratch. – michael Feb 27 '17 at 0:42
  • 2
    I'm unable to navigate to sharepointpro.com.au/Blog/Post/26/… asking me sign in – Shujaath Khan Jul 28 '17 at 5:13
  • The link is now a 404 page – Dinerdo Aug 5 '17 at 21:53
0

You can try to create some empty GET controller action with [SharePointContextFilter] attribute and call it periodically using JavaScript. This should prevent token expiration.

  • This was my first idea, unfortunately it didn't work either. Ill update the original question – michael Feb 24 '17 at 10:16
  • @michael any update on above pls? – Shujaath Khan Jul 28 '17 at 5:21
  • 1
    I solved it and blogged about it: sharepointpro.com.au/… – michael Aug 7 '17 at 2:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.