protected virtual void OnAfterCompleted(ServiceOperationEventArgs e) { object request = null; lock (asyncRequests) { if (asyncRequests.ContainsKey(e.MsnServiceState)) { request = asyncRequests[e.MsnServiceState]; asyncRequests.Remove(e.MsnServiceState); } } if (e.MsnServiceState.AddToAsyncList) { lock (asyncStates) asyncStates.Remove(e.MsnServiceState); } if (e.AsyncCompletedEventArgs.Cancelled) { Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Async method cancelled:\r\n" + "Service: " + e.WebService.ToString() + "\r\n" + "MethodName: " + e.MsnServiceState.MethodName + "\r\n" + "PartnerScenario: " + e.MsnServiceState.PartnerScenario); } else if (e.AsyncCompletedEventArgs.Error != null) { BeforeRunAsyncMethodEventArgs reinvokeArgs = null; if (e.AsyncCompletedEventArgs.Error is WebException) { WebException webException = e.AsyncCompletedEventArgs.Error as WebException; HttpWebResponse webResponse = webException.Response as HttpWebResponse; if (webResponse != null && request != null) { if (webResponse.StatusCode == HttpStatusCode.MovedPermanently) { DeltasList deltas = NSMessageHandler.ContactService.Deltas; if (deltas == null) { throw new MSNPSharpException("Deltas is null."); } string redirctURL = webResponse.Headers[HttpResponseHeader.Location]; string preferredHostKey = e.WebService.ToString() + "." + e.MsnServiceState.MethodName; lock (deltas.SyncObject) { deltas.PreferredHosts[preferredHostKey] = FetchHost(redirctURL); deltas.Save(); } e.WebService.Url = redirctURL; reinvokeArgs = new BeforeRunAsyncMethodEventArgs(e.WebService, e.ServiceType, e.MsnServiceState, request); } } } if (reinvokeArgs == null) { OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs(e.MsnServiceState.MethodName, e.AsyncCompletedEventArgs.Error)); } else { RunAsyncMethod(reinvokeArgs); } } else { // HandleServiceHeader if (NSMessageHandler.MSNTicket != MSNTicket.Empty && (e.ServiceType == MsnServiceType.AB || e.ServiceType == MsnServiceType.Sharing)) { HandleServiceHeader(e.WebService, e.ServiceType, e.MsnServiceState); } // Fire event if (AfterCompleted != null) { AfterCompleted(this, e); } } }
protected void ChangeCacheKeyAndPreferredHostForSpecifiedMethod(SoapHttpClientProtocol ws, MsnServiceType st, MsnServiceState ss, object request) { if (st == MsnServiceType.AB || st == MsnServiceType.Sharing || st == MsnServiceType.Storage) { DeltasList deltas = NSMessageHandler.ContactService.Deltas; if (deltas == null) { throw new MSNPSharpException("Deltas is null."); } string methodName = ss.MethodName; string preferredHostKey = ws.ToString() + "." + methodName; CacheKeyType keyType = (st == MsnServiceType.Storage) ? CacheKeyType.StorageServiceCacheKey : CacheKeyType.OmegaContactServiceCacheKey; string originalUrl = ws.Url; string originalHost = FetchHost(ws.Url); bool needRequest = false; lock (deltas.SyncObject) { needRequest = (deltas.CacheKeys.ContainsKey(keyType) == false || deltas.CacheKeys[keyType] == string.Empty || (deltas.CacheKeys[keyType] != string.Empty && (deltas.PreferredHosts.ContainsKey(preferredHostKey) == false || deltas.PreferredHosts[preferredHostKey] == String.Empty))); } if (needRequest) { try { Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, ws.GetType().ToString() + " is requesting a cachekey and preferred host for calling " + methodName); switch (keyType) { case CacheKeyType.OmegaContactServiceCacheKey: ws.Url = ws.Url.Replace(originalHost, MSNService.ContactServiceRedirectionHost); break; case CacheKeyType.StorageServiceCacheKey: ws.Url = ws.Url.Replace(originalHost, MSNService.StorageServiceRedirectionHost); break; } ws.GetType().InvokeMember(methodName, System.Reflection.BindingFlags.InvokeMethod, null, ws, new object[] { request }); } catch (Exception ex) { bool getHost = false; if (ex.InnerException is WebException && ex.InnerException != null) { WebException webException = ex.InnerException as WebException; HttpWebResponse webResponse = webException.Response as HttpWebResponse; if (webResponse != null) { if (webResponse.StatusCode == HttpStatusCode.Moved || webResponse.StatusCode == HttpStatusCode.MovedPermanently || webResponse.StatusCode == HttpStatusCode.Redirect || webResponse.StatusCode == HttpStatusCode.RedirectKeepVerb) { string redirectUrl = webResponse.Headers[HttpResponseHeader.Location]; if (!string.IsNullOrEmpty(redirectUrl)) { getHost = true; lock (deltas.SyncObject) deltas.PreferredHosts[preferredHostKey] = FetchHost(redirectUrl); Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Get redirect URL by HTTP error succeed, method " + methodName + ":\r\n " + "Original: " + FetchHost(ws.Url) + "\r\n " + "Redirect: " + FetchHost(redirectUrl) + "\r\n"); } #region Fetch CacheKey try { XmlDocument errdoc = new XmlDocument(); string errorMessage = ex.InnerException.Message; string xmlstr = errorMessage.Substring(errorMessage.IndexOf("<?xml")); xmlstr = xmlstr.Substring(0, xmlstr.IndexOf("</soap:envelope>", StringComparison.InvariantCultureIgnoreCase) + "</soap:envelope>".Length); //I think the xml parser microsoft used internally is just a super parser, it can ignore everything. xmlstr = xmlstr.Replace("&", "&"); xmlstr = xmlstr.Replace("&", "&"); errdoc.LoadXml(xmlstr); XmlNodeList findnodelist = errdoc.GetElementsByTagName("CacheKey"); if (findnodelist.Count > 0 && !String.IsNullOrEmpty(findnodelist[0].InnerText)) { deltas.CacheKeys[keyType] = findnodelist[0].InnerText; } } catch (Exception exc) { Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while getting CacheKey:\r\n" + "Service: " + ws.GetType().ToString() + "\r\n" + "MethodName: " + methodName + "\r\n" + "Message: " + exc.Message); } #endregion } } } if (!getHost) { Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while getting CacheKey and Preferred host:\r\n" + "Service: " + ws.GetType().ToString() + "\r\n" + "MethodName: " + methodName + "\r\n" + "Message: " + ex.Message); lock (deltas.SyncObject) deltas.PreferredHosts[preferredHostKey] = originalHost; //If there's an error, we must set the host back to its original value. } } deltas.Save(); } lock (deltas.SyncObject) { if (originalHost != null && originalHost != String.Empty) { if (deltas.PreferredHosts.ContainsKey(preferredHostKey)) { ws.Url = originalUrl.Replace(originalHost, FetchHost(deltas.PreferredHosts[preferredHostKey])); } else { //This means the redirection URL returns respond content. lock (deltas.SyncObject) { deltas.PreferredHosts[preferredHostKey] = ws.Url; deltas.Save(); } Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "The redirect URL returns correct result, use " + ws.Url + " for " + preferredHostKey); } } // Set cache key if (st == MsnServiceType.AB) { ((ABServiceBinding)ws).ABApplicationHeaderValue.CacheKey = deltas.CacheKeys[keyType]; } else if (st == MsnServiceType.Sharing) { ((SharingServiceBinding)ws).ABApplicationHeaderValue.CacheKey = deltas.CacheKeys[keyType]; } else if (st == MsnServiceType.Storage) { ((StorageService)ws).AffinityCacheHeaderValue.CacheKey = deltas.CacheKeys[keyType]; } } } }