/// <summary> /// Registers all controllers in the specified assembly which are marked with the MessageController attribute. /// </summary> /// <param name="builder"></param> /// <param name="assembly">The assembly to scan for controllers.</param> public static ITapetiConfigBuilder RegisterAllControllers(this ITapetiConfigBuilder builder, Assembly assembly) { foreach (var type in assembly.GetTypes().Where(t => t.IsDefined(typeof(MessageControllerAttribute)))) { RegisterController(builder, type); } return(builder); }
/// <summary> /// Enables the Flow SQL repository. /// </summary> /// <param name="config"></param> /// <param name="connectionString"></param> /// <param name="tableName"></param> public static ITapetiConfigBuilder WithFlowSqlRepository(this ITapetiConfigBuilder config, string connectionString, string tableName = "Flow") { config.Use(new FlowSqlRepositoryExtension(connectionString, tableName)); return(config); }
/// <summary> /// Enables the DataAnnotations validation middleware. /// </summary> /// <param name="config"></param> public static ITapetiConfigBuilder WithDataAnnotations(this ITapetiConfigBuilder config) { config.Use(new DataAnnotationsExtension()); return(config); }
/// <summary> /// Registers all public methods in the specified controller class as message handlers. /// </summary> /// <param name="builder"></param> /// <param name="controller">The controller class to register. The class and/or methods must be annotated with either the DurableQueue or DynamicQueue attribute.</param> public static ITapetiConfigBuilder RegisterController(this ITapetiConfigBuilder builder, Type controller) { var builderAccess = (ITapetiConfigBuilderAccess)builder; if (!controller.IsClass) { throw new ArgumentException($"Controller {controller.Name} must be a class"); } var controllerQueueInfo = GetQueueInfo(controller); (builderAccess.DependencyResolver as IDependencyContainer)?.RegisterController(controller); var controllerIsObsolete = controller.GetCustomAttribute <ObsoleteAttribute>() != null; foreach (var method in controller.GetMembers(BindingFlags.Public | BindingFlags.Instance) .Where(m => m.MemberType == MemberTypes.Method && m.DeclaringType != typeof(object) && (m as MethodInfo)?.IsSpecialName == false) .Select(m => (MethodInfo)m)) { var methodIsObsolete = controllerIsObsolete || method.GetCustomAttribute <ObsoleteAttribute>() != null; var context = new ControllerBindingContext(method.GetParameters(), method.ReturnParameter) { Controller = controller, Method = method }; if (method.GetCustomAttribute <ResponseHandlerAttribute>() != null) { context.SetBindingTargetMode(BindingTargetMode.Direct); } var allowBinding = false; builderAccess.ApplyBindingMiddleware(context, () => { allowBinding = true; }); if (!allowBinding) { continue; } if (context.MessageClass == null) { throw new TopologyConfigurationException($"Method {method.Name} in controller {controller.Name} does not resolve to a message class"); } var invalidBindings = context.Parameters.Where(p => !p.HasBinding).ToList(); if (invalidBindings.Count > 0) { var parameterNames = string.Join(", ", invalidBindings.Select(p => p.Info.Name)); throw new TopologyConfigurationException($"Method {method.Name} in controller {method.DeclaringType?.Name} has unknown parameters: {parameterNames}"); } var methodQueueInfo = GetQueueInfo(method) ?? controllerQueueInfo; if (methodQueueInfo == null || !methodQueueInfo.IsValid) { throw new TopologyConfigurationException( $"Method {method.Name} or controller {controller.Name} requires a queue attribute"); } builder.RegisterBinding(new ControllerMethodBinding(builderAccess.DependencyResolver, new ControllerMethodBinding.BindingInfo { ControllerType = controller, Method = method, QueueInfo = methodQueueInfo, MessageClass = context.MessageClass, BindingTargetMode = context.BindingTargetMode, IsObsolete = methodIsObsolete, ParameterFactories = context.GetParameterHandlers(), ResultHandler = context.GetResultHandler(), FilterMiddleware = context.Middleware.Where(m => m is IControllerFilterMiddleware).Cast <IControllerFilterMiddleware>().ToList(), MessageMiddleware = context.Middleware.Where(m => m is IControllerMessageMiddleware).Cast <IControllerMessageMiddleware>().ToList(), CleanupMiddleware = context.Middleware.Where(m => m is IControllerCleanupMiddleware).Cast <IControllerCleanupMiddleware>().ToList() })); } return(builder); }
/// <summary> /// Registers all controllers in the entry assembly which are marked with the MessageController attribute. /// </summary> /// <param name="builder"></param> public static ITapetiConfigBuilder RegisterAllControllers(this ITapetiConfigBuilder builder) { return(RegisterAllControllers(builder, Assembly.GetEntryAssembly())); }
/// <summary> /// Registers the transient publisher and required middleware /// </summary> /// <param name="config"></param> /// <param name="defaultTimeout"></param> /// <param name="dynamicQueuePrefix"></param> /// <returns></returns> public static ITapetiConfigBuilder WithTransient(this ITapetiConfigBuilder config, TimeSpan defaultTimeout, string dynamicQueuePrefix = "transient") { config.Use(new TransientExtension(defaultTimeout, dynamicQueuePrefix)); return(config); }
/// <summary> /// Enables Tapeti Flow. /// </summary> /// <param name="config"></param> /// <param name="flowRepository">An optional IFlowRepository implementation to persist flow state. If not provided, flow state will be lost when the application restarts.</param> /// <returns></returns> public static ITapetiConfigBuilder WithFlow(this ITapetiConfigBuilder config, IFlowRepository flowRepository = null) { config.Use(new FlowExtension(flowRepository)); return(config); }