private static BValue Select(string category, string path, BValue localeRoot) { var section = localeRoot[category]; if (section is null) { return(null); } var current = 0; while (true) { var len = path.IndexOf('.', current); string key; if (len < 0) { //dot in path not found, final key key = path.Substring(current); return(section[key]); } key = path.Substring(current, len); section = section[key]; if (section is null) { return(null); } current = len + 1; } }
public void TestConvertWithDifferentArraySources() { var collection = new TestConverterCollection <AValue, BValue>(new PathFormatterCollection(), configurator => { configurator.If(a => a.Condition) .Target(b => b.BOuterArray.Each().BInnerArray.Each().FirstValue) .Set(a => a.AOuterArray.Current().AFirstAFirstInnerArray.Current().Value); configurator.If(a => !a.Condition) .Target(b => b.BOuterArray.Each().BInnerArray.Each().FirstValue) .Set(a => a.AOuterArray.Current().ASecondASecondInnerArray.Current().Value); }); var converter = collection.GetConverter(MutatorsContext.Empty); var from = new AValue { AOuterArray = new[] { new AOuterValue { AFirstAFirstInnerArray = new[] { new AFirstInnerValue { Value = "123" } }, ASecondASecondInnerArray = new[] { new ASecondInnerValue { Value = "321" } }, } }, Condition = true, }; Following.Code(() => converter(from)) .Should().Throw <InvalidOperationException>() .Which.Message.Should().MatchRegex(@"^Method T Current\[T\].* cannot be invoked$"); return; #pragma warning disable 162 var expected = new BValue { BOuterArray = new[] { new BOuterValue { BInnerArray = new[] { new BInnerValue { FirstValue = "123" }, }, }, }, }; converter(from).Should().BeEquivalentTo(expected); #pragma warning restore 162 }
private bool UpdateRightsForUsersUponChangeOnSharing(List <string> _RelevantIdList, Tuple <string, List <string> >[] _RightsRegex, Controller_Rights_Internal.EChangeUserRightsForModelType _Action, Action <string> _ErrorMessageAction = null) { var WaitFor = new ManualResetEvent(false); var InternalError = new BValue <bool>(false, EBProducerStatus.MultipleProducer); var DoneStack = new ConcurrentStack <bool>(); for (var i = 0; i < _RelevantIdList.Count; i++) { for (var j = 0; j < _RightsRegex.Length; j++) { DoneStack.Push(true); } } foreach (var ChangeForUserId in _RelevantIdList) { var CurrentUserID = ChangeForUserId; foreach (var PathRegex in _RightsRegex) { var CurrentPathRegex = PathRegex; BTaskWrapper.Run(() => { if (!Controller_AtomicDBOperation.Get().GetClearanceForDBOperation(InnerProcessor, UserDBEntry.DBSERVICE_USERS_TABLE(), CurrentUserID, _ErrorMessageAction)) { _ErrorMessageAction?.Invoke("PubSub_To_AuthService->UpdateRightsForUsersUponChangeOnSharing: Atomic operation control has failed for " + UserDBEntry.KEY_NAME_USER_ID + ": " + CurrentUserID); InternalError.Set(true); try { WaitFor.Set(); } catch (Exception) { } return; } try { if (!Controller_Rights_Internal.Get().ChangeBaseUserRight( out bool _bInternalErrorOccured, true,/*important to set to true*/ _Action, CurrentUserID, CurrentPathRegex.Item1.Replace("{shareeUserId}", ChangeForUserId, StringComparison.InvariantCulture), _ErrorMessageAction, CurrentPathRegex.Item2)) { if (_bInternalErrorOccured) { InternalError.Set(true); try { WaitFor.Set(); } catch (Exception) { } return; } } } finally { Controller_AtomicDBOperation.Get().SetClearanceForDBOperationForOthers(InnerProcessor, UserDBEntry.DBSERVICE_USERS_TABLE(), CurrentUserID, _ErrorMessageAction); } DoneStack.TryPop(out bool _); if (DoneStack.Count == 0) { try { WaitFor.Set(); } catch (Exception) { } } }); } } try { if (_RelevantIdList.Count > 0) { WaitFor.WaitOne(); } WaitFor.Close(); } catch (Exception) { } //Retry if internal error occured return(InternalError.Get() == false); }
public void Add(BValue key, BValue value) { dictionary.Add(key, value); }
/// <summary> /// /// <para>CustomSubscribe:</para> /// /// <para>Subscribes to given custom topic</para> /// /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para> /// /// </summary> public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false) { if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null && BUtility.CalculateStringMD5(_CustomTopic, out string TopicMD5, _ErrorMessageAction)) { if (EnsureQueueExists(TopicMD5, out string QueueUrl, _ErrorMessageAction)) { var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer); var SubscriptionThread = new Thread(() => { Thread.CurrentThread.IsBackground = true; while (!SubscriptionCancellationVar.Get()) { ReceiveMessageResponse Response; try { using (var ReceiveMessageTask = SQSClient.ReceiveMessageAsync(QueueUrl)) { ReceiveMessageTask.Wait(); Response = ReceiveMessageTask.Result; } } catch (Exception e) { Response = null; _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace); if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } } if (Response == null || Response.Messages == null || Response.Messages.Count == 0) { Thread.Sleep(1000); continue; } var AckDictionary = new Dictionary <string, string>(); foreach (var MessageContainer in Response.Messages) { if (MessageContainer != null) { if (!AckDictionary.ContainsKey(MessageContainer.MessageId)) { AckDictionary.Add(MessageContainer.MessageId, MessageContainer.ReceiptHandle); } string Data = MessageContainer.Body; if (UniqueMessageDeliveryEnsurer != null) { UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash); if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(_CustomTopic, TimestampHash, _ErrorMessageAction)) { _OnMessage?.Invoke(_CustomTopic, Data); } } else { _OnMessage?.Invoke(_CustomTopic, Data); } } } var AckArray = new List <DeleteMessageBatchRequestEntry>(); foreach (var Current in AckDictionary) { AckArray.Add(new DeleteMessageBatchRequestEntry(Current.Key, Current.Value)); } try { using (var DeleteMessageBatchTask = SQSClient.DeleteMessageBatchAsync(QueueUrl, AckArray)) { DeleteMessageBatchTask.Wait(); } } catch (Exception e) { _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace); if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } } } }); SubscriptionThread.Start(); lock (SubscriberThreadsDictionaryLock) { SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar)); } return(true); } } return(false); }
public void Run(Action <string> _ServerLogAction = null) { var bStartSucceed = new BValue <bool>(false); var WaitForFirstSuccess = new ManualResetEvent(false); BTaskWrapper.Run(() => { var WaitForException = new ManualResetEvent(false); int FailureCount = 0; do { try { lock (Listener) { Listener.Start(); } bStartSucceed.Set(true); try { WaitForFirstSuccess.Set(); } catch (Exception) {} FailureCount = 0; try { WaitForException.WaitOne(); //Do not close WaitForException! Can be reused. } catch (Exception) { } } catch (Exception e) { _ServerLogAction?.Invoke("BWebService->Run->HttpListener->Start: " + e.Message + ", trace: " + e.Message); try { WaitForException.Set(); } catch (Exception) { } Thread.Sleep(1000); } } while (++FailureCount < 10); try { WaitForFirstSuccess.Set(); //When exhausted } catch (Exception) { } }); try { WaitForFirstSuccess.WaitOne(); //Do not close WaitForFirstSuccess! Can be reused. } catch (Exception) {} if (!bStartSucceed.Get()) { _ServerLogAction?.Invoke("BWebService->Run: HttpListener.Start() has failed."); return; } BTaskWrapper.Run(() => { _ServerLogAction?.Invoke("BWebserver->Run: Server is running. Listening port " + ServerPort); while (Listener.IsListening) { HttpListenerContext Context = null; int FailureCount = 0; bool bSuccess; do { try { lock (Listener) { Context = Listener.GetContext(); } bSuccess = true; FailureCount = 0; } catch (Exception e) { _ServerLogAction?.Invoke("BWebService->Run->HttpListener->GetContext: " + e.Message + ", trace: " + e.Message); bSuccess = false; Thread.Sleep(1000); } } while (!bSuccess && ++FailureCount < 10); if (Context == null) { continue; } BTaskWrapper.Run(() => { if (Context == null) { return; } try { Context.Response.AppendHeader("Access-Control-Allow-Origin", "*"); bool bIsWebhookRequest = BWebUtilities.DoesContextContainHeader(out List <string> _, out string _, Context, "webhook-request-callback") && BWebUtilities.DoesContextContainHeader(out List <string> _, out string _, Context, "webhook-request-origin"); if (Context.Request.HttpMethod == "OPTIONS" && !bIsWebhookRequest) { Context.Response.AppendHeader("Access-Control-Allow-Headers", "*"); Context.Response.AppendHeader("Access-Control-Allow-Credentials", "true"); Context.Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH"); Context.Response.AppendHeader("Access-Control-Max-Age", "-1"); Context.Response.StatusCode = BWebResponse.Status_OK_Code; } else { if (PrefixesToListen == null) { _ServerLogAction?.Invoke("BWebserver->Run: PrefixesToListen is null."); WriteInternalError(Context.Response, "Code: WS-PTLN."); return; } if (!LookForListenersFromRequest(out BWebServiceBase _Callback, Context)) { if (Context.Request.RawUrl.EndsWith("/ping")) { WriteOK(Context.Response, "pong"); return; } _ServerLogAction?.Invoke($"BWebserver->Run: Request is not being listened. Request: {Context.Request.RawUrl}"); WriteNotFound(Context.Response, "Request is not being listened."); return; } var Response = _Callback.OnRequest(Context, _ServerLogAction); Context.Response.StatusCode = Response.StatusCode; foreach (var CurrentHeader in Response.Headers) { foreach (var Value in CurrentHeader.Value) { if (CurrentHeader.Key.ToLower() != "access-control-allow-origin") { Context.Response.AppendHeader(CurrentHeader.Key, Value); } } } if (Response.ResponseContentType != null) { Context.Response.ContentType = Response.ResponseContentType; } if (Response.ResponseContent.Type == EBStringOrStreamEnum.String) { byte[] Buffer = Encoding.UTF8.GetBytes(Response.ResponseContent.String); if (Buffer != null) { Context.Response.ContentLength64 = Buffer.Length; if (Buffer.Length > 0) { Context.Response.OutputStream.Write(Buffer, 0, Buffer.Length); } } else { Context.Response.ContentLength64 = 0; } } else { if (Response.ResponseContent.Stream != null && Response.ResponseContent.StreamLength > 0) { Context.Response.ContentLength64 = Response.ResponseContent.StreamLength; Response.ResponseContent.Stream.CopyTo(Context.Response.OutputStream); } else { _ServerLogAction?.Invoke("BWebserver->Error: Response is stream, but stream object is " + (Response.ResponseContent.Stream == null ? "null" : "valid") + " and content length is " + Response.ResponseContent.StreamLength); WriteInternalError(Context.Response, "Code: WS-STRMINV."); return; } } } } catch (Exception e) { try { WriteInternalError(Context.Response, "An unexpected internal error has occured: " + e.Message); } catch (Exception) { } _ServerLogAction?.Invoke("Uncaught exception in the request handle: " + e.Message + ", trace: " + e.StackTrace); } finally { //Always close the stream try { Context.Response.OutputStream.Close(); } catch (Exception) { } try { Context.Response.OutputStream.Dispose(); } catch (Exception) { } //try { Context.Response.Close(); } catch (Exception) { } } }); } }); }
private bool GetUserListFromAzure(out List <UserPrincipal> _Users, string _TokenType, string _AccessToken, Action <string> _ErrorMessageAction) { _Users = null; using var Handler = new HttpClientHandler { SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, ServerCertificateCustomValidationCallback = (a, b, c, d) => true }; using var Client = new HttpClient(Handler); Client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", _TokenType + " " + _AccessToken); string ResponseString = ""; try { using var RequestTask = Client.GetAsync("https://graph.microsoft.com/v1.0/servicePrincipals/" + FetchUsersAppObjectID + "/appRoleAssignedTo"); RequestTask.Wait(); using var Response = RequestTask.Result; using var ResponseContent = Response.Content; using var ReadResponseTask = ResponseContent.ReadAsStringAsync(); ReadResponseTask.Wait(); ResponseString = ReadResponseTask.Result; if (!Response.IsSuccessStatusCode) { _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: " + ResponseString); return(false); } var Parsed = JObject.Parse(ResponseString); if (!Parsed.TryGetValue("value", out JToken Values) || Values.Type != JTokenType.Array) { _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString); return(false); } var UsersResult = new List <UserPrincipal>(); var ValuesArray = Values as JArray; var InternalFailure = new BValue <bool>(false, EBProducerStatus.MultipleProducer); var WaitFor = new ManualResetEvent(false); var RemainedTasks = new ConcurrentStack <bool>(); for (var i = 0; i < ValuesArray.Count; i++) { RemainedTasks.Push(true); } foreach (var Value in ValuesArray) { if (Value.Type != JTokenType.Object) { _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString); return(false); } var ValueObject = (JObject)Value; if (!ValueObject.TryGetValue("principalDisplayName", out JToken UserNameToken) || UserNameToken.Type != JTokenType.String || !ValueObject.TryGetValue("principalId", out JToken PrincipleIDToken) || PrincipleIDToken.Type != JTokenType.String) { _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString); return(false); } var UserName = (string)UserNameToken; var PrincipalId = (string)PrincipleIDToken; BTaskWrapper.Run(() => { if (!GetUserEmail(out string UserEmail, PrincipalId, _TokenType, _AccessToken, _ErrorMessageAction)) { InternalFailure.Set(true); WaitFor.Set(); return; } if (InternalFailure.Get()) { return; } lock (UsersResult) { UsersResult.Add(new UserPrincipal() { Name = UserName, Email = UserEmail }); } RemainedTasks.TryPop(out bool _); if (RemainedTasks.Count == 0) { WaitFor.Set(); } }); } if (ValuesArray.Count > 0) { try { WaitFor.WaitOne(); } catch (Exception) { } } try { WaitFor.Close(); } catch (Exception) { } if (InternalFailure.Get()) { _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Get user e-mail step has failed."); return(false); } _Users = UsersResult; } catch (Exception e) { if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } if (e is AggregateException) { foreach (var Inner in (e as AggregateException).InnerExceptions) { _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Aggregate->Inner: " + Inner.Message + ", Trace: " + Inner.StackTrace); } } _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: " + ResponseString + ", message: " + e.Message + ", trace: " + e.StackTrace); return(false); } return(true); }
/// <summary> /// /// <para>CustomSubscribe:</para> /// /// <para>Subscribes to given custom topic</para> /// /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para> /// /// </summary> public bool CustomSubscribe( string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false) { if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null) { _CustomTopic = GetGoogleFriendlyTopicName(_CustomTopic); if (GetSubscriber(out SubscriberServiceApiClient APIClientVar, out SubscriptionName SubscriptionNameVar, _CustomTopic, _ErrorMessageAction)) { var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer); var SubscriptionThread = new Thread(() => { Thread.CurrentThread.IsBackground = true; while (!SubscriptionCancellationVar.Get()) { PullResponse Response = null; try { Response = APIClientVar.Pull(SubscriptionNameVar, true, 1000); } catch (Exception e) { if (e is RpcException && (e as RpcException).StatusCode == StatusCode.DeadlineExceeded) { Thread.Sleep(1000); continue; } Response = null; _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace); if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } } if (Response == null || Response.ReceivedMessages == null || !Response.ReceivedMessages.Any()) { Thread.Sleep(1000); continue; } var MessageContainers = Response.ReceivedMessages.ToArray(); if (MessageContainers != null && MessageContainers.Length > 0) { var AckArray = new List <string>(); foreach (var MessageContainer in MessageContainers) { if (MessageContainer != null) { if (!AckArray.Contains(MessageContainer.AckId)) { AckArray.Add(MessageContainer.AckId); } string Topic = GetTopicNameFromGoogleFriendlyName(_CustomTopic); string Data = MessageContainer.Message.Data.ToStringUtf8(); if (UniqueMessageDeliveryEnsurer != null) { UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash); if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction)) { _OnMessage?.Invoke(Topic, Data); } } else { _OnMessage?.Invoke(Topic, Data); } } } try { APIClientVar.Acknowledge(SubscriptionNameVar, AckArray); } catch (Exception e) { if (e is RpcException && (e as RpcException).Status.StatusCode == StatusCode.InvalidArgument) { //That is fine, probably due to previous subscriptions } else { _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace); if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } } } } } }); SubscriptionThread.Start(); lock (SubscriberThreadsDictionaryLock) { SubscriberThreadsDictionary.Add(SubscriptionNameVar, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar)); } return(true); } } return(false); }
public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false) { if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null) { _CustomTopic = GetAzureFriendlyTopicName(_CustomTopic); if (EnsureTopicExists(_CustomTopic, out ITopicClient _TopicClient, _ErrorMessageAction)) { if (EnsureSubscriptionExists(_CustomTopic, _TopicClient, out Microsoft.Azure.ServiceBus.ISubscriptionClient _SubscriptionClient, _ErrorMessageAction)) { var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer); var SubscriptionThread = new Thread(() => { Thread.CurrentThread.IsBackground = true; try { // Define exception receiver handler Func <ExceptionReceivedEventArgs, Task> ExceptionReceiverHandler = (ExceptionReceivedEventArgs _EventArgs) => { _ErrorMessageAction?.Invoke($"BPubSubServiceAzure->CustomSubscribe->ExceptionReceiverHandler: {_EventArgs.Exception.Message}, Action: {_EventArgs.ExceptionReceivedContext.Action}, EntityPath: {_EventArgs.ExceptionReceivedContext.EntityPath}, Endpoint: {_EventArgs.ExceptionReceivedContext.Endpoint}, ClientId: {_EventArgs.ExceptionReceivedContext.ClientId}, Trace: {_EventArgs.Exception.StackTrace}"); RemoveSubscriberThread(_CustomTopic); if (!_SubscriptionClient.IsClosedOrClosing) { using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync()) { CloseSubscriptionTask.Wait(); } } return(Task.CompletedTask); }; // Configure the message handler options in terms of exception handling, number of concurrent messages to deliver, etc. var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceiverHandler) { // Maximum number of concurrent calls to the callback ProcessMessagesAsync(), set to 1 for simplicity. // Set it according to how many messages the application wants to process in parallel. MaxConcurrentCalls = 1, // Indicates whether the message pump should automatically complete the messages after returning from user callback. // False below indicates the complete operation is handled by the user callback as in ProcessMessagesAsync(). AutoComplete = false }; // Register the function that processes messages. _SubscriptionClient.RegisterMessageHandler(async(Message MessageContainer, CancellationToken token) => { if (MessageContainer != null) { string Topic = GetTopicNameFromAzureFriendlyName(_CustomTopic); string Data = Encoding.UTF8.GetString(MessageContainer.Body); if (MessageContainer.Label != null && MessageContainer.Label.Equals(_CustomTopic)) { _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [Internal] pub/sub message."); } else { _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [StorageAccount] pub/sub message."); } if (UniqueMessageDeliveryEnsurer != null) { UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash); if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction)) { _OnMessage?.Invoke(Topic, Data); RemoveSubscriberThread(_CustomTopic); if (!_SubscriptionClient.IsClosedOrClosing) { await _SubscriptionClient.CloseAsync(); } } } else { _OnMessage?.Invoke(Topic, Data); } await _SubscriptionClient.CompleteAsync(MessageContainer.SystemProperties.LockToken); if (_SubscribeSingleMessage) { RemoveSubscriberThread(_CustomTopic); if (!_SubscriptionClient.IsClosedOrClosing) { await _SubscriptionClient.CloseAsync(); } } } }, messageHandlerOptions); } catch (Exception e) { _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace); if (e.InnerException != null && e.InnerException != e) { _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe->InnerException: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace); } RemoveSubscriberThread(_CustomTopic); if (!_SubscriptionClient.IsClosedOrClosing) { using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync()) { CloseSubscriptionTask.Wait(); } } } while (!SubscriptionCancellationVar.Get()) { //Wait until delete Thread.Sleep(500); } if (!_SubscriptionClient.IsClosedOrClosing) { using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync()) { CloseSubscriptionTask.Wait(); } } }); SubscriptionThread.Start(); lock (SubscriberThreadsDictionaryLock) { SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar)); } return(true); } } } return(false); }