コード例 #1
0
        public static IConveyBuilder AddRedis(this IConveyBuilder builder, RedisOptions options)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            //TODO: Still 2.2
            builder.Services.AddDistributedRedisCache(o =>
            {
                o.Configuration = options.ConnectionString;
                o.InstanceName  = options.Instance;
            });

            return(builder);
        }
コード例 #2
0
ファイル: Extensions.cs プロジェクト: Allesad/Convey
        public static IConveyBuilder AddMessageOutbox(this IConveyBuilder builder, string sectionName = SectionName)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            var options = builder.GetOptions <OutboxOptions>(sectionName);

            builder.Services.AddSingleton(options);
            builder.AddMongo();
            builder.AddMongoRepository <OutboxMessage, Guid>("outbox");
            builder.Services.AddTransient <IMessageOutbox, MongoMessageOutbox>();
            builder.Services.AddHostedService <OutboxProcessor>();
            return(builder);
        }
コード例 #3
0
        public static IConveyBuilder AddMongo(this IConveyBuilder builder, MongoDbOptions mongoOptions,
                                              Type seederType = null, bool registerConventions = true)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (mongoOptions.SetRandomDatabaseSuffix)
            {
                var suffix = $"{Guid.NewGuid():N}";
                Console.WriteLine($"Setting a random MongoDB database suffix: '{suffix}'.");
                mongoOptions.Database = $"{mongoOptions.Database}_{suffix}";
            }

            builder.Services.AddSingleton(mongoOptions);
            builder.Services.AddSingleton <IMongoClient>(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                return(new MongoClient(options.ConnectionString));
            });
            builder.Services.AddTransient(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                var client  = sp.GetService <IMongoClient>();
                return(client.GetDatabase(options.Database));
            });
            builder.Services.AddTransient <IMongoDbInitializer, MongoDbInitializer>();
            builder.Services.AddTransient <IMongoSessionFactory, MongoSessionFactory>();

            if (seederType is null)
            {
                builder.Services.AddTransient <IMongoDbSeeder, MongoDbSeeder>();
            }
            else
            {
                builder.Services.AddTransient(typeof(IMongoDbSeeder), seederType);
            }

            builder.AddInitializer <IMongoDbInitializer>();
            if (registerConventions && !_conventionsRegistered)
            {
                RegisterConventions();
            }

            return(builder);
        }
コード例 #4
0
ファイル: Extensions.cs プロジェクト: fahrigoktuna/Convey-1
        public static IConveyBuilder AddCertificateAuthentication(this IConveyBuilder builder,
                                                                  string sectionName = SectionName, Type permissionValidatorType = null)
        {
            var options = builder.GetOptions <SecurityOptions>(sectionName);

            builder.Services.AddSingleton(options);
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (options.Certificate is null || !options.Certificate.Enabled)
            {
                return(builder);
            }

            if (permissionValidatorType is {})
コード例 #5
0
ファイル: Extensions.cs プロジェクト: yshadmehr/Convey
        public static IConveyBuilder AddConsul(this IConveyBuilder builder, ConsulOptions options,
                                               HttpClientOptions httpClientOptions)
        {
            builder.Services.AddSingleton(options);
            if (!options.Enabled || !builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (httpClientOptions.Type?.ToLowerInvariant() == "consul")
            {
                builder.Services.AddTransient <ConsulServiceDiscoveryMessageHandler>();
                builder.Services.AddHttpClient <IConsulHttpClient, ConsulHttpClient>("consul-http")
                .AddHttpMessageHandler <ConsulServiceDiscoveryMessageHandler>();
                builder.RemoveHttpClient();
                builder.Services.AddHttpClient <IHttpClient, ConsulHttpClient>("consul")
                .AddHttpMessageHandler <ConsulServiceDiscoveryMessageHandler>();
            }

            builder.Services.AddTransient <IConsulServicesRegistry, ConsulServicesRegistry>();
            builder.Services.AddSingleton <IConsulClient>(c => new ConsulClient(cfg =>
            {
                if (!string.IsNullOrEmpty(options.Url))
                {
                    cfg.Address = new Uri(options.Url);
                }
            }));

            var registration = builder.CreateConsulAgentRegistration(options);

            if (registration is null)
            {
                return(builder);
            }

            builder.Services.AddSingleton(registration);
            builder.AddBuildAction(sp =>
            {
                var consulRegistration = sp.GetService <AgentServiceRegistration>();
                var client             = sp.GetService <IConsulClient>();

                client.Agent.ServiceRegister(consulRegistration);
            });

            return(builder);
        }
コード例 #6
0
ファイル: Extensions.cs プロジェクト: xiaowei-toolbox/Convey
        private static IConveyBuilder AddJwt(this IConveyBuilder builder, JwtOptions options,
                                             Action <JwtBearerOptions> optionsFactory = null)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            builder.Services.AddSingleton <IJwtHandler, JwtHandler>();
            builder.Services.AddSingleton <IAccessTokenService, InMemoryAccessTokenService>();
            builder.Services.AddTransient <AccessTokenValidatorMiddleware>();

            if (options.AuthenticationDisabled)
            {
                builder.Services.AddSingleton <IPolicyEvaluator, DisabledAuthenticationPolicyEvaluator>();
            }

            var tokenValidationParameters = new TokenValidationParameters
            {
                RequireAudience          = options.RequireAudience,
                ValidIssuer              = options.ValidIssuer,
                ValidIssuers             = options.ValidIssuers,
                ValidateActor            = options.ValidateActor,
                ValidAudience            = options.ValidAudience,
                ValidAudiences           = options.ValidAudiences,
                ValidateAudience         = options.ValidateAudience,
                ValidateIssuer           = options.ValidateIssuer,
                ValidateLifetime         = options.ValidateLifetime,
                ValidateTokenReplay      = options.ValidateTokenReplay,
                ValidateIssuerSigningKey = options.ValidateIssuerSigningKey,
                SaveSigninToken          = options.SaveSigninToken,
                RequireExpirationTime    = options.RequireExpirationTime,
                RequireSignedTokens      = options.RequireSignedTokens,
                ClockSkew = TimeSpan.Zero
            };

            if (!string.IsNullOrWhiteSpace(options.AuthenticationType))
            {
                tokenValidationParameters.AuthenticationType = options.AuthenticationType;
            }

            var hasCertificate = false;

            if (options.Certificate is {})
コード例 #7
0
ファイル: Extensions.cs プロジェクト: ubudubu/Convey
        public static IConveyBuilder AddHttpClient(this IConveyBuilder builder, string sectionName = SectionName)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            var options = builder.GetOptions <HttpClientOptions>(sectionName);

            builder.Services.AddSingleton(options);
            builder.Services.AddHttpClient <IHttpClient, ConveyHttpClient>("convey");

            return(builder);
        }
コード例 #8
0
        public static IConveyBuilder AddRedis(this IConveyBuilder builder, RedisOptions options)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services
            .AddSingleton(options)
            .AddSingleton <IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(options.ConnectionString))
            .AddTransient(sp => sp.GetRequiredService <IConnectionMultiplexer>().GetDatabase(options.Database))
            .AddStackExchangeRedisCache(o =>
            {
                o.Configuration = options.ConnectionString;
                o.InstanceName  = options.Instance;
            });

            return(builder);
        }
コード例 #9
0
        public static IConveyBuilder AddWebApi(this IConveyBuilder builder, Action <IMvcCoreBuilder> configureMvc = null,
                                               IJsonFormatterResolver jsonFormatterResolver = null, string sectionName = SectionName)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            Resolver = jsonFormatterResolver ?? StandardResolver.AllowPrivateCamelCase;
            builder.Services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            builder.Services.AddSingleton(new WebApiEndpointDefinitions());
            var options = builder.GetOptions <WebApiOptions>(sectionName);

            builder.Services.AddSingleton(options);
            _bindRequestFromRoute = options.BindRequestFromRoute;

            var mvcCoreBuilder = builder.Services
                                 .AddLogging()
                                 .AddMvcCore();

            mvcCoreBuilder.AddMvcOptions(o =>
            {
                o.OutputFormatters.Clear();
                o.OutputFormatters.Add(new JsonOutputFormatter(Resolver));
                o.InputFormatters.Clear();
                o.InputFormatters.Add(new JsonInputFormatter(Resolver));
            })
            .AddDataAnnotations()
            .AddApiExplorer()
            .AddAuthorization();

            configureMvc?.Invoke(mvcCoreBuilder);

            builder.Services.Scan(s =>
                                  s.FromAssemblies(AppDomain.CurrentDomain.GetAssemblies())
                                  .AddClasses(c => c.AssignableTo(typeof(IRequestHandler <,>)))
                                  .AsImplementedInterfaces()
                                  .WithTransientLifetime());

            builder.Services.AddTransient <IRequestDispatcher, RequestDispatcher>();

            return(builder);
        }
コード例 #10
0
ファイル: Extensions.cs プロジェクト: partytitan/Convey
        public static IConveyBuilder AddJaeger(this IConveyBuilder builder, JaegerOptions options)
        {
            if (Interlocked.Exchange(ref _initialized, 1) == 1)
            {
                return(builder);
            }

            builder.Services.AddSingleton(options);
            if (!options.Enabled)
            {
                var defaultTracer = ConveyDefaultTracer.Create();
                builder.Services.AddSingleton(defaultTracer);
                return(builder);
            }

            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (options.ExcludePaths is {})
コード例 #11
0
        public static IConveyBuilder AddHttpClient(this IConveyBuilder builder, string clientName = "convey",
                                                   IEnumerable <string> maskedRequestUrlParts     = null, string sectionName = SectionName)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (string.IsNullOrWhiteSpace(clientName))
            {
                throw new ArgumentException("HTTP client name cannot be empty.", nameof(clientName));
            }

            var options = builder.GetOptions <HttpClientOptions>(sectionName);

            if (maskedRequestUrlParts is {} && options.RequestMasking is {})
コード例 #12
0
        public static IConveyBuilder AddMessageInbox(this IConveyBuilder builder, string sectionName = SectionName)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            var options = builder.GetOptions <InboxOptions>(sectionName);

            builder.Services.AddSingleton(options);
            if (!options.Enabled)
            {
                builder.RegisterInMemoryInbox();
                return(builder);
            }

            switch (options.Type?.ToLowerInvariant() ?? string.Empty)
            {
            case "memory":
                builder.RegisterInMemoryInbox();
                break;

            case "mongo":
                builder.AddMongo();
                builder.Services.AddTransient <IMessageInbox, MongoMessageInbox>();
                builder.Services.AddTransient <MongoInboxInitializer>();
                builder.AddInitializer <MongoInboxInitializer>();
                break;

            case "redis":
                builder.Services.AddTransient <IMessageInbox, RedisMessageInbox>();
                break;

            default:
                builder.RegisterInMemoryInbox();
                break;
            }

            return(builder);
        }
コード例 #13
0
        private static IConveyBuilder AddFabio(this IConveyBuilder builder, FabioOptions fabioOptions,
                                               HttpClientOptions httpClientOptions, Action <IConveyBuilder> registerConsul)
        {
            registerConsul(builder);
            builder.Services.AddSingleton(fabioOptions);

            if (!fabioOptions.Enabled || !builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (httpClientOptions.Type?.ToLowerInvariant() == "fabio")
            {
                builder.Services.AddTransient <FabioMessageHandler>();
                builder.Services.AddHttpClient <IFabioHttpClient, FabioHttpClient>("fabio-http")
                .AddHttpMessageHandler <FabioMessageHandler>();


                builder.RemoveHttpClient();
                builder.Services.AddHttpClient <IHttpClient, FabioHttpClient>("fabio")
                .AddHttpMessageHandler <FabioMessageHandler>();
            }

            using var serviceProvider = builder.Services.BuildServiceProvider();
            var registration = serviceProvider.GetService <ServiceRegistration>();
            var tags         = GetFabioTags(registration.Name, fabioOptions.Service);

            if (registration.Tags is null)
            {
                registration.Tags = tags;
            }
            else
            {
                registration.Tags.AddRange(tags);
            }

            builder.Services.UpdateConsulRegistration(registration);

            return(builder);
        }
コード例 #14
0
        public static IConveyBuilder AddJaeger(this IConveyBuilder builder, JaegerOptions options)
        {
            builder.Services.AddSingleton(options);
            if (!options.Enabled)
            {
                var defaultTracer = ConveyDefaultTracer.Create();
                builder.Services.AddSingleton(defaultTracer);
                return(builder);
            }

            if (!builder.TryRegister(RegistryName) || _initialized)
            {
                return(builder);
            }

            _initialized = true;
            builder.Services.AddSingleton <ITracer>(sp =>
            {
                var loggerFactory = sp.GetRequiredService <ILoggerFactory>();

                var reporter = new RemoteReporter.Builder()
                               .WithSender(new UdpSender(options.UdpHost, options.UdpPort, options.MaxPacketSize))
                               .WithLoggerFactory(loggerFactory)
                               .Build();

                var sampler = GetSampler(options);

                var tracer = new Tracer.Builder(options.ServiceName)
                             .WithLoggerFactory(loggerFactory)
                             .WithReporter(reporter)
                             .WithSampler(sampler)
                             .Build();

                GlobalTracer.Register(tracer);

                return(tracer);
            });

            return(builder);
        }
コード例 #15
0
        public static IConveyBuilder AddMongo(this IConveyBuilder builder, MongoDbOptions mongoOptions,
                                              Type seederType = null, bool registerConventions = true)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton(mongoOptions);
            builder.Services.AddSingleton <IMongoClient>(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                return(new MongoClient(options.ConnectionString));
            });
            builder.Services.AddTransient(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                var client  = sp.GetService <IMongoClient>();
                return(client.GetDatabase(options.Database));
            });
            builder.Services.AddTransient <IMongoDbInitializer, MongoDbInitializer>();
            builder.Services.AddTransient <IMongoSessionFactory, MongoSessionFactory>();

            if (seederType is null)
            {
                builder.Services.AddTransient <IMongoDbSeeder, MongoDbSeeder>();
            }
            else
            {
                builder.Services.AddTransient(typeof(IMongoDbSeeder), seederType);
            }

            builder.AddInitializer <IMongoDbInitializer>();
            if (registerConventions && !_conventionsRegistered)
            {
                RegisterConventions();
            }

            return(builder);
        }
コード例 #16
0
ファイル: Extensions.cs プロジェクト: mumby0168/Convey
    public static IConveyBuilder AddCertificateAuthentication(this IConveyBuilder builder,
                                                              string sectionName = SectionName, Type permissionValidatorType = null)
    {
        var options = builder.GetOptions <SecurityOptions>(sectionName);

        builder.Services.AddSingleton(options);
        if (!builder.TryRegister(RegistryName))
        {
            return(builder);
        }

        if (options.Certificate is null || !options.Certificate.Enabled)
        {
            return(builder);
        }

        if (permissionValidatorType is not null)
        {
            builder.Services.AddSingleton(typeof(ICertificatePermissionValidator), permissionValidatorType);
        }
        else
        {
            builder.Services.AddSingleton <ICertificatePermissionValidator, DefaultCertificatePermissionValidator>();
        }

        builder.Services.AddSingleton <CertificateMiddleware>();
        builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate();
        builder.Services.AddCertificateForwarding(c =>
        {
            c.CertificateHeader = options.Certificate.GetHeaderName();
            c.HeaderConverter   = headerValue =>
                                  string.IsNullOrWhiteSpace(headerValue)
                    ? null
                    : new X509Certificate2(StringToByteArray(headerValue));
        });

        return(builder);
    }
コード例 #17
0
        public static IConveyBuilder AddMongo(this IConveyBuilder builder, MongoDbOptions mongoOptions,
                                              IMongoDbSeeder seeder = null)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton(mongoOptions);

            builder.Services.AddSingleton <IMongoClient>(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                return(new MongoClient(options.ConnectionString));
            });

            builder.Services.AddTransient(sp =>
            {
                var options = sp.GetService <MongoDbOptions>();
                var client  = sp.GetService <MongoClient>();
                return(client.GetDatabase(options.Database));
            });

            builder.Services.AddTransient <IMongoDbInitializer, MongoDbInitializer>();
            builder.Services.AddTransient <IMongoSessionFactory, MongoSessionFactory>();

            if (seeder is null)
            {
                builder.Services.AddSingleton <IMongoDbSeeder, MongoDbSeeder>();
            }
            else
            {
                builder.Services.AddSingleton(seeder);
            }

            builder.AddInitializer <IMongoDbInitializer>();

            return(builder);
        }
コード例 #18
0
        private static IConveyBuilder AddRabbitMq <TContext>(this IConveyBuilder builder, RabbitMqOptions options,
                                                             Func <IRabbitMqPluginRegister, IRabbitMqPluginRegister> plugins, Action <IConveyBuilder> registerRedis)
            where TContext : class, new()
        {
            builder.Services.AddSingleton(options);
            builder.Services.AddSingleton <RawRabbitConfiguration>(options);
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddTransient <IBusPublisher, BusPublisher>();
            if (options.MessageProcessor?.Enabled == true)
            {
                switch (options.MessageProcessor.Type?.ToLowerInvariant())
                {
                case "redis":
                    registerRedis(builder);
                    builder.Services.AddTransient <IMessageProcessor, RedisMessageProcessor>();
                    break;

                default:
                    builder.Services.AddMemoryCache();
                    builder.Services.AddTransient <IMessageProcessor, InMemoryMessageProcessor>();
                    break;
                }
            }
            else
            {
                builder.Services.AddSingleton <IMessageProcessor, EmptyMessageProcessor>();
            }

            builder.Services.AddSingleton <ICorrelationContextAccessor>(new CorrelationContextAccessor());

            ConfigureBus <TContext>(builder, plugins);

            return(builder);
        }
コード例 #19
0
        public static IConveyBuilder AddMessageOutbox(this IConveyBuilder builder, string sectionName = SectionName)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            var options = builder.GetOptions <OutboxOptions>(sectionName);

            builder.Services.AddSingleton(options);

            switch (options.Type?.ToLowerInvariant() ?? string.Empty)
            {
            default:
                builder.AddMongo();
                builder.AddMongoRepository <OutboxMessage, Guid>("outbox");
                builder.Services.AddTransient <IMessageOutbox, MongoMessageOutbox>();
                builder.Services.AddHostedService <OutboxProcessor>();
                break;
            }

            return(builder);
        }
コード例 #20
0
ファイル: Extensions.cs プロジェクト: fahrigoktuna/Convey-1
        public static IConveyBuilder AddMessageOutbox(this IConveyBuilder builder,
                                                      Action <IMessageOutboxConfigurator> configure = null, string sectionName = SectionName)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            var options = builder.GetOptions <OutboxOptions>(sectionName);

            builder.Services.AddSingleton(options);
            var configurator = new MessageOutboxConfigurator(builder, options);

            if (configure is null)
            {
                configurator.AddInMemory();
            }
            else
            {
                configure(configurator);
            }

            if (!options.Enabled)
            {
                return(builder);
            }

            builder.Services.AddHostedService <OutboxProcessor>();

            return(builder);
        }
コード例 #21
0
        public static IConveyBuilder AddWebApi(this IConveyBuilder builder, Action <IMvcCoreBuilder> configureMvc = null,
                                               IJsonSerializer jsonSerializer = null, string sectionName = SectionName)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (jsonSerializer is null)
            {
                var factory = new Open.Serialization.Json.Newtonsoft.JsonSerializerFactory(new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    Converters       = { new StringEnumConverter(true) }
                });
                jsonSerializer = factory.GetSerializer();
            }

            if (jsonSerializer.GetType().Namespace?.Contains("Newtonsoft") == true)
            {
                builder.Services.Configure <KestrelServerOptions>(o => o.AllowSynchronousIO = true);
                builder.Services.Configure <IISServerOptions>(o => o.AllowSynchronousIO     = true);
            }

            builder.Services.AddSingleton(jsonSerializer);
            builder.Services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
            builder.Services.AddSingleton(new WebApiEndpointDefinitions());
            var options = builder.GetOptions <WebApiOptions>(sectionName);

            builder.Services.AddSingleton(options);
            _bindRequestFromRoute = options.BindRequestFromRoute;

            var mvcCoreBuilder = builder.Services
                                 .AddLogging()
                                 .AddMvcCore();

            mvcCoreBuilder.AddMvcOptions(o =>
            {
                o.OutputFormatters.Clear();
                o.OutputFormatters.Add(new JsonOutputFormatter(jsonSerializer));
                o.InputFormatters.Clear();
                o.InputFormatters.Add(new JsonInputFormatter(jsonSerializer));
            })
            .AddDataAnnotations()
            .AddApiExplorer()
            .AddAuthorization();

            configureMvc?.Invoke(mvcCoreBuilder);

            builder.Services.Scan(s =>
                                  s.FromAssemblies(AppDomain.CurrentDomain.GetAssemblies())
                                  .AddClasses(c => c.AssignableTo(typeof(IRequestHandler <,>))
                                              .WithoutAttribute(typeof(DecoratorAttribute)))
                                  .AsImplementedInterfaces()
                                  .WithTransientLifetime());

            builder.Services.AddTransient <IRequestDispatcher, RequestDispatcher>();

            if (builder.Services.All(s => s.ServiceType != typeof(IExceptionToResponseMapper)))
            {
                builder.Services.AddTransient <IExceptionToResponseMapper, EmptyExceptionToResponseMapper>();
            }

            return(builder);
        }
コード例 #22
0
        public static IConveyBuilder AddRabbitMq(this IConveyBuilder builder, string sectionName = SectionName)
        {
            var options = builder.GetOptions <RabbitMqOptions>(sectionName);

            builder.Services.AddSingleton(options);
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton <IContextProvider, ContextProvider>();
            builder.Services.AddSingleton <ICorrelationContextAccessor>(new CorrelationContextAccessor());
            builder.Services.AddSingleton <IMessagePropertiesAccessor>(new MessagePropertiesAccessor());
            builder.Services.AddSingleton <IConventionsBuilder, ConventionsBuilder>();
            builder.Services.AddSingleton <IConventionsProvider, ConventionsProvider>();
            builder.Services.AddSingleton <IConventionsRegistry, ConventionsRegistry>();
            builder.Services.AddSingleton <IRabbitMqSerializer, NewtonsoftJsonRabbitMqSerializer>();
            builder.Services.AddSingleton <IRabbitMqClient, RabbitMqClient>();
            builder.Services.AddSingleton <IBusPublisher, RabbitMqPublisher>();
            builder.Services.AddSingleton <IBusSubscriber, RabbitMqSubscriber>();
            if (options.MessageProcessor?.Enabled == true)
            {
                builder.Services.AddSingleton <IRabbitMqMiddleware, UniqueMessagesMiddleware>();
                builder.Services.AddSingleton <IUniqueMessagesMiddleware, UniqueMessagesMiddleware>();
                switch (options.MessageProcessor.Type?.ToLowerInvariant())
                {
                default:
                    builder.Services.AddMemoryCache();
                    builder.Services.AddSingleton <IMessageProcessor, InMemoryMessageProcessor>();
                    break;
                }
            }
            else
            {
                builder.Services.AddSingleton <IMessageProcessor, EmptyMessageProcessor>();
            }

            builder.Services.AddSingleton(sp =>
            {
                var connectionFactory = new ConnectionFactory
                {
                    HostName    = options.HostNames?.FirstOrDefault(),
                    Port        = options.Port,
                    VirtualHost = options.VirtualHost,
                    UserName    = options.Username,
                    Password    = options.Password,
                    RequestedConnectionTimeout = options.RequestedConnectionTimeout,
                    SocketReadTimeout          = options.SocketReadTimeout,
                    SocketWriteTimeout         = options.SocketWriteTimeout,
                    RequestedChannelMax        = options.RequestedChannelMax,
                    RequestedFrameMax          = options.RequestedFrameMax,
                    RequestedHeartbeat         = options.RequestedHeartbeat,
                    UseBackgroundThreadsForIO  = options.UseBackgroundThreadsForIO,
                    DispatchConsumersAsync     = true,
                    Ssl = options.Ssl is null
                        ? new SslOption()
                        : new SslOption(options.Ssl.ServerName, options.Ssl.CertificatePath, options.Ssl.Enabled)
                };

                var connection = connectionFactory.CreateConnection(options.ConnectionName);
                if (options.Exchange is null || !options.Exchange.Declare)
                {
                    return(connection);
                }

                using (var channel = connection.CreateModel())
                {
                    if (options.Logger?.Enabled == true)
                    {
                        var logger = sp.GetService <ILogger <IConnection> >();
                        logger.LogInformation($"Declaring an exchange: '{options.Exchange.Name}', type: '{options.Exchange.Type}'.");
                    }

                    channel.ExchangeDeclare(options.Exchange.Name, options.Exchange.Type, options.Exchange.Durable,
                                            options.Exchange.AutoDelete);
                    channel.Close();
                }

                return(connection);
            });

            return(builder);
        }
コード例 #23
0
ファイル: Extensions.cs プロジェクト: ubudubu/Convey
        public static IConveyBuilder AddRabbitMq(this IConveyBuilder builder, string sectionName = SectionName,
                                                 Func <IRabbitMqPluginsRegistry, IRabbitMqPluginsRegistry> plugins = null)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            var options = builder.GetOptions <RabbitMqOptions>(sectionName);

            builder.Services.AddSingleton(options);
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton <IContextProvider, ContextProvider>();
            builder.Services.AddSingleton <ICorrelationContextAccessor>(new CorrelationContextAccessor());
            builder.Services.AddSingleton <IMessagePropertiesAccessor>(new MessagePropertiesAccessor());
            builder.Services.AddSingleton <IConventionsBuilder, ConventionsBuilder>();
            builder.Services.AddSingleton <IConventionsProvider, ConventionsProvider>();
            builder.Services.AddSingleton <IConventionsRegistry, ConventionsRegistry>();
            builder.Services.AddSingleton <IRabbitMqSerializer, NewtonsoftJsonRabbitMqSerializer>();
            builder.Services.AddSingleton <IRabbitMqClient, RabbitMqClient>();
            builder.Services.AddSingleton <IBusPublisher, RabbitMqPublisher>();
            builder.Services.AddSingleton <IBusSubscriber, RabbitMqSubscriber>();
            builder.Services.AddTransient <RabbitMqExchangeInitializer>();
            builder.AddInitializer <RabbitMqExchangeInitializer>();

            var pluginsRegistry = new RabbitMqPluginsRegistry();

            builder.Services.AddSingleton <IRabbitMqPluginsRegistryAccessor>(pluginsRegistry);
            builder.Services.AddSingleton <IRabbitMqPluginsExecutor, RabbitMqPluginsExecutor>();
            plugins?.Invoke(pluginsRegistry);

            if (options.MessageProcessor?.Enabled == true)
            {
                pluginsRegistry.Add <UniqueMessagesPlugin>();
                switch (options.MessageProcessor.Type?.ToLowerInvariant())
                {
                case "distributed":
                    builder.Services.AddTransient <IMessageProcessor, DistributedMessageProcessor>();
                    break;

                default:
                    builder.Services.AddTransient <IMessageProcessor, InMemoryMessageProcessor>();
                    break;
                }
            }
            else
            {
                builder.Services.AddSingleton <IMessageProcessor, EmptyMessageProcessor>();
            }

            builder.Services.AddSingleton(sp =>
            {
                var connectionFactory = new ConnectionFactory
                {
                    HostName    = options.HostNames?.FirstOrDefault(),
                    Port        = options.Port,
                    VirtualHost = options.VirtualHost,
                    UserName    = options.Username,
                    Password    = options.Password,
                    RequestedConnectionTimeout = options.RequestedConnectionTimeout,
                    SocketReadTimeout          = options.SocketReadTimeout,
                    SocketWriteTimeout         = options.SocketWriteTimeout,
                    RequestedChannelMax        = options.RequestedChannelMax,
                    RequestedFrameMax          = options.RequestedFrameMax,
                    RequestedHeartbeat         = options.RequestedHeartbeat,
                    UseBackgroundThreadsForIO  = options.UseBackgroundThreadsForIO,
                    DispatchConsumersAsync     = true,
                    Ssl = options.Ssl is null
                        ? new SslOption()
                        : new SslOption(options.Ssl.ServerName, options.Ssl.CertificatePath, options.Ssl.Enabled)
                };

                return(connectionFactory.CreateConnection(options.ConnectionName));
            });

            ((IRabbitMqPluginsRegistryAccessor)pluginsRegistry).Get().ToList().ForEach(p =>
                                                                                       builder.Services.AddTransient(p.PluginType));

            return(builder);
        }
コード例 #24
0
        private static IConveyBuilder AddJwt(this IConveyBuilder builder, JwtOptions options)
        {
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            builder.Services.AddSingleton(options);
            builder.Services.AddSingleton <IJwtHandler, JwtHandler>();
            builder.Services.AddSingleton <IAccessTokenService, InMemoryAccessTokenService>();
            builder.Services.AddTransient <AccessTokenValidatorMiddleware>();

            var tokenValidationParameters = new TokenValidationParameters
            {
                RequireAudience          = options.RequireAudience,
                ValidIssuer              = options.ValidIssuer,
                ValidIssuers             = options.ValidIssuers,
                ValidateActor            = options.ValidateActor,
                ValidAudience            = options.ValidAudience,
                ValidAudiences           = options.ValidAudiences,
                ValidateAudience         = options.ValidateAudience,
                ValidateIssuer           = options.ValidateIssuer,
                ValidateLifetime         = options.ValidateLifetime,
                ValidateTokenReplay      = options.ValidateTokenReplay,
                ValidateIssuerSigningKey = options.ValidateIssuerSigningKey,
                SaveSigninToken          = options.SaveSigninToken,
                RequireExpirationTime    = options.RequireExpirationTime,
                RequireSignedTokens      = options.RequireSignedTokens,
                ClockSkew = TimeSpan.Zero
            };

            if (!string.IsNullOrWhiteSpace(options.AuthenticationType))
            {
                tokenValidationParameters.AuthenticationType = options.AuthenticationType;
            }

            if (!string.IsNullOrWhiteSpace(options.IssuerSigningKey))
            {
                tokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes(options.IssuerSigningKey));
            }

            if (!string.IsNullOrWhiteSpace(options.NameClaimType))
            {
                tokenValidationParameters.NameClaimType = options.NameClaimType;
            }

            if (!string.IsNullOrWhiteSpace(options.RoleClaimType))
            {
                tokenValidationParameters.RoleClaimType = options.RoleClaimType;
            }

            builder.Services.AddSingleton(tokenValidationParameters);

            builder.Services
            .AddAuthentication(o =>
            {
                o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                o.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(o =>
            {
                o.Authority                  = options.Authority;
                o.Audience                   = options.Audience;
                o.MetadataAddress            = options.MetadataAddress;
                o.SaveToken                  = options.SaveToken;
                o.RefreshOnIssuerKeyNotFound = options.RefreshOnIssuerKeyNotFound;
                o.RequireHttpsMetadata       = options.RequireHttpsMetadata;
                o.IncludeErrorDetails        = options.IncludeErrorDetails;
                o.TokenValidationParameters  = tokenValidationParameters;
                if (!string.IsNullOrWhiteSpace(options.Challenge))
                {
                    o.Challenge = options.Challenge;
                }
            });

            return(builder);
        }
コード例 #25
0
ファイル: Extensions.cs プロジェクト: mumby0168/Convey
    public static IConveyBuilder AddJaeger(this IConveyBuilder builder, JaegerOptions options,
                                           string sectionName = SectionName, Action <IOpenTracingBuilder> openTracingBuilder = null)
    {
        if (Interlocked.Exchange(ref _initialized, 1) == 1)
        {
            return(builder);
        }

        builder.Services.AddSingleton(options);
        if (!options.Enabled)
        {
            var defaultTracer = ConveyDefaultTracer.Create();
            builder.Services.AddSingleton(defaultTracer);
            return(builder);
        }

        if (!builder.TryRegister(RegistryName))
        {
            return(builder);
        }

        if (options.ExcludePaths is not null)
        {
            builder.Services.Configure <AspNetCoreDiagnosticOptions>(o =>
            {
                foreach (var path in options.ExcludePaths)
                {
                    o.Hosting.IgnorePatterns.Add(x => x.Request.Path == path);
                }
            });
        }

        builder.Services.AddOpenTracing(x => openTracingBuilder?.Invoke(x));

        builder.Services.AddSingleton <ITracer>(sp =>
        {
            var loggerFactory = sp.GetRequiredService <ILoggerFactory>();
            var maxPacketSize = options.MaxPacketSize <= 0 ? 64967 : options.MaxPacketSize;
            var senderType    = string.IsNullOrWhiteSpace(options.Sender) ? "udp" : options.Sender?.ToLowerInvariant();
            ISender sender    = senderType switch
            {
                "http" => BuildHttpSender(options.HttpSender),
                "udp" => new UdpSender(options.UdpHost, options.UdpPort, maxPacketSize),
                _ => throw new Exception($"Invalid Jaeger sender type: '{senderType}'.")
            };

            var reporter = new RemoteReporter.Builder()
                           .WithSender(sender)
                           .WithLoggerFactory(loggerFactory)
                           .Build();

            var sampler = GetSampler(options);

            var tracer = new Tracer.Builder(options.ServiceName)
                         .WithLoggerFactory(loggerFactory)
                         .WithReporter(reporter)
                         .WithSampler(sampler)
                         .Build();

            GlobalTracer.Register(tracer);

            return(tracer);
        });

        return(builder);
    }
コード例 #26
0
ファイル: Extensions.cs プロジェクト: yshadmehr/Convey
        public static IConveyBuilder AddMetrics(this IConveyBuilder builder, MetricsOptions options)
        {
            builder.Services.AddSingleton(options);
            if (!builder.TryRegister(RegistryName) || !options.Enabled || _initialized)
            {
                return(builder);
            }

            _initialized = true;
            var metricsBuilder = new MetricsBuilder().Configuration.Configure(cfg =>
            {
                var tags = options.Tags;
                if (tags == null)
                {
                    return;
                }

                tags.TryGetValue("app", out var app);
                tags.TryGetValue("env", out var env);
                tags.TryGetValue("server", out var server);
                cfg.AddAppTag(string.IsNullOrWhiteSpace(app) ? null : app);
                cfg.AddEnvTag(string.IsNullOrWhiteSpace(env) ? null : env);
                cfg.AddServerTag(string.IsNullOrWhiteSpace(server) ? null : server);
                foreach (var tag in tags)
                {
                    if (!cfg.GlobalTags.ContainsKey(tag.Key))
                    {
                        cfg.GlobalTags.Add(tag.Key, tag.Value);
                    }
                }
            });

            if (options.InfluxEnabled)
            {
                metricsBuilder.Report.ToInfluxDb(o =>
                {
                    o.InfluxDb.Database = options.Database;
                    o.InfluxDb.BaseUri  = new Uri(options.InfluxUrl);
                    o.InfluxDb.CreateDataBaseIfNotExists = true;
                    o.FlushInterval = TimeSpan.FromSeconds(options.Interval);
                });
            }

            var metrics = metricsBuilder.Build();
            var metricsWebHostOptions = GetMetricsWebHostOptions(options);

            using (var serviceProvider = builder.Services.BuildServiceProvider())
            {
                var configuration = serviceProvider.GetService <IConfiguration>();
                builder.Services.AddHealth();
                builder.Services.AddHealthEndpoints(configuration);
                builder.Services.AddMetricsTrackingMiddleware(configuration);
                builder.Services.AddMetricsEndpoints(configuration);
                builder.Services.AddSingleton <IStartupFilter>(new DefaultMetricsEndpointsStartupFilter());
                builder.Services.AddSingleton <IStartupFilter>(new DefaultHealthEndpointsStartupFilter());
                builder.Services.AddSingleton <IStartupFilter>(new DefaultMetricsTrackingStartupFilter());
                builder.Services.AddMetricsReportingHostedService(metricsWebHostOptions.UnobservedTaskExceptionHandler);
                builder.Services.AddMetricsEndpoints(metricsWebHostOptions.EndpointOptions, configuration);
                builder.Services.AddMetricsTrackingMiddleware(metricsWebHostOptions.TrackingMiddlewareOptions,
                                                              configuration);
                builder.Services.AddMetrics(metrics);
            }

            return(builder);
        }
コード例 #27
0
    public static IConveyBuilder AddMetrics(this IConveyBuilder builder, MetricsOptions metricsOptions,
                                            AppOptions appOptions)
    {
        builder.Services.AddSingleton(metricsOptions);
        if (!builder.TryRegister(RegistryName) || !metricsOptions.Enabled || _initialized)
        {
            return(builder);
        }

        _initialized = true;

        //TODO: Remove once fixed https://github.com/AppMetrics/AppMetrics/issues/396
        builder.Services.Configure <KestrelServerOptions>(o => o.AllowSynchronousIO = true);
        builder.Services.Configure <IISServerOptions>(o => o.AllowSynchronousIO     = true);

        var metricsBuilder = new MetricsBuilder().Configuration.Configure(cfg =>
        {
            var tags = metricsOptions.Tags;
            if (tags is null)
            {
                return;
            }

            tags.TryGetValue("app", out var app);
            tags.TryGetValue("env", out var env);
            tags.TryGetValue("server", out var server);
            cfg.AddAppTag(string.IsNullOrWhiteSpace(app) ? appOptions.Service : app);
            cfg.AddEnvTag(string.IsNullOrWhiteSpace(env) ? null : env);
            cfg.AddServerTag(string.IsNullOrWhiteSpace(server) ? null : server);
            if (!string.IsNullOrWhiteSpace(appOptions.Instance))
            {
                cfg.GlobalTags.Add("instance", appOptions.Instance);
            }

            if (!string.IsNullOrWhiteSpace(appOptions.Version))
            {
                cfg.GlobalTags.Add("version", appOptions.Version);
            }

            foreach (var tag in tags)
            {
                if (cfg.GlobalTags.ContainsKey(tag.Key))
                {
                    cfg.GlobalTags.Remove(tag.Key);
                }

                if (!cfg.GlobalTags.ContainsKey(tag.Key))
                {
                    cfg.GlobalTags.TryAdd(tag.Key, tag.Value);
                }
            }
        });

        if (metricsOptions.InfluxEnabled)
        {
            metricsBuilder.Report.ToInfluxDb(o =>
            {
                o.InfluxDb.Database = metricsOptions.Database;
                o.InfluxDb.BaseUri  = new Uri(metricsOptions.InfluxUrl);
                o.InfluxDb.CreateDataBaseIfNotExists = true;
                o.FlushInterval = TimeSpan.FromSeconds(metricsOptions.Interval);
            });
        }

        var metrics = metricsBuilder.Build();
        var metricsWebHostOptions = GetMetricsWebHostOptions(metricsOptions);

        using var serviceProvider = builder.Services.BuildServiceProvider();
        var configuration = builder.Configuration ?? serviceProvider.GetRequiredService <IConfiguration>();

        builder.Services.AddHealth();
        builder.Services.AddHealthEndpoints(configuration);
        builder.Services.AddMetricsTrackingMiddleware(configuration);
        builder.Services.AddMetricsEndpoints(configuration);
        builder.Services.AddSingleton <IStartupFilter>(new DefaultMetricsEndpointsStartupFilter());
        builder.Services.AddSingleton <IStartupFilter>(new DefaultHealthEndpointsStartupFilter());
        builder.Services.AddSingleton <IStartupFilter>(new DefaultMetricsTrackingStartupFilter());
        builder.Services.AddMetricsReportingHostedService(metricsWebHostOptions.UnobservedTaskExceptionHandler);
        builder.Services.AddMetricsEndpoints(metricsWebHostOptions.EndpointOptions, configuration);
        builder.Services.AddMetricsTrackingMiddleware(metricsWebHostOptions.TrackingMiddlewareOptions, configuration);
        builder.Services.AddMetrics(metrics);

        return(builder);
    }
コード例 #28
0
        public static IConveyBuilder AddRabbitMq(this IConveyBuilder builder, string sectionName = SectionName,
                                                 Func <IRabbitMqPluginsRegistry, IRabbitMqPluginsRegistry> plugins = null,
                                                 Action <ConnectionFactory> connectionFactoryConfigurator          = null)
        {
            if (string.IsNullOrWhiteSpace(sectionName))
            {
                sectionName = SectionName;
            }

            var options = builder.GetOptions <RabbitMqOptions>(sectionName);

            builder.Services.AddSingleton(options);
            if (!builder.TryRegister(RegistryName))
            {
                return(builder);
            }

            if (options.HostNames is null || !options.HostNames.Any())
            {
                throw new ArgumentException("RabbitMQ hostnames are not specified.", nameof(options.HostNames));
            }

            builder.Services.AddSingleton <IContextProvider, ContextProvider>();
            builder.Services.AddSingleton <ICorrelationContextAccessor>(new CorrelationContextAccessor());
            builder.Services.AddSingleton <IMessagePropertiesAccessor>(new MessagePropertiesAccessor());
            builder.Services.AddSingleton <IConventionsBuilder, ConventionsBuilder>();
            builder.Services.AddSingleton <IConventionsProvider, ConventionsProvider>();
            builder.Services.AddSingleton <IConventionsRegistry, ConventionsRegistry>();
            builder.Services.AddSingleton <IRabbitMqSerializer, NewtonsoftJsonRabbitMqSerializer>();
            builder.Services.AddSingleton <IRabbitMqClient, RabbitMqClient>();
            builder.Services.AddSingleton <IBusPublisher, RabbitMqPublisher>();
            builder.Services.AddSingleton <IBusSubscriber, RabbitMqSubscriber>();
            builder.Services.AddTransient <RabbitMqExchangeInitializer>();
            builder.Services.AddHostedService <RabbitMqHostedService>();
            builder.AddInitializer <RabbitMqExchangeInitializer>();

            var pluginsRegistry = new RabbitMqPluginsRegistry();

            builder.Services.AddSingleton <IRabbitMqPluginsRegistryAccessor>(pluginsRegistry);
            builder.Services.AddSingleton <IRabbitMqPluginsExecutor, RabbitMqPluginsExecutor>();
            plugins?.Invoke(pluginsRegistry);

            var connectionFactory = new ConnectionFactory
            {
                Port                         = options.Port,
                VirtualHost                  = options.VirtualHost,
                UserName                     = options.Username,
                Password                     = options.Password,
                RequestedHeartbeat           = options.RequestedHeartbeat,
                RequestedConnectionTimeout   = options.RequestedConnectionTimeout,
                SocketReadTimeout            = options.SocketReadTimeout,
                SocketWriteTimeout           = options.SocketWriteTimeout,
                RequestedChannelMax          = options.RequestedChannelMax,
                RequestedFrameMax            = options.RequestedFrameMax,
                UseBackgroundThreadsForIO    = options.UseBackgroundThreadsForIO,
                DispatchConsumersAsync       = true,
                ContinuationTimeout          = options.ContinuationTimeout,
                HandshakeContinuationTimeout = options.HandshakeContinuationTimeout,
                NetworkRecoveryInterval      = options.NetworkRecoveryInterval,
                Ssl = options.Ssl is null
                    ? new SslOption()
                    : new SslOption(options.Ssl.ServerName, options.Ssl.CertificatePath, options.Ssl.Enabled)
            };

            ConfigureSsl(connectionFactory, options);
            connectionFactoryConfigurator?.Invoke(connectionFactory);

            var connection = connectionFactory.CreateConnection(options.HostNames.ToList(), options.ConnectionName);

            builder.Services.AddSingleton(connection);

            ((IRabbitMqPluginsRegistryAccessor)pluginsRegistry).Get().ToList().ForEach(p =>
                                                                                       builder.Services.AddTransient(p.PluginType));

            return(builder);
        }
コード例 #29
0
    private static IConveyBuilder AddJwt(this IConveyBuilder builder, JwtOptions options,
                                         Action <JwtBearerOptions> optionsFactory = null)
    {
        if (!builder.TryRegister(RegistryName))
        {
            return(builder);
        }

        builder.Services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>();
        builder.Services.AddSingleton <IJwtHandler, JwtHandler>();
        builder.Services.AddSingleton <IAccessTokenService, InMemoryAccessTokenService>();
        builder.Services.AddTransient <AccessTokenValidatorMiddleware>();

        if (options.AuthenticationDisabled)
        {
            builder.Services.AddSingleton <IPolicyEvaluator, DisabledAuthenticationPolicyEvaluator>();
        }

        var tokenValidationParameters = new TokenValidationParameters
        {
            RequireAudience          = options.RequireAudience,
            ValidIssuer              = options.ValidIssuer,
            ValidIssuers             = options.ValidIssuers,
            ValidateActor            = options.ValidateActor,
            ValidAudience            = options.ValidAudience,
            ValidAudiences           = options.ValidAudiences,
            ValidateAudience         = options.ValidateAudience,
            ValidateIssuer           = options.ValidateIssuer,
            ValidateLifetime         = options.ValidateLifetime,
            ValidateTokenReplay      = options.ValidateTokenReplay,
            ValidateIssuerSigningKey = options.ValidateIssuerSigningKey,
            SaveSigninToken          = options.SaveSigninToken,
            RequireExpirationTime    = options.RequireExpirationTime,
            RequireSignedTokens      = options.RequireSignedTokens,
            ClockSkew = TimeSpan.Zero
        };

        if (!string.IsNullOrWhiteSpace(options.AuthenticationType))
        {
            tokenValidationParameters.AuthenticationType = options.AuthenticationType;
        }

        var hasCertificate = false;

        if (options.Certificate is not null)
        {
            X509Certificate2 certificate = null;
            var password    = options.Certificate.Password;
            var hasPassword = !string.IsNullOrWhiteSpace(password);
            if (!string.IsNullOrWhiteSpace(options.Certificate.Location))
            {
                certificate = hasPassword
                    ? new X509Certificate2(options.Certificate.Location, password)
                    : new X509Certificate2(options.Certificate.Location);
                var keyType = certificate.HasPrivateKey ? "with private key" : "with public key only";
                Console.WriteLine($"Loaded X.509 certificate from location: '{options.Certificate.Location}' {keyType}.");
            }

            if (!string.IsNullOrWhiteSpace(options.Certificate.RawData))
            {
                var rawData = Convert.FromBase64String(options.Certificate.RawData);
                certificate = hasPassword
                    ? new X509Certificate2(rawData, password)
                    : new X509Certificate2(rawData);
                var keyType = certificate.HasPrivateKey ? "with private key" : "with public key only";
                Console.WriteLine($"Loaded X.509 certificate from raw data {keyType}.");
            }

            if (certificate is not null)
            {
                if (string.IsNullOrWhiteSpace(options.Algorithm))
                {
                    options.Algorithm = SecurityAlgorithms.RsaSha256;
                }

                hasCertificate = true;
                tokenValidationParameters.IssuerSigningKey = new X509SecurityKey(certificate);
                var actionType = certificate.HasPrivateKey ? "issuing" : "validating";
                Console.WriteLine($"Using X.509 certificate for {actionType} tokens.");
            }
        }

        if (!string.IsNullOrWhiteSpace(options.IssuerSigningKey) && !hasCertificate)
        {
            if (string.IsNullOrWhiteSpace(options.Algorithm) || hasCertificate)
            {
                options.Algorithm = SecurityAlgorithms.HmacSha256;
            }

            var rawKey = Encoding.UTF8.GetBytes(options.IssuerSigningKey);
            tokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(rawKey);
            Console.WriteLine("Using symmetric encryption for issuing tokens.");
        }

        if (!string.IsNullOrWhiteSpace(options.NameClaimType))
        {
            tokenValidationParameters.NameClaimType = options.NameClaimType;
        }

        if (!string.IsNullOrWhiteSpace(options.RoleClaimType))
        {
            tokenValidationParameters.RoleClaimType = options.RoleClaimType;
        }

        builder.Services
        .AddAuthentication(o =>
        {
            o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            o.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(o =>
        {
            o.Authority                  = options.Authority;
            o.Audience                   = options.Audience;
            o.MetadataAddress            = options.MetadataAddress;
            o.SaveToken                  = options.SaveToken;
            o.RefreshOnIssuerKeyNotFound = options.RefreshOnIssuerKeyNotFound;
            o.RequireHttpsMetadata       = options.RequireHttpsMetadata;
            o.IncludeErrorDetails        = options.IncludeErrorDetails;
            o.TokenValidationParameters  = tokenValidationParameters;
            if (!string.IsNullOrWhiteSpace(options.Challenge))
            {
                o.Challenge = options.Challenge;
            }

            optionsFactory?.Invoke(o);
        });

        builder.Services.AddSingleton(options);
        builder.Services.AddSingleton(tokenValidationParameters);

        return(builder);
    }