Nancy is slowly starting to accept applications

I'm struggling to figure out why Nancy is not accepting requests for about 1 minute. I have about 60 endpoints, and they all initialize very quickly, so all modules are processed.

Are there any common reasons for this? Or is there a way to track what is happening?

EDIT

Application Launch Registration

App Start 4/15/2014 11:03:48 AM App Start Complete 4/15/2014 11:03:48 AM Bootstrap 4/15/2014 11:04:19 AM Module 3 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 2 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:37 AM Module 1 4/15/2014 11:06:38 AM Module 1 4/15/2014 11:06:38 AM Module 1 4/15/2014 11:06:38 AM 

As you can see during the delay before loading, as well as before calling the modules.

EDIT 2

My configuration is Nancy (v0.22.2, built from the source, because you need a strong key without changing the code) ASP.NET 4.5 using web forms. Using Visual Studio 2013 as an IDE

+6
source share
2 answers

I think I understand what the problem is. The problem is the AutoRegister function from the TinyIoC container that Nancy uses.

Basically, at startup (first request), it scans every assembly of your AppDomain to register dependencies. This process is very slow: https://github.com/NancyFx/Nancy/issues/643

The solution is to manually register your dependencies, as indicated here: https://github.com/NancyFx/Nancy/wiki/Bootstrapping-nancy

Basically, you just need to create a class in your AspNet project that inherits from DefaultNancyAspNetBootstrapper and overrides the ConfigureApplicationContainer method:

 public class Bootstrapper : DefaultNancyAspNetBootstrapper { protected override void ConfigureApplicationContainer(TinyIoCContainer container) { // Register our app dependency as a normal singleton } } 

Hope this helps,

+9
source

The root cause of the slow running AutoRegister function in Nancy is the sheer number of assemblies and types processed. The second problem is not the optimal code for this case. The current stable version of Nancy (1.4.3) has the following code https://github.com/NancyFx/Nancy/blob/1.x-WorkingBranch/src/Nancy/TinyIoc/TinyIoC.cs#L3092-L3094 As a result, this is a linq expression processed for each type ... To change this behavior, you can use the following class as a base for your Bootstrapper. You can also speed up this code by excluding your 3D assemblies in AutoRegisterIgnoredAssemblies (see the example in the code).

On my system, this helps to increase the speed of automatic registration by 521 times from 50 seconds to 95 ms.

  public class AutoRegistredBootstrapper : DefaultNancyBootstrapper { private readonly object AutoRegisterLock = new object(); private void AutoRegister(TinyIoCContainer container, IEnumerable<Assembly> assemblies) { var ignoreChecks = new List<Func<Type, bool>>() { t => t.FullName.StartsWith("System.", StringComparison.Ordinal), t => t.FullName.StartsWith("Microsoft.", StringComparison.Ordinal), t => t.IsPrimitive(), t => (t.GetConstructors(BindingFlags.Instance | BindingFlags.Public).Length == 0) && !(t.IsInterface() || t.IsAbstract()), t => t.Assembly == typeof(NancyEngine).Assembly }; lock (AutoRegisterLock) { var thisType = this.GetType(); var types = assemblies.SelectMany(a => AssemblyExtensions.SafeGetTypes(a)) .Where(type => (type.DeclaringType != thisType) && !type.IsGenericTypeDefinition()) .Where(t => !ignoreChecks.Any(check => check(t))) .ToList(); var assignebleTypes = types.Where( type => type.IsClass() && (type.IsAbstract() == false) && (type != thisType)) .Select(t => { // be careful with side effects in linq container.Register(t); return t; }) .Where(implementationType => implementationType.GetTypeInfo().ImplementedInterfaces.Any() || implementationType.BaseType != typeof(Object)) .ToList(); var abstractInterfaceTypes = types.Where(type => ((type.IsInterface() || type.IsAbstract()))); foreach (var abstractInterfaceType in abstractInterfaceTypes) { var localType = abstractInterfaceType; var implementations = assignebleTypes.Where(implementationType => localType.IsAssignableFrom(implementationType)).ToList(); if (implementations.Count > 1) { if (implementations.Count != implementations.Distinct().Count()) { var fullNamesOfDuplicatedTypes = string.Join(",\n", implementations.GroupBy(i => i).Where(j => j.Count() > 1).Select(j => j.Key.FullName)); throw new ArgumentException($"types: The same implementation type cannot be specified multiple times for {abstractInterfaceType.FullName}\n\n{fullNamesOfDuplicatedTypes}"); } foreach (var implementationType in implementations) { container.Register(abstractInterfaceType, implementationType, implementationType.FullName); } } var firstImplementation = implementations.FirstOrDefault(); if (firstImplementation != null) { container.Register(abstractInterfaceType, firstImplementation); } } } } protected override IEnumerable<Func<Assembly, bool>> AutoRegisterIgnoredAssemblies { get { return DefaultAutoRegisterIgnoredAssemblies.Concat(new Func<Assembly, bool>[] { asm => asm.FullName.StartsWith("ICSharpCode.", StringComparison.Ordinal), asm => asm.FullName.StartsWith("Ionic.", StringComparison.Ordinal), asm => asm.FullName.StartsWith("CommandLine,", StringComparison.Ordinal) // ADD THE REST OF 3D party libs that you don't use as dependencies }); } } protected override void ConfigureApplicationContainer(TinyIoCContainer container) { var currentDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies(); var ignoredAssemblies = this.AutoRegisterIgnoredAssemblies.ToList(); var asmsForProcessing = currentDomainAssemblies.Where(a => !ignoredAssemblies.Any(ia => ia(a))).ToList(); AutoRegister(container, asmsForProcessing); } } 
0
source

All Articles