2015-07-28 20 views
14

Ho il seguente codice nei miei Startup.SignalR.cs:MVC5 blocca su MapSignalR quando riconnessione dopo cicli AppPool

using Microsoft.AspNet.SignalR; 
using Owin; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Admin 
{ 
    public partial class Startup 
    { 
     public void ConfigureSignalR(IAppBuilder app) 
     { 
      var Config = new HubConfiguration() 
      { 
       EnableDetailedErrors = false, 
       Resolver = new DefaultDependencyResolver() 
      }; 

#if DEBUG 
      Config.EnableDetailedErrors = true; 
#endif 
      // Any connection or hub wire up and configuration should go here 
      app.MapSignalR(); 

      GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(600); 
     } 
    } 
} 

Durante il caricamento iniziale dell'applicazione, tutto va bene, tuttavia quando è consentito il filo a dormire (lasciato per ~ 10 minuti) l'AppPool viene riciclata e il filo si blocca su questa linea:

app.MapSignalR(); 

l'IDE è bloccato con la freccia verde e This is the next statement to execute when this thread returns from the current function.. Tuttavia non ho idea di cosa sia lo current function in questo contesto.

Cercando di controllare tutte le variabili risultati locali in Cannot evaluate expression because a native frame is on top of the call stack. tuttavia la Stack di chiamate mostra: Admin.dll!Admin.Startup.ConfigureSignalR(Owin.IAppBuilder app) Line 25 come il telaio superiore ...

Il codice non recupera da questo stato e l'AppPool deve essere completamente riavviato riavviando il debug sessione.

Chiunque ha qualche spiegazione per questo scenario?

Ulteriori informazioni: Dopo aver abilitato Debug => di Windows => Parrallel Stack vedo una più dettagliata dello stack:

[Managed to Native Transition] 
mscorlib.dll!Microsoft.Win32.RegistryKey.OpenSubKey(string name, bool writable) 
mscorlib.dll!Microsoft.Win32.RegistryKey.OpenSubKey(string name) 
System.dll!System.Diagnostics.PerformanceCounterLib.FindCustomCategory(string category, out System.Diagnostics.PerformanceCounterCategoryType categoryType) 
System.dll!System.Diagnostics.PerformanceCounterLib.IsCustomCategory(string machine, string category) 
System.dll!System.Diagnostics.PerformanceCounter.InitializeImpl() 
System.dll!System.Diagnostics.PerformanceCounter.PerformanceCounter(string categoryName, string counterName, string instanceName, bool readOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.LoadCounter(string categoryName, string counterName, string instanceName, bool isReadOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.LoadCounter(string categoryName, string counterName, bool isReadOnly) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.SetCounterProperties() 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Infrastructure.PerformanceCounterManager.Initialize(string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hosting.HostDependencyResolverExtensions.InitializePerformanceCounters(Microsoft.AspNet.SignalR.IDependencyResolver resolver, string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Microsoft.AspNet.SignalR.Hosting.HostDependencyResolverExtensions.InitializeHost(Microsoft.AspNet.SignalR.IDependencyResolver resolver, string instanceName, System.Threading.CancellationToken hostShutdownToken) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.UseSignalRMiddleware<Microsoft.AspNet.SignalR.Owin.Middleware.HubDispatcherMiddleware>(Owin.IAppBuilder builder, object[] args) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.RunSignalR(Owin.IAppBuilder builder, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR.AnonymousMethod__0(Owin.IAppBuilder subApp) 
Microsoft.Owin.dll!Owin.MapExtensions.Map(Owin.IAppBuilder app, Microsoft.Owin.PathString pathMatch, System.Action<Owin.IAppBuilder> configuration) 
Microsoft.Owin.dll!Owin.MapExtensions.Map(Owin.IAppBuilder app, string pathMatch, System.Action<Owin.IAppBuilder> configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder, string path, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder, Microsoft.AspNet.SignalR.HubConfiguration configuration) 
Microsoft.AspNet.SignalR.Core.dll!Owin.OwinExtensions.MapSignalR(Owin.IAppBuilder builder) 
Admin.dll!Admin.Startup.ConfigureSignalR(Owin.IAppBuilder app) Line 25 
+1

Questo è simile a questo: https://github.com/SignalR/SignalR/issues/3414 – Pawel

+0

Ho riscontrato lo stesso problema – JacobE

risposta

5

Come già detto da Pawel, sono stato in grado di risolvere il mio problema con l'uso di un manichino contatore delle prestazioni come documentato qui: https://github.com/SignalR/SignalR/issues/3414

// Global.asmx 
var tempCounterManager = new TempPerformanceCounterManager(); 
GlobalHost.DependencyResolver.Register(typeof (IPerformanceCounterManager),() => tempCounterManager); 

[....] 

// Helper Class 
public class TempPerformanceCounterManager : IPerformanceCounterManager 
{ 
    private readonly static PropertyInfo[] _counterProperties = GetCounterPropertyInfo(); 
    private readonly static IPerformanceCounter _noOpCounter = new NoOpPerformanceCounter(); 

    public TempPerformanceCounterManager() 
    { 
     foreach (var property in _counterProperties) 
     { 
      property.SetValue(this, new NoOpPerformanceCounter(), null); 
     } 
    } 

    public void Initialize(string instanceName, CancellationToken hostShutdownToken) 
    { 
    } 

    public IPerformanceCounter LoadCounter(string categoryName, string counterName, string instanceName, bool isReadOnly) 
    { 
     return _noOpCounter; 
    } 

    internal static PropertyInfo[] GetCounterPropertyInfo() 
    { 
     return typeof(TempPerformanceCounterManager) 
      .GetProperties() 
      .Where(p => p.PropertyType == typeof(IPerformanceCounter)) 
      .ToArray(); 
    } 
    public IPerformanceCounter ConnectionsConnected { get; set; } 
    public IPerformanceCounter ConnectionsReconnected { get; set; } 
    public IPerformanceCounter ConnectionsDisconnected { get; set; } 
    public IPerformanceCounter ConnectionsCurrentForeverFrame { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentLongPolling { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentServerSentEvents { get; private set; } 
    public IPerformanceCounter ConnectionsCurrentWebSockets { get; private set; } 
    public IPerformanceCounter ConnectionsCurrent { get; private set; } 
    public IPerformanceCounter ConnectionMessagesReceivedTotal { get; private set; } 
    public IPerformanceCounter ConnectionMessagesSentTotal { get; private set; } 
    public IPerformanceCounter ConnectionMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter ConnectionMessagesSentPerSec { get; private set; } 
    public IPerformanceCounter MessageBusMessagesReceivedTotal { get; private set; } 
    public IPerformanceCounter MessageBusMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutMessageBusMessagesReceivedPerSec { get; private set; } 
    public IPerformanceCounter MessageBusMessagesPublishedTotal { get; private set; } 
    public IPerformanceCounter MessageBusMessagesPublishedPerSec { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersCurrent { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersTotal { get; private set; } 
    public IPerformanceCounter MessageBusSubscribersPerSec { get; private set; } 
    public IPerformanceCounter MessageBusAllocatedWorkers { get; private set; } 
    public IPerformanceCounter MessageBusBusyWorkers { get; private set; } 
    public IPerformanceCounter MessageBusTopicsCurrent { get; private set; } 
    public IPerformanceCounter ErrorsAllTotal { get; private set; } 
    public IPerformanceCounter ErrorsAllPerSec { get; private set; } 
    public IPerformanceCounter ErrorsHubResolutionTotal { get; private set; } 
    public IPerformanceCounter ErrorsHubResolutionPerSec { get; private set; } 
    public IPerformanceCounter ErrorsHubInvocationTotal { get; private set; } 
    public IPerformanceCounter ErrorsHubInvocationPerSec { get; private set; } 
    public IPerformanceCounter ErrorsTransportTotal { get; private set; } 
    public IPerformanceCounter ErrorsTransportPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountTotal { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountOpen { get; private set; } 
    public IPerformanceCounter ScaleoutStreamCountBuffering { get; private set; } 
    public IPerformanceCounter ScaleoutErrorsTotal { get; private set; } 
    public IPerformanceCounter ScaleoutErrorsPerSec { get; private set; } 
    public IPerformanceCounter ScaleoutSendQueueLength { get; private set; } 
} 

internal class NoOpPerformanceCounter : IPerformanceCounter 
{ 
    public string CounterName 
    { 
     get 
     { 
      return GetType().Name; 
     } 
    } 
    public long Decrement() 
    { 
     return 0; 
    } 
    public long Increment() 
    { 
     return 0; 
    } 
    public long IncrementBy(long value) 
    { 
     return 0; 
    } 
    public long RawValue 
    { 
     get { return 0; } 
     set { } 
    } 
    public void Close() 
    { 
    } 
    public void RemoveInstance() 
    { 
    } 
    public CounterSample NextSample() 
    { 
     return CounterSample.Empty; 
    } 
} 
+0

Si prega di vedere la risposta da @eladm qui sotto, in quanto è la correzione ufficiale https://github.com/SignalR/SignalR/pull/3609 nel ramo di sviluppo SignalR. Non ancora rilasciato in 2.2.0. – bigbearzhu

11

un'altra correzione per questo, da questo post del blog: http://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol

app.SanitizeThreadCulture(); 

public static void SanitizeThreadCulture(this IAppBuilder app) 
{ 
     var currentCulture = CultureInfo.CurrentCulture; 

     // at the top of any culture should be the invariant culture, 
     // find it doing an .Equals comparison ensure that we will 
     // find it and not loop endlessly 
     var invariantCulture = currentCulture; 
     while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false) 
      invariantCulture = invariantCulture.Parent; 

     if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture)) 
      return; 

     var thread = Thread.CurrentThread; 
     thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name); 
     thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name); 
} 
2

ho trovato la soluzione qui: github.com/SignalR/SignalR/issues/3414 Snip campione:

public void Configuration(IAppBuilder app) 
{ 
    var task = Task.Run(() => app.MapSignalR()); 
    task.Wait(300); 
    //try again if it fails just to be sure ;) 
    if (task.IsCanceled) Task.Run(() => app.MapSignalR()).Wait(300); 
} 
+1

Inizialmente ho provato questo approccio e non mi è stato d'aiuto, stavo ancora ricevendo degli hang durante il primo 'Task.Run()' anche se aveva un timeout di attesa di 300ms. –

+0

funziona perfettamente per me e mi sembra più pulito – SQueek