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); } }
SPContextTokenthat the ACS server returns has expiry date that's just over an hour after you get it. Since theSharePointContextclass checks that token in theSharePointContextFilter, 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.