internal void Route(MqttRouteContext routeContext)
        {
            for (var i = 0; i < Routes.Length; i++)
            {
                Routes[i].Match(routeContext);

                if (routeContext.Handler != null)
                {
                    return;
                }
            }
        }
        public void Route_Miss()
        {
            // Arrange
            var routes = new string[]
            {
                "super/awesome",
                "super/cool",
                "other/route"
            };

            var MockMethod  = Type.GetType("MQTTnet.AspNetCore.AttributeRouting.Tests.RouteTableTests").GetMethod("Route_Match", BindingFlags.Public);
            var MockMethod2 = Type.GetType("MQTTnet.AspNetCore.AttributeRouting.Tests.RouteTableTests").GetMethod("Route_Constructor", BindingFlags.Public);
            var MockRoutes  = new MqttRoute[] {
                new MqttRoute(
                    new RouteTemplate(routes[0], new List <TemplateSegment>()
                {
                    new TemplateSegment(routes[0], "super", false),
                    new TemplateSegment(routes[0], "awesome", false),
                }), MockMethod, new string[] { }),
                new MqttRoute(
                    new RouteTemplate(routes[1], new List <TemplateSegment>()
                {
                    new TemplateSegment(routes[1], "super", false),
                    new TemplateSegment(routes[1], "cool", false),
                }), MockMethod2, new string[] { }),
                new MqttRoute(
                    new RouteTemplate(routes[2], new List <TemplateSegment>()
                {
                    new TemplateSegment(routes[2], "other", false),
                    new TemplateSegment(routes[2], "route", false),
                }), MockMethod2, new string[] { }),
            };
            var context = new MqttRouteContext("super/miss");

            // Act
            var MockTable = new MqttRouteTable(MockRoutes);

            MockTable.Route(context);

            // Assert
            Assert.IsNull(context.Handler);
        }
        internal async Task OnIncomingApplicationMessage(AspNetMqttServerOptionsBuilder options, MqttApplicationMessageInterceptorContext context)
        {
            // Don't process messages sent from the server itself. This avoids footguns like a server failing to publish
            // a message because a route isn't found on a controller.
            if (context.ClientId == null)
            {
                return;
            }

            var routeContext = new MqttRouteContext(context.ApplicationMessage.Topic);

            routeTable.Route(routeContext);

            if (routeContext.Handler == null)
            {
                // Route not found
                logger.LogDebug($"Rejecting message publish because '{context.ApplicationMessage.Topic}' did not match any known routes.");

                context.AcceptPublish = false;
            }
            else
            {
                using (var scope = options.ServiceProvider.CreateScope())
                {
                    Type?declaringType = routeContext.Handler.DeclaringType;

                    if (declaringType == null)
                    {
                        throw new InvalidOperationException($"{routeContext.Handler} must have a declaring type.");
                    }

                    var classInstance = typeActivator.CreateInstance <object>(scope.ServiceProvider, declaringType);

                    // Potential perf improvement is to cache this reflection work in the future.
                    var activateProperties = declaringType.GetRuntimeProperties()
                                             .Where((property) =>
                    {
                        return
                        (property.IsDefined(typeof(MqttControllerContextAttribute)) &&
                         property.GetIndexParameters().Length == 0 &&
                         property.SetMethod != null &&
                         !property.SetMethod.IsStatic);
                    })
                                             .ToArray();

                    if (activateProperties.Length == 0)
                    {
                        logger.LogDebug($"MqttController '{declaringType.FullName}' does not have a property that can accept a controller context.  You may want to add a [{nameof(MqttControllerContextAttribute)}] to a pubilc property.");
                    }

                    var controllerContext = new MqttControllerContext()
                    {
                        MqttContext = context,
                        MqttServer  = scope.ServiceProvider.GetRequiredService <IMqttServer>()
                    };

                    for (int i = 0; i < activateProperties.Length; i++)
                    {
                        PropertyInfo property = activateProperties[i];
                        property.SetValue(classInstance, controllerContext);
                    }

                    ParameterInfo[] parameters = routeContext.Handler.GetParameters();

                    context.AcceptPublish = true;

                    if (parameters.Length == 0)
                    {
                        await HandlerInvoker(routeContext.Handler, classInstance, null).ConfigureAwait(false);
                    }
                    else
                    {
                        object?[] paramArray;

                        try
                        {
                            paramArray = parameters.Select(p => MatchParameterOrThrow(p, routeContext.Parameters)).ToArray();

                            await HandlerInvoker(routeContext.Handler, classInstance, paramArray).ConfigureAwait(false);
                        }
                        catch (ArgumentException ex)
                        {
                            logger.LogError(ex, $"Unable to match route parameters to all arguments. See inner exception for details.");

                            context.AcceptPublish = false;
                        }
                        catch (TargetInvocationException ex)
                        {
                            logger.LogError(ex.InnerException, $"Unhandled MQTT action exception. See inner exception for details.");

                            // This is an unandled exception from the invoked action
                            context.AcceptPublish = false;
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "Unable to invoke Mqtt Action.  See inner exception for details.");

                            context.AcceptPublish = false;
                        }
                    }
                }
            }
        }