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
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); }
}
}
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
"* Ich brauche etwas Zeit o erklären meine verrückte Situation. *" sofort gefolgt von "* Es ist sehr einfach *" ... Rote Lichter blinken! – InBetween
Die verrückte Situation kommt von der Einfachheit, die überhaupt nicht funktioniert @InBetween –