HubConnection.Start throws error only when called from singleton object - c#

I have built a notification system with the following code:
class SignalRClient
{
HubConnection hubconn;
IHubProxy proxy;
public SignalRClient(string url)
{
hubconn = new HubConnection(url);
proxy = hubconn.CreateProxy("XXX.NotificationHub");
hubconn.Start().Wait();
}
public void SendMessage()
{
proxy.Invoke("LiveNotify", new { Application = "SRWinClient", Server = Environment.MachineName, Message = "This is a test", ImgId= 2 });
}
}
This works great when i trigger it from a test windows forms app (on a button click), but when i call if from a singleton object that i have it fails on the Start().Wait(). I have copy pasted the code and checked a number of times to make sure there were no typos.
Here is my notification singleton. It does more than the SignalR bit. it updates Databases and more, but here is the relevant parts:
public class CDSNotifier
{
private static object mLock = new object();
private static CDSNotifier mnotifier = null;
private bool enableSignalRNotifications = false;
private SignalRNotifier snotifier;
private CDSNotifier()
{
NameValueCollection appSettings = ConfigurationManager.AppSettings;
try
{
enableSignalRNotifications = Convert.ToBoolean(appSettings["EnableSignalRNotifications"]);
}
catch { };
if (enableSignalRNotifications)
{
snotifier = new SignalRNotifier(appSettings["SignalRHubURL"]);
}
}
public static CDSNotifier Instance
{
get
{
if (mnotifier == null)
{
// for thread safety, lock an object when
lock (mLock)
{
if (mnotifier == null)
{
mnotifier = new CDSNotifier();
}
}
}
return mnotifier;
}
}
public void Notify(int applicationId, int? companyId, string message, NotificationType type, string server)
{
.....
try
{
if (enableSignalRNotifications)
snotifier.SendMessage(applicationId, message, type);
}
catch { }
}
Exception that I am getting:
System.AggregateException
Message: One or more errors occured
StackTrace: at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()

I finally figured it out. My notification system was a separate lib and my executable's bin was not getting the Newtonsoft.JSON dlls. I added the package using nuget to my primary projects and it worked like a charm.
#M.Babcock thanks for leading me in the right direction. i looked at the exceptions but i was looking at the one that said "InnerExceptions" (the one with s), that did not have any info. but when i looked in to "InnerException" i found more info.

Related

Firebase Function throwing internal error when trying to call it from Unity

I work on a Unity C# app with Firebase Auth and Firebase Functions SDK installed.
I have three callable functions I developed and tested thanks to the Firebase emulators and they seem to work correctly.
I deployed my functions, launched the game in Unity Editor and I get an error whenever I call a function. The error is always INTERNAL.
I checked the logs on Google Cloud dashboard and it seems my function doesn't even run.
I put a breakpoint and decide to inspect the exception to gather some information.
However, there isn't any useful information other than "One or more errors occurred" and "INTERNAL".
After numerous searches on Google/SO I've found two possible culprits :
Outdated SDK -> I redownload latest SDK and re-import Firebase Auth and Firebase Functions into my Unity project --> same error.
Need to specify region when getting the Functions instance if different than us-central1. According to the Google dashboard my functions are located in the us-central1 region but just in case I specify it anyway --> same error.
Then I notice that my actual Firebase project is in europe-west3 so I specify this in my code when getting the instance of Firebase Functions or App --> still the same error.
Now I'm starting to doubt everything so I comment out UseFunctionsEmulator() and test again with the emulators -> it works fine.
What could be the problem?
Here is my FirebaseManager.cs that run before anything else:
public class FirebaseManager : MonoBehaviour
{
private static bool gameQuitting = false;
private static readonly object Lock = new object();
private static FirebaseManager _instance;
public static FirebaseManager Instance
{
get
{
// [check if instance exists etc..]
}
}
private FirebaseApp _app;
private FirebaseAuth _auth;
public FirebaseAuth Auth
{
get
{
if (_auth == null)
{
_auth = FirebaseAuth.GetAuth(_app);
}
return _auth;
}
}
private FirebaseUser _user;
public FirebaseUser User
{
get
{
return _user;
}
set
{
_user = value;
}
}
private FirebaseFunctions _func;
public FirebaseFunctions Func
{
get
{
if (_func == null)
{
_func = FirebaseFunctions.DefaultInstance;
}
return _func;
}
}
// Events to subscribe to for this service
public delegate void FirebaseInitialized();
public static event FirebaseInitialized OnFirebaseInitialized;
public static bool IsInitialized = false;
private void Awake()
{
if (_instance == null)
{
DontDestroyOnLoad(this.gameObject);
_instance = this;
}
else { Destroy(this.gameObject); }
}
private void Start()
{
InitializeFirebase();
}
private void InitializeFirebase()
{
Debug.Log($"FirebaseManager.cs > INITIALIZING FIREBASE");
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available)
{
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
_app = FirebaseApp.DefaultInstance;
// _app = FirebaseApp.GetInstance("europe-west3");
// Create and hold a reference to FirebaseAuth
_auth = FirebaseAuth.DefaultInstance;
// Create and hold a reference to already logged in user (if any)
_user = _auth.CurrentUser;
// Create and hold a reference to Functions
_func = FirebaseFunctions.DefaultInstance;
// _func = FirebaseFunctions.GetInstance(FirebaseApp.DefaultInstance, "europe-west3");
// _func = FirebaseFunctions.GetInstance("europe-west3");
// #if UNITY_EDITOR
// _func.UseFunctionsEmulator("http://localhost:5001"); // LOCAL FUNCS
// #endif
// Subscribing to AuthStateChanged
FirebaseManager.Instance.Auth.StateChanged += AuthService.AuthStateChanged;
Debug.Log($"FirebaseManager.cs > INITIALIZED");
IsInitialized = true;
if (OnFirebaseInitialized != null) OnFirebaseInitialized.Invoke();
}
else
{
UnityEngine.Debug.LogError(System.String.Format(
"FirebaseManager.cs > Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
}
private void OnDestroy()
{
if (_auth != null) _auth = null;
}
private void OnApplicationQuit()
{
FirebaseManager.Instance.Auth.StateChanged -= AuthService.AuthStateChanged;
gameQuitting = true;
}
}
I call my function from Unity like this :
HttpsCallableReference function = FirebaseManager.Instance.Func.GetHttpsCallable("GetAllCharacters");
// Call the function and extract the operation from the result.
function.CallAsync().ContinueWithOnMainThread((task) =>
{
if (task.IsFaulted)
{
// this foreach is a debug attempt
foreach (var e in task.Exception.Flatten().InnerExceptions)
{
Debug.LogWarning($"Received Exception: {e.Message}");
}
foreach (var inner in task.Exception.InnerExceptions)
{
if (inner is FunctionsException)
{
var e = (FunctionsException)inner;
// Function error code, will be INTERNAL if the failure
// was not handled properly in the function call.
var code = e.ErrorCode;
var message = e.Message;
Debug.LogError($"Code: {code} // Message: {message}");
// [Handle error]
}
}
}
else
{
// [Handle data returned by the function]
}
});
Finally, my Firebase Functions look like this: (index.ts)
import * as Characters from "./Characters/Characters";
// CHARACTERS
export const CreateNewCharacter = Characters.CreateNewCharacter;
export const GetAllCharacters = Characters.GetAllCharacters;
export const DeleteCharacterByID = Characters.DeleteCharacterByID;
Characters.ts:
import * as functions from "firebase-functions";
import { initializeApp } from "firebase-admin/app";
// [custom classes imports]
// DATABASE INITIALIZATION
initializeApp();
const db = getFirestore();
// CREATE NEW CHARACTER
export const CreateNewCharacter =
functions.https.onCall(async (data, context) =>
{
...
});
// GET ALL CHARACTERS
export const GetAllCharacters =
functions.https.onCall(async (data, context) =>
{
...
});
// DELETE CHARACTER BY ID
export const DeleteCharacterByID =
functions.https.onCall(async (data, context) =>
{
...
});
In step-by-step debugging, here is what I find:
The StackTrace value is :
" at Firebase.Functions.HttpsCallableReference.b__9_0 (System.Threading.Tasks.Task'1[TResult] task) [0x00063] in <9b40ff23f61a4fcf97a5710997860279>:0 \n at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2[TAntecedentResult,TResult].InnerInvoke () [0x00024] in <4ba27aa039714eafa1e8892e51af2932>:0 \n at System.Threading.Tasks.Task.Execute () [0x00000] in <4ba27aa039714eafa1e8892e51af2932>:0 "

Unable to use logger for task

I have a situation where there is a synchronous call to a method and based on a parameter we switch the response for sync /async and inside async we start a task as below. The problem is tracer works until its outside the Task() but not inside. Is it happening that Task cannot access the parent thread data ?
RequestProcessor.cs file code:
public classA_Res GetListbyUserRequest(ApiRequest<object> request)
{
if(request.IsAsync)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call started"); // this works/ gets logged in db
var taskProcessEventsResponseAsync = new Task(() =>
ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId));
taskProcessEventsResponseAsync.Start();
}
else
{
response=DataManager.Instance.GetListbyUserRequest(); // this gets paginated data for UI
}
//some code for response that request has been put down for export async.
}
private void ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call in progress"); // this doesnt works/ doesnt gets logged in db but also doesnt throws any error
//some code for processing data in chunks and creating files on server
}
LocalTracer.cs
public interface ILocalTracer
{
void TraceInformation(AVEventType eventType, DummyParameter dummy = null);
}
public sealed class LocalTracer:ILocalTracer
{
static ILocalTracer _instance = new LocalTracer();
public static ILocalTracer Instance
{
get { return _instance; }
set { _instance = value; }
}
private LocalTracer()
{
}
public static void TraceInformation(AVEventType eventType, string sMessage = "", string
userName = "", string ipAddress = "",.....)
{
//tracer code
}
public void TraceInformation(AVEventType eventType, DummyParameter dummy = null)
{
TraceInformation(eventType, "");
}
}
Please assume all this code in proper try catch blocks.

Xamarin app crash when attempting to sync SyncTable

I making an app using xamarin and azure mobile service. I am attempting to add offline sync capabilities but I am stuck. I have a service which looks like this
class AzureService
{
public MobileServiceClient Client;
AuthHandler authHandler;
IMobileServiceTable<Subscription> subscriptionTable;
IMobileServiceSyncTable<ShopItem> shopItemTable;
IMobileServiceSyncTable<ContraceptionCenter> contraceptionCenterTable;
IMobileServiceTable<Member> memberTable;
const string offlineDbPath = #"localstore.db";
static AzureService defaultInstance = new AzureService();
private AzureService()
{
this.authHandler = new AuthHandler();
this.Client = new MobileServiceClient(Constants.ApplicationURL, authHandler);
if (!string.IsNullOrWhiteSpace(Settings.AuthToken) && !string.IsNullOrWhiteSpace(Settings.UserId))
{
Client.CurrentUser = new MobileServiceUser(Settings.UserId);
Client.CurrentUser.MobileServiceAuthenticationToken = Settings.AuthToken;
}
authHandler.Client = Client;
//local sync table definitions
//var path = "syncstore.db";
//path = Path.Combine(MobileServiceClient.DefaultDatabasePath, path);
//setup our local sqlite store and intialize our table
var store = new MobileServiceSQLiteStore(offlineDbPath);
//Define sync table
store.DefineTable<ShopItem>();
store.DefineTable<ContraceptionCenter>();
//Initialize file sync context
//Client.InitializeFileSyncContext(new ShopItemFileSyncHandler(this), store);
//Initialize SyncContext
this.Client.SyncContext.InitializeAsync(store);
//Tables
contraceptionCenterTable = Client.GetSyncTable<ContraceptionCenter>();
subscriptionTable = Client.GetTable<Subscription>();
shopItemTable = Client.GetSyncTable<ShopItem>();
memberTable = Client.GetTable<Member>();
}
public static AzureService defaultManager
{
get { return defaultInstance; }
set { defaultInstance = value; }
}
public MobileServiceClient CurrentClient
{
get { return Client; }
}
public async Task<IEnumerable<ContraceptionCenter>> GetContraceptionCenters()
{
try
{
await this.SyncContraceptionCenters();
return await contraceptionCenterTable.ToEnumerableAsync();
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.Message);
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
}
return null;
}
public async Task SyncContraceptionCenters()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
//await this.Client.SyncContext.PushAsync();
await this.contraceptionCenterTable.PullAsync(
//The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
//Use a different query name for each unique query in your program
"allContraceptionCenters",
this.contraceptionCenterTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
// Simple error/conflict handling. A real application would handle the various errors like network conditions,
// server conflicts and others via the IMobileServiceSyncHandler.
if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
//Update failed, reverting to server's copy.
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change.
await error.CancelAndDiscardItemAsync();
}
Debug.WriteLine(#"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
}
}
}
I am getting this error:
System.NullReferenceException: Object reference not set to an instance of an object. When the SyncContraceptionCenters() is run. As far as I can tell I reproduced the coffeeItems example in my service But I am stuck.
I think I found the solution. The issue was the way the tables were being synced.
by calling SyncContraceptionCenters() and SyncShop() at the same time shopItemtable.PullAsync and contraceptionTable.PullAsync were happening at the same time. Which is bad apparently bad. So but putting them in the same method and awaiting them they run separately and they work as expected.

Application Insights with invalid instrumentation key - how to handle as no error is thrown

Is there a way to capture an error when when an invalid instrumentation key is used when tracing messages to Application Insights?
I'm programmatically specifying an instrumentation key like below but no exception is thrown. I'm trying to build a Logging WebApi that will return a success or failure dependent on whether the message was successfully logged to Application Insights?
TelemetryConfiguration config = TelemetryConfiguration.CreateDefault();
config.InstrumentationKey = "ABC";
client.TrackTrace("Test"),SeverityLevel.Information);
You should implement your own channel that implements ITelemetryChannel, and handle exceptions as you want.
Here's a naive example:
public class SynchronousTelemetryChannel : ITelemetryChannel
{
private const string ContentType = "application/x-json-stream";
private readonly List<ITelemetry> _items;
private object _lock = new object();
public bool? DeveloperMode { get; set; }
public string EndpointAddress { get; set; }
public SynchronousTelemetryChannel()
{
_items = new List<ITelemetry>();
EndpointAddress = "https://dc.services.visualstudio.com/v2/track";
}
public void Send(ITelemetry item)
{
lock (_lock)
{
_items.Add(item);
}
}
public void Flush()
{
lock (_lock)
{
try
{
byte[] data = JsonSerializer.Serialize(_items);
new Transmission(new Uri(EndpointAddress), data, ContentType, JsonSerializer.CompressionType).SendAsync().Wait();
_items.Clear();
}
catch (Exception e)
{
// Do whatever you want.
}
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
Then, initialize the configuration with your channel via code or configuration file:
TelemetryConfiguration.Active.TelemetryChannel = new SynchronousTelemetryChannel();

Unknown command error when using multithread to set redis

I am using the ServiceStack.Redis C# client to talk to Redis.
With few request everything is ok, but when I get LoadRunner to request it or use multi-threading to make requests, I get some errors that say I am using the wrong command.
I check the errors, and it seems that it cut off the command, or it mess up.
Here is my code, very simple. Has anyone come across this problem? The errors happen when I call the Push method using multi-threading.
public class ImpresstionQueueService : IQueueService<InsertImpressionRequest>
{
private string _queueName;
private string _host;
private static IRedisClient redisClient = new RedisClient(ConfigHost);
private static string ConfigHost
{
get
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
private string Host
{
get
{
if (!string.IsNullOrEmpty(_host))
return _host;
else
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
}
public ImpresstionQueueService(string queue_name)
{
this._queueName = queue_name;
}
public ImpresstionQueueService(string host, string queu_name)
{
this._queueName = queu_name;
this._host = host;
}
#region IQueueService<InsertImpressionRequest> Members
class testData
{
}
public int Push(InsertImpressionRequest value)
{
try
{
//using (var redisClient = new RedisClient(this.Host))
{
//ser
string ser_value = TypeSerializer.SerializeToString<InsertImpressionRequest>(value);
//push
redisClient.AddItemToList(this._queueName, ser_value);//here will be error
}
}
catch (Exception ex)
{
HLogger.GetLogger("RedisLogger").Error(ex.Message + ex.StackTrace);
}
//throw new NotImplementedException();
return 1;
}
public InsertImpressionRequest Pop()
{
InsertImpressionRequest request = null;
//using (var redisClient = new RedisClient(this.Host))
{
string pop_string_value = redisClient.PopItemFromList(this._queueName);
//deseri
if (pop_string_value != null)
{
request = TypeSerializer.DeserializeFromString<InsertImpressionRequest>(pop_string_value);
}
}
return request;
}
#endregion
}
You are probably using the same Redis connection simultaneously from multiple threads. Both threads could possibly send commands or wait for replies at the same time. When this happens, one thread receives data intended for the other thread. This causes your error.
If you use one Redis client per thread (instead of one client per ImpresstionQueueService), each thread can send commands at the same time without interfering with each other.
Alternatively, you can create a client just for the single request (which you commented out just above the error location). The disadvantage of this alternative is the overhead of a new connection every time (which might be large or small or unnoticeable).

Categories