2017-07-11 16 views
2

Ich arbeite an ASP.NET MVC-Projekt.
Ich brauche etwas Zeit, um meine verrückte Situation zu erklären.
Ich versuche Push-Benachrichtigungen vom MVC-Projekt an die Android- und Apple-Geräte zu senden.
Die Senden Logik für beide korrekt sind, können Sie Ihre Zeit nicht über diese
Methode wird nicht ausgeführt ausgeführt Aufgabe

der Katastrophe bedenkt, dass ich bin vor: die statische Methode in einer statischen Klasse die verantwortlich für das Senden Die Benachrichtigung lautet nicht. (Ich bin nicht frisch Programmierer, ich habe mehr als 5 Jahre in C# Programmierung), aber ich kann eine Methode nicht aufrufen.

um Sie in den Kontext des Problems zu bringen, wird diese Methode aufgerufen und ausgeführt und die Benachrichtigung an die Geräte erreicht, wenn ich den Code auf meinem lokalen Rechner (Entwicklungsmaschine) ausführe.
Die statische Methode wird nur nicht aufgerufen, wenn ich das MVC-Projekt veröffentliche und es auf unserem Server installiere.

Woher weiß ich, dass die Methode nicht aufgerufen wird?
Da ich in einer Textdatei protokollieren, und ich eine Protokollanweisung in der ersten Zeile der Methode und eine Protokollanweisung vor dem Aufruf der Methode.
Das Protokoll, das vor dem Aufruf der Methode steht, wird ausgeführt und an die Textdatei angepasst, aber das Protokoll, das am Anfang der statischen Methode steht, wird nicht ausgeführt !!!!!.

Hier ist ein Code, und dann werde ich Ihnen sagen, was ich versucht habe, dies zu lösen.

public interface IHandler<T> where T : IMessage 
{ 
    Task Handle(T args); 
} 

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> 
{ 
    public Task Handle(RequestAdded args) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      try 
      { 
       GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId); 

       // this statment is executed, and the text log file will contains this line 
       TracingSystem.TraceInformation("Before Send Google Notification"); 

       SendersFacade.PartnerSender.Send(notification).Wait(); 
      } 
      catch (Exception ex) 
      { 
       TracingSystem.TraceException(ex); 
      } 
     }); 
    } 

    private GoogleNotification CreateAndroidPartnerAppNotification(string to) 
    { 
     return new GoogleNotification(); // some initialization and creating for the notification object. 
    } 
} 

Fassadenklasse

public static class SendersFacade 
{ 
    public static GoogleNotificationSender ClientSender { get; private set; } 
    public static GoogleNotificationSender PartnerSender { get; private set; } 
    //public static AppleNotificationSender AppleSender { get; private set; } 

    static SendersFacade() 
    { 
     ClientSender = new GoogleNotificationSender("correct api key"); 
     PartnerSender = new GoogleNotificationSender("correct api key"); 
     //AppleSender = some intialization. 
    } 
} 

Google Mitteilung senden Logic

public class GoogleNotificationSender 
{ 
    private string _authorizationToken; 
    private string AuthorizationToken 
    { 
     get { return _authorizationToken; } 
     set 
     { 
      if (string.IsNullOrEmpty(value)) 
       throw new InvalidOperationException("authorizationToken must not be null"); 
      _authorizationToken = value; 
     } 
    } 

    public GoogleNotificationSender(string authorizationToken) 
    { 
     this.AuthorizationToken = authorizationToken; 
    } 

    public async Task Send(GoogleNotification notification) 
    { 
     // ATTENTION PLEASE 
     // This method is not called, and the following line is not fleshed to the log file 
     TracingSystem.TraceInformation("Inside Send Google notification"); 

     using (HttpClient client = new HttpClient()) 
     { 
      client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken); 

      string json = notification.GetJson(); 
      StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); 

      using (HttpResponseMessage message = await client.PostAsync("https://fcm.googleapis.com/fcm/send", content)) 
      { 
       message.EnsureSuccessStatusCode(); 

       string resultAsString = await message.Content.ReadAsStringAsync(); 
       GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString); 

       if (result.Failure > 0) 
        throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}"); 
      } 
     } 
    } 
} 

Google Mitteilung Klasse

public class GoogleNotification 
{ 
    [JsonProperty("to")] 
    public string To { get; set; } 

    [JsonProperty("data")] 
    public JObject Data { get; set; } 

    [JsonProperty("notification")] 
    public JObject Notification { get; set; } 

    // some other property which is not used at all 

    internal string GetJson() 
    { 
     return JsonConvert.SerializeObject(this, 
      new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); 
    } 
} 

Was habe ich in den letzten drei Tagen versucht?

1- Stellen Sie die DLLs, die für das Debuggen bestimmt sind (nicht die veröffentlichten DLLs im Release-Modus), auf den Server ein, und das Problem wurde dadurch nicht behoben.

2- Machen Sie die SendersFacade als nicht statische Klasse, und wenden Sie das Singletone Deisng-Muster darauf, auch nicht funktioniert.

public class SendersFacade 
{ 
    public static SendersFacade Instance { get; private set; } 

    public GoogleNotificationSender ClientSender { get; private set; } 
    public GoogleNotificationSender PartnerSender { get; private set; } 
    //public static AppleNotificationSender AppleSender { get; private set; } 

    static SendersFacade() 
    { 
     if (Instance != null) 
      Instance = new SendersFacade(); 
    } 
    public SendersFacade() 
    { 
     ClientSender = new GoogleNotificationSender("correct api key"); 
     PartnerSender = new GoogleNotificationSender("correct api key"); 
     //AppleSender = some intialization. 
    } 
} 

3- Versuchen Sie, die Logik der das Senden innerhalb der Klasse Handler es selbst zu setzen, und das funktionierte, und ich konnte die Benachrichtigung vom Server senden war, Aber warum, zum Teufel, THIS FOLGENDER CODE FUNKTIONIERT, ABER DER VORHERIGE CODE FUNKTIONIERT NICHT ??????????

public interface IHandler<T> where T : IMessage 
{ 
    Task Handle(T args); 
} 

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> 
{ 
    public Task Handle(RequestAdded args) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      try 
      { 
       GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId); 

       // this statment is executed, and the text log file will contains this line 
       TracingSystem.TraceInformation("Before Send Google Notification"); 

       SendersFacade.PartnerSender.Send(notification).Wait(); 
      } 
      catch (Exception ex) 
      { 
       TracingSystem.TraceException(ex); 
      } 
     }); 
    } 

    private GoogleNotification CreateAndroidPartnerAppNotification(string to) 
    { 
     return new GoogleNotification(); // some initialization and creating for the notification object. 
    } 

    private void Send(GoogleNotification notification, string authorizationToken) 
    { 
     TracingSystem.TraceInformation("Inside Send Google notification"); 

     using (HttpClient client = new HttpClient()) 
     { 
      client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + authorizationToken); 

      string json = notification.GetJson(); 
      StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); 

      using (HttpResponseMessage message = client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result) 
      { 
       message.EnsureSuccessStatusCode(); 

       string resultAsString = message.Content.ReadAsStringAsync().Result; 
       GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString); 

       if (result.Failure > 0) 
        throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}"); 
      } 
     } 
    } 
} 

Hinzufügen einfach die Logik des Sendemethode zum RequestAddedAppMonitorHandler Klasse löste das Problem, aber ich möchte nicht, dass zu tun, und warum dies in erster Linie passiert ist ?? Es ruft nur eine Methode.

3- versuchen, die Sendemethode serielle Methode zu machen (nicht die async verwenden), und es wird auch

nicht funktioniert hat
public void Send(GoogleNotification notification) 
{ 
    TracingSystem.TraceInformation("Inside Send Google notification"); 

    using (HttpClient client = new HttpClient()) 
    { 
     client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken); 

     string json = notification.GetJson(); 
     StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); 

     using (HttpResponseMessage message = client.PostAsync(BASE_URL, content).Result) 
     { 
      message.EnsureSuccessStatusCode(); 

      string resultAsString = message.Content.ReadAsStringAsync().Result; 
      GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString); 

      if (result.Failure > 0) 
       throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}"); 
     } 
    } 
} 

NOTE1: Ich bemerkte, dass ich ein Problem auf die ich immer Server (der überhaupt nicht auf meinem lokalen Rechner angezeigt wird), bei dem es sich um den für diese Website spezifischen Anwendungspool handelt, der häufig angehalten wird und der 503-Dienst beim Anfordern der Website nicht verfügbar ist.

HINWEIS 2: Ich vermute, dass die wahrscheinlichste Ursache für dieses Problem Gewinde ist. aber ich kann definitive Lösung nicht erreichen

ANMERKUNG 3: Bitte berücksichtigen nicht, dass es Antwort auf diese Frage ist, ist es nicht mir überhaupt geholfen hat.

Ich arbeite an diesem von drei Tagen, und ich bin wirklich hoffnungslos, irgendwelche Ideen Danke.


aktualisiert die Antwort von @Nkosi wirklich hilfreich ist, zumindest ich jetzt weiß, was das Problem ist, habe ich beschlossen, synchronen die ganzen Weg zu gehen. und um zu vermeiden, dass async/await mit den blockierenden calles gemischt wird.

so hier ist das Ergebnis, das ich

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> 
{ 
    public Task Handle(RequestAdded args) 
    { 
     return Task.Factory.StartNew(() => 
     { 
      try 
      { 
       if (deviceOS.Value == DeviceOSEnum.Android.ToString()) 
       { 
        GoogleNotification notification = CreateAndroidUpdateRequestMessage(args.CustomerRequest, deviceId.Value, notificationString.Title_RequestStared, message); 
        SendGoogleNotification(notification, "some id"); 
       } 
       else if (deviceOS.Value == DeviceOSEnum.IOS.ToString()) 
       { 
        AppleNotification notification = CreateAppleNotification(deviceId.Value, notificationString.Title_RequestStared, message); 
        AppleNotificationSender sender = new AppleNotificationSender(); 
        sender.SendAppleNotification(notification); 
       } 
      } 
      catch (Exception ex) 
      { 
       TracingSystem.TraceException(ex); 
      } 
     }); 
    } 

und die AppleNotificationSender Klasse

public class AppleNotificationSender 
{ 
    private TcpClient client; 
    private string host = "gateway.push.apple.com"; 
    private int port = 2195; 
    private X509Certificate2 certificate; 

    public AppleNotificationSender() 
    { 
     string path = HostingEnvironment.MapPath("~/Certificates.p12"); 
     certificate = new X509Certificate2(path, "some correct password"); 
    } 

    private void SetSocketKeepAliveValues(Socket socket, int KeepAliveTime, int KeepAliveInterval) 
    { 
     //KeepAliveTime: default value is 2hr 
     //KeepAliveInterval: default value is 1s and Detect 5 times 

     uint dummy = 0; //lenth = 4 
     byte[] inOptionValues = new byte[System.Runtime.InteropServices.Marshal.SizeOf(dummy) * 3]; //size = lenth * 3 = 12 

     BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0); 
     BitConverter.GetBytes((uint)KeepAliveTime).CopyTo(inOptionValues, System.Runtime.InteropServices.Marshal.SizeOf(dummy)); 
     BitConverter.GetBytes((uint)KeepAliveInterval).CopyTo(inOptionValues, System.Runtime.InteropServices.Marshal.SizeOf(dummy) * 2); 
     // of course there are other ways to marshal up this byte array, this is just one way 
     // call WSAIoctl via IOControl 

     // .net 3.5 type 
     socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null); 
    } 

    private bool SocketCanWrite(SslStream stream) 
    { 
     if (client == null) 
      return false; 

     if (stream == null || !stream.CanWrite) 
      return false; 

     if (!client.Client.Connected) 
      return false; 

     return client.Client.Poll(1000, SelectMode.SelectWrite); 
    } 

    private void Connect() 
    { 
     try 
     { 
      if (client == null) 
       client = new TcpClient(); 

      client.Connect(host, port); 

      //Set keep alive on the socket may help maintain our APNS connection 
      try { client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); } 
      catch { } 

      // Really not sure if this will work on MONO.... 
      // This may help windows azure users 
      try 
      { 
       SetSocketKeepAliveValues(client.Client, (int)TimeSpan.FromMinutes(20).TotalMilliseconds, (int)TimeSpan.FromSeconds(30).TotalMilliseconds); 
      } 
      catch { } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Failed to Connect, check your firewall settings!", ex); 
     } 
    } 

    public void SendAppleNotification(AppleNotification notification) 
    { 
     SslStream stream = null; 
     try 
     { 
      Connect(); 

      stream = new SslStream(client.GetStream(), 
       false, 
       (sender, cert, chain, policyErrors) => true, 
       (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => certificate); 

      try 
      { 
       X509CertificateCollection collection = new X509CertificateCollection(); 
       collection.Add(certificate); 
       stream.AuthenticateAsClient(host, collection, System.Security.Authentication.SslProtocols.Tls, false); 
      } 
      catch (System.Security.Authentication.AuthenticationException ex) 
      { 
       throw new Exception("SSL Stream Failed to Authenticate as Client", ex); 
      } 

      if (!stream.IsMutuallyAuthenticated) 
       throw new Exception("SSL Stream Failed to Authenticate", null); 

      if (!stream.CanWrite) 
       throw new Exception("SSL Stream is not Writable", null); 

      if (!SocketCanWrite(stream)) 
       Connect(); 

      byte[] data = notification.ToBytes(); 
      stream.Write(data, 0, data.Length); 
      //TracingSystem.TraceInformation("Write to stream ended."); 
     } 
     catch (Exception) 
     { 
      TracingSystem.TraceError("Error in sending Apple notification"); 
      throw; 
     } 
     finally 
     { 
      try { stream?.Close(); } catch { } 
      try { stream?.Dispose(); } catch { } 
      try { client?.Client?.Shutdown(SocketShutdown.Both); } catch { } 
      try { client?.Client?.Dispose(); } catch { } 
      try { client?.Close(); } catch { } 
      client = null; 
     } 
    } 
} 

Jetzt erreichte ich das Deadlock-Problem gelöst, aber ich habe ein anderes Problem. Beim Senden einer Apple-Benachrichtigung wird die MVC-Aktion, die diese Handle-Methode auslöst, zweimal aufgerufen, und dies verursacht eine Geschäftsregelausnahme (normal, wenn diese Aktion zweimal ausgelöst wird). und die Apple-Benachrichtigung wird überhaupt nicht erreicht.
Hinweis: Wenn ich den Code des Sendens der Apple-Benachrichtigung auf meinem lokalen Computer debuggen, alles ist gut, und die Benachrichtigung erreicht, und die Aktion nur einmal aufgerufen, erscheint das zuvor beschriebene Problem nur nach der Bereitstellung dieses Codes zu der Server.
Hinweis: Dieses Problem tritt nicht auf, wenn die Google-Benachrichtigung an alle gesendet wird.

Durch die Art und Weise ist hier die Auslösung der Methode Verarbeitung

public class MessageBus : ICommandSender 
{ 
    public static MessageBus Instance { get; private set; } 

    private MessageBus() 
    { 
     handlers = new List<Delegate>(); 
    } 

    static MessageBus() 
    { 
     if (Instance == null) 
      Instance = new MessageBus(); 
    } 

    private List<Delegate> handlers; 

    public void Send<T>(T command) where T : ICommand 
    { 
     List<Task> tasks = new List<Task>(); 
     foreach (Func<T, Task> handle in handlers.OfType<Func<T, Task>>()) 
     { 
      try { tasks.Add(handle(command)); } 
      catch (Exception ex) { TracingSystem.TraceException(ex); } 
     } 

     try { Task.WaitAll(tasks.ToArray()); } 
     catch (BusinessRuleException buzEx) { TracingSystem.TraceException(buzEx); throw buzEx; } 
     catch (Exception ex) { TracingSystem.TraceException(ex); } 
    }  
} 
+0

Gibt es eine einfache Möglichkeit für uns, den Code an unserem Ende neu zu erstellen und das Problem zu sehen? https://stackoverflow.com/help/mcve – mjwills

+7

"* Ich brauche etwas Zeit o erklären meine verrückte Situation. *" sofort gefolgt von "* Es ist sehr einfach *" ... Rote Lichter blinken! – InBetween

+0

Die verrückte Situation kommt von der Einfachheit, die überhaupt nicht funktioniert @InBetween –

Antwort

5

ABER WARUM FUNKTIONIERT DIESER FOLGENDE CODE, ABER DER VORHERIGE CODE FUNKTIONIERT NICHT?

Der Arbeitscode funktioniert, weil er alle synchron aufgerufen wird und keine Async/Warte- und Blockierungsaufrufe mischt.

Im vorherigen Code mischen Sie async/await mit blockierenden Aufrufen wie .Result oder .Wait(), die zu Deadlocks führen können. Sie gehen entweder durch den ganzen Weg asynchron oder synchron durch den ganzen Weg.

Ich schlage vor, Sie GoogleNotificationSender Refactoring, sicherstellen, dass es async den ganzen Weg ist durch

public class GoogleNotificationSender { 
    private HttpClient client; 
    private string authorizationToken; 

    public GoogleNotificationSender(string authorizationToken) { 
     this.AuthorizationToken = authorizationToken; 
    } 

    private string AuthorizationToken { 
     get { return authorizationToken; } 
     set { 
      if (string.IsNullOrEmpty(value)) 
       throw new InvalidOperationException("authorizationToken must not be null"); 
      authorizationToken = value; 
     } 
    } 

    private HttpClient Client { 
     get { 
      if (client == null) { 
       client = new HttpClient(); 
       client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken); 
      } 
      return client; 
     } 
    } 

    public async Task SendAsync(GoogleNotification notification) { 
     TracingSystem.TraceInformation("Inside Send Google notification"); 

     var json = notification.GetJson(); 
     var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); 
     var requestUri = "https://fcm.googleapis.com/fcm/send"; 

     using (var message = await Client.PostAsync(requestUri, content)) { 
      message.EnsureSuccessStatusCode(); 

      var result = await message.Content.ReadAsAsync<GoogleNotificationResult>(); 
      if (result.Failure > 0) 
       throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}"); 
     } 
    } 
} 

Hinweis die Umbenennung von Send zu SendAsync richtig Absicht auszudrücken. Versuchen Sie nicht, bei jedem Anruf ein neues HttpClient zu erstellen. Das kann Nebenwirkungen haben, aber es liegt außerhalb des Rahmens dieser Frage und Antwort. Es gibt bereits viele Antworten auf SO, die das erklären.

Als nächstes stellen Sie sicher, das Handler wird auch als richtig umgesetzt async

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> { 
    public async Task Handle(RequestAdded args) { 
     try { 
      string deviceId = args.DeviceId;//This is an assumption here 
      var notification = CreateAndroidPartnerAppNotification(deviceId); 

      // this statment is executed, and the text log file will contains this line 
      TracingSystem.TraceInformation("Before Send Google Notification"); 

      await SendersFacade.PartnerSender.SendAsync(notification); 
     } catch (Exception ex) { 
      TracingSystem.TraceException(ex); 
     } 
    } 

    private GoogleNotification CreateAndroidPartnerAppNotification(string to) { 
     // some initialization and creating for the notification object. 
     return new GoogleNotification() { 
      To = to 
     }; 
    } 
} 

Schließlich versuchen, um sicherzustellen, dass es keine blockierende Anrufe höher in dem Call-Stack gemacht werden, da dies nur Sie zurück setzen würde in das festgefahrene Problem, das Sie erlebt haben. zB: was auch immer ruft Task IHandler<T>.Handle(T args) sollte nicht async und blockierende Anrufe mischen.

Wenn Probleme bei voll Verständnis async/await, die Sie wirklich

Async/Await - Best Practices in Asynchronous Programming

Lesen in Betracht ziehen sollten, ein besseres Verständnis des Themas zu bekommen.

+0

Ich weiß, dass das eine gute Antwort ist, ich schätze deine Bemühungen, mir zu helfen, habe ich deine Antwort gewählt. Aber ich verstehe das async/await nicht wirklich und deshalb mag ich es nicht, ich habe es wirklich versucht und ich habe immer noch das selbe Problem. Ich habe versucht, alles synchron zu machen, aber es hat nicht funktioniert, ich kämpfe wirklich und stecke dabei fest. –

+0

Vielen Dank für Ihre Anweisungen über den gesamten Weg "Async" oder die ganze Art der Synchronisierung, Eigentlich wähle ich, um den gesamten Weg zu synchronisieren. und ich löste das Deadlock-Problem, aber ich sah ein anderes Problem, bitte sehen Sie mein letztes Update auf die Frage. Nochmals vielen Dank, und ich werde verpflichtet sein, diese Antwort zu akzeptieren und das Kopfgeld zu geben, nochmals vielen Dank. –

9

Sieht aus wie Sie einen Deadlock haben. Sie müssen über Synchronisationskontext und ConfigureAwait lesen.

Ich würde Ihnen empfehlen, zu verwenden:

await SendersFacade.PartnerSender.SendAsync(notification); 

Statt:

SendersFacade.PartnerSender.Send(notification).Wait(); 

UPD:

Wenn Sie nicht Ihre Methode Senden machen async Sie brauchen Fügen Sie ConfigureAwait (false) zu den erwarteten Methoden hinzu:

await client.PostAsync("https://fcm.googleapis.com/fcm/send", content).ConfigureAwait(false); 

await message.Content.ReadAsStringAsync().ConfigureAwait(false); 

Dadurch können Sie Deadlocks vermeiden.

+0

** 1: ** Ich kann 'wait' von meiner Methode nicht verwenden, weil es nicht' async' ist, dies wird einen Kompilierfehler ergeben, ** 2: ** dort ist keine Version von 'SendAsync' das' Send' selbst ist eine asynchrone Methode, ** 3: ** es gibt keinen wirklichen Unterschied zwischen dem Aufrufenden 'wait' und dem'Award' vor dem Aufruf, ** 4: * * Sie haben die Lösung für das Problem in den Details nicht beschrieben –

+0

** Dies funktioniert nicht für mich ** –

+1

** 1 **: Markieren Sie einfach Ihre (anonyme) Methode als 'async', ** 2 **: As Du sagtest, 'Send' ist bereits' async', du brauchst nicht 'SendAsync' (eine asynchrone Version von' Send'), ** 3 **: Errr ... nein, die zwei ('erwarten' vs' warten ') IST eigentlich anders, (siehe [hier] (https://stackoverflow.com/questions/9519414/whats-the-difference-between-task-start-wait-and-async-await) ... und [hier ] (https: // stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock)), ** 4 **: obwohl es möglicherweise keine vollständige Lösung, aber @Aliaksandr tatsächlich den wahrscheinlichsten Täter für Ihr Problem beschreiben ... – IronGeek

0

Ich würde persönlich PushSharp empfehlen. Es bietet eine großartige vermittelte asynchrone Lösung für das Senden von Benachrichtigungen an iOS, Android, Chrome und Windows Phone.

Ich fand es viel einfacher, mich selbst zu verwenden und über fehlgeschlagene Push-Versuche zu berichten.Alle Open-Source von https://github.com/Redth/PushSharp oder durch NuGet

+0

Ich habe mit PushSharp mehr versucht, als Sie sich vorstellen können, ich habe versucht, es so zu benutzen, wie es ist, und ich habe auch eine Gabel daraus auf GitHub erstellt und habe versucht, diese Gabel zu benutzen, aber nichts hat mir geholfen. Danke trotzdem –

+0

Stimmen Sie mit diesem Kommentar überein, verwendet es für beide iOS und Android-Benachrichtigungen - hat ein paar Probleme, aber nichts wichtiges. – WooHoo

0

Ich denke, das Problem ist, dass Sie einen Rückgabetyp von async Task auf Ihren Anruf hier haben:

public async Task Send(GoogleNotification notification) 

... aber man kann nie tatsächlich beginnen, diese Aufgabe mit Task.Run . Sie arbeiten hier .Wait() auf ihn nennen:

SendersFacade.PartnerSender.Send(notification).Wait(); 

... aber das ist nicht, wie es funktioniert, Sie haben tatsächlich die Aufgabe zu starten, um zu warten, bis es, wird es nur dort ewig warten so wie das.

Wenn Sie Ihre Send Methode ändern, um eine Unterschrift und Körper wie diese zu haben, es wird funktionieren:

public Task Send(GoogleNotification notification) 
    { 
     return Task.Run(()=> 
     { 
      TracingSystem.TraceInformation("Inside Send Google notification"); 

      using (HttpClient client = new HttpClient()) 
      { 
       client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + AuthorizationToken); 

       string json = notification.GetJson(); 
       StringContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); 

       using (HttpResponseMessage message =client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result) 
       { 
        message.EnsureSuccessStatusCode(); 

        string resultAsString = message.Content.ReadAsStringAsync().Result; 
        GoogleNotificationResult result = JsonConvert.DeserializeObject<GoogleNotificationResult>(resultAsString); 

        if (result.Failure > 0) 
         throw new Exception($"Sending Failed : {result.Results.FirstOrDefault().Error}"); 
       } 
      } 
     }); 
    } 

Bitte beachte, dass ich auch die await Schlüsselwörter im Inneren des Körpers des Verfahrens entfernt haben - ich wollte um es einfach zu halten und synchron innerhalb der übergeordneten Aufgabe zu laufen, sind wir schließlich asynchron, so dass es im Körper keinen Unterschied macht.

Hier ist ein vollständiges Beispiel, sie in eine Konsole app Whack und es zu gehen ...

static void Main(string[] args) 
    { 
     Console.WriteLine("Press any key to run."); 
     Example thing = new Example(); 
     while (Console.ReadKey() != null) 
      thing.Send(); 
    } 

    class Example 
    { 
     Task<DisposableThing> DoTask() 
     { 
      return Task.Run(() => { Console.WriteLine("DoTask()"); return new DisposableThing(); }); 
     } 
     Task<DisposableThing> DoTaskWillNotWork() 
     { 
      return new Task<DisposableThing>(() => { Console.WriteLine("DoTaskWillNotWork()"); return new DisposableThing(); }); 
     } 

     async Task<DisposableThing> DoAsync() 
     { 
      Func<DisposableThing> action = new Func<DisposableThing>(() => 
      { 
       Console.WriteLine("DoAsync()"); 
       return new DisposableThing(); 
      }); 
      return await Task.Run(action); 
     } 

     public Task Send() 
     { 
      return Task.Run(() => 
      { 
       using (DisposableThing client = new DisposableThing()) 
       { 
        using (DisposableThing message = DoAsync().Result) 
        { 
         DisposableThing resultAsString = DoTask().Result; 
         DisposableThing resultAsString2 = DoTaskWillNotWork().Result; 
        } 
       } 
      }); 
     } 
    } 

    class DisposableThing : IDisposable 
    { 
     public void Dispose() 
     { 
      //not much to do 
     } 
    } 

hoffe, das hilft!

0

ich Deadlocks sind hier an Schuld spüren, untersuchen Sie die Linie HttpResponseMessage message = client.PostAsync("https://fcm.googleapis.com/fcm/send", content).Result in Bezug auf https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Kombination von async und wartet mit .Wait() aufrufen Methoden und .RESULT Eigenschaften stattdessen eine Aufgabe innerhalb einer asynchronen Aufgabe der Erwartung Methode kann den ganzen Weg zu Deadlocks führen, wie hier beschrieben. https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

BTW, ich glaube nicht, dass Ihre Verwendung von Task.Factory.StartNew korrekt ist. Gibt es einen besonderen Grund dafür, Threads (oder Tasks) zu manipulieren, anstatt diese auf dem Framework zu belassen? Gibt es ein Problem mit dem folgenden Code?

public class RequestAddedAppMonitorHandler : IHandler<RequestAdded> 
{ 
    public async Task Handle(RequestAdded args) 
    { 
     try 
     { 
      GoogleNotification notification = CreateAndroidPartnerAppNotification(deviceId); 

      // this statment is executed, and the text log file will contains this line 
      TracingSystem.TraceInformation("Before Send Google Notification"); 

      await SendersFacade.PartnerSender.Send(notification); 
     } 
     catch (Exception ex) 
     { 
      TracingSystem.TraceException(ex); 
     } 
    } 
} 
Verwandte Themen