/// <summary> /// 使用 Redis 缓存服务(将以 Redis 缓存实现 <see cref="ICacheManager"/> 接口,默认连接配置节为 Schubert:Redis。)。 /// </summary> /// <param name="builder"></param> /// <param name="setup"> Redis 缓存的配置安装方法。</param> /// <returns></returns> public static SchubertServicesBuilder AddRedisCache(this SchubertServicesBuilder builder, Action <SchubertRedisOptions> setup = null) { var configuration = builder.Configuration.GetSection("Schubert:Redis") as IConfiguration ?? new ConfigurationBuilder().Build(); builder.ServiceCollection.Configure <SchubertRedisOptions>(configuration); SchubertRedisOptions options = new SchubertRedisOptions(); var redisSetup = new ConfigureFromConfigurationOptions <SchubertRedisOptions>(configuration); redisSetup.Configure(options); if (setup != null) { setup(options); builder.ServiceCollection.Configure(setup); } builder.ServiceCollection.AddSmart(ServiceDescriber.Singleton <ICacheManager, RedisCacheManager>(SmartOptions.Replace)); if (builder.AddedModules.Add(_module)) { builder.ServiceCollection.AddSmart(ServiceDescriber.Singleton <IRedisCacheSerializer, JsonNetSerializer>(SmartOptions.Append)); } if (options.ConnectionString.IsNullOrWhiteSpace()) { throw new SchubertException("必须为 RedisCacheManager 指定连接字符串,可以通过 Schubert:Redis:ConnectionString 配置节配置。"); } return(builder); }
/// <summary> /// 添加以 Dapper 作为持久化的数据层特性。 /// </summary> /// <param name="builder"></param> /// <param name="setup"></param> /// <returns></returns> public static SchubertServicesBuilder AddDapperDataFeature(this SchubertServicesBuilder builder, Action <DapperDataFeatureBuilder> setup = null) { DapperDatabaseOptions dbOptions = new DapperDatabaseOptions(); if (builder.AddedModules.Add(_module)) { //修改dapper的默认映射规则,让其支持下划线列名到C#实体驼峰命名属性 Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; var configuration = builder.Configuration.GetSection("Schubert:Data") as IConfiguration ?? new ConfigurationBuilder().Build(); builder.ServiceCollection.Configure <DapperDatabaseOptions>(configuration); var schubertDataSetup = new ConfigureFromConfigurationOptions <DapperDatabaseOptions>(configuration); schubertDataSetup.Configure(dbOptions); } DapperDataFeatureBuilder featureBuilder = new DapperDataFeatureBuilder(dbOptions); setup?.Invoke(featureBuilder); featureBuilder.Build(); builder.ServiceCollection.Configure(featureBuilder.Configure); builder.ServiceCollection.AddSmart(DapperServices.GetServices(dbOptions)); return(builder); }
public static SchubertServicesBuilder AddEntityFrameworkFeature(this SchubertServicesBuilder builder, Action <DbBuilder> setup = null) { DbOptions options = new DbOptions(); if (builder.AddedModules.Add(_module)) { var configuration = builder.Configuration.GetSection("Schubert:Data") as IConfiguration ?? new ConfigurationBuilder().Build(); builder.ServiceCollection.Configure <DbOptions>(configuration); var schubertDataSetup = new ConfigureFromConfigurationOptions <DbOptions>(configuration); schubertDataSetup.Configure(options); } DbBuilder dbBuilder = new DbBuilder(); if (setup != null) { setup(dbBuilder); if (dbBuilder.Setup != null) { dbBuilder.Setup(options); builder.ServiceCollection.Configure(dbBuilder.Setup); } } options.DbContextSettings = dbBuilder.DbSettings; builder.ServiceCollection.Configure <DbOptions>(dbOp => { dbOp.DbContextSettings.AddRange(dbBuilder.DbSettings, true); }); _dbConnectionMappings.AddRange(dbBuilder.DbContexts, true); if (dbBuilder.ShellDbAdded) { builder.ServiceCollection.AddSmart(ServiceDescriber.Scoped <IRepository <ShellDescriptorRecord>, Repository <ShellDescriptorRecord, ShellDescriptorDbContext> >()); builder.ServiceCollection.AddSmart(ServiceDescriber.Scoped <IRepository <SettingRecord>, Repository <SettingRecord, ShellDescriptorDbContext> >()); builder.ServiceCollection.AddSmart(ServiceDescriber.Scoped <IShellDescriptorManager, ShellDescriptorManager>()); } builder.ServiceCollection.AddSmart(EntityFrameworkServices.GetServices(options)); foreach (var action in dbBuilder.DbConfigurings.Values) { action(builder.ServiceCollection); } builder.ServiceCollection.AddSmart(ServiceDescriber.Scoped( s => { IOptions <DbOptions> dbOps = s.GetRequiredService <IOptions <DbOptions> >(); return(new DbContextResources(s, dbBuilder.DefaultDbConnectionName, _dbConnectionMappings)); }, SmartOptions.Replace)); builder.ServiceCollection.TryAddScoped <IDatabaseContext>(s => s.GetRequiredService <DbContextResources>()); return(builder); }
/// <summary> /// 向服务集合中添加 SchubertFramework 的依赖服务。 /// </summary> /// <param name="services"></param> /// <param name="configuration">应用程序配置对象。</param> /// <param name="setupAction">SchubertFramework 安装选项。</param> /// <param name="shellCreationSetup">配置 Shell 环境,该操作作用域仅为 Shell 创建过程。</param> public static void AddSchubertFramework(this IServiceCollection services, IConfiguration configuration, Action <SchubertServicesBuilder> setupAction = null, Action <ShellCreationScope> shellCreationSetup = null) { AddVariables(configuration); IConfiguration c = (configuration.GetSection("Schubert") as IConfiguration) ?? new ConfigurationBuilder().Build(); Console.OutputEncoding = System.Text.Encoding.UTF8; Guard.ArgumentNotNull(configuration, nameof(configuration)); SchubertEngine.Current.ApplicationName = c.GetSection(nameof(SchubertOptions.AppSystemName))?.Value.IfNullOrWhiteSpace(String.Empty); SchubertEngine.Current.GroupName = c.GetSection(nameof(SchubertOptions.Group))?.Value.IfNullOrWhiteSpace(String.Empty); SchubertEngine.Current.ApplicationVersion = c.GetSection(nameof(SchubertOptions.Version))?.Value.IfNullOrWhiteSpace("0.0.0"); services.Configure <MemoryCacheOptions>(o => o.ExpirationScanFrequency = TimeSpan.FromMinutes(3)); //刷新和ExpirationScanFrequency的设置没有关系 services.Configure <SchubertOptions>(c); var networkConfiguration = (configuration.GetSection("Schubert:Network") as IConfiguration) ?? new ConfigurationBuilder().Build(); services.Configure <NetworkOptions>(networkConfiguration); var builder = new SchubertServicesBuilder(services, configuration); setupAction?.Invoke(builder); InitShell(builder, shellCreationSetup); }
public override void ConfigureServices(SchubertServicesBuilder servicesBuilder, SchubertWebOptions webOptions) { servicesBuilder.ServiceCollection.Configure <MvcOptions>(options => { options.ModelMetadataDetailsProviders.Add(new FluentValidationMetadataProvider()); options.ModelValidatorProviders.Add(new FluentValidationModelValidatorProvider()); }); servicesBuilder.ServiceCollection.AddTransient <IConfigureOptions <MvcViewOptions>, LabijieMvcViewOptionsSetup>(); }
/// <summary> /// 使用 Schubert 提供的缓存来实现 asp.net 框架中的缓存(<see cref="IDistributedCache"/>)提供程序。 /// </summary> /// <param name="collection"></param> /// <param name="regionName">用来存储 asp.net 缓存数据的分区。</param> public static void AddCacheForAspNet(this SchubertServicesBuilder collection, string regionName = "aspnet") { collection.ServiceCollection.AddSmart(new SmartServiceDescriptor(typeof(IDistributedCache), serviceProvider => { var manager = serviceProvider.GetRequiredService <ICacheManager>(); return(new DistributedCacheAdapter(manager, regionName)); }, ServiceLifetime.Transient) { Options = SmartOptions.TryAdd }); }
public override void ConfigureServices(SchubertServicesBuilder servicesBuilder, SchubertWebOptions options) { var identitySvcdescriptor = ServiceDescriber.Scoped <IIdentityService, TIdentityService>(); servicesBuilder.ServiceCollection.AddSmart(identitySvcdescriptor); servicesBuilder.ServiceCollection .AddIdentity <TUser, TRole>(iop => _configure?.Invoke(iop)) .AddDefaultTokenProviders() .AddDapperStores <TUser, TRole>(); }
/// <summary> /// 向服务容器中添加 Swifty (基于 Thrift 的 RPC)服务。 /// 可以使用 <see cref="SwiftyOptions.EnableFeatures"/> 控制是否启用客户端/服务端功能。 /// </summary> /// <param name="builder"></param> /// <param name="setupAction">对 Swifty 进行配置的委托。</param> public static void AddSwifty(this SchubertServicesBuilder builder, Action <SwiftyOptions> setupAction = null) { SwiftyOptions touchOptions = AddSwiftyOptions(builder, setupAction); //启动服务端。 if (touchOptions.EnableFeatures.HasFlag(SwiftyFeatures.Server)) { AddSwiftyServer(); } if (touchOptions.EnableFeatures.HasFlag(SwiftyFeatures.Client) /*&& !touchOptions.Client.ExploringAssemblies.IsNullOrEmpty()*/) { AddSwiftyClient(touchOptions); } }
private static void AddMvc(SchubertServicesBuilder services, SchubertWebBuilder featureBuilder, SchubertWebOptions options) { Action <MvcOptions> configure = mvc => { if (!options.GlobalRoutePrefix.IsNullOrWhiteSpace()) { mvc.Conventions.Insert(0, new RoutePrefixConvention(new RouteAttribute(options.GlobalRoutePrefix.Trim()))); } }; switch (options.MvcFeatures) { case MvcFeatures.Full: var mvcBuilder = services.ServiceCollection.AddMvc(configure); featureBuilder.MvcSetup?.Invoke(mvcBuilder); mvcBuilder.AddJsonOptions(json => json.SerializerSettings.ContractResolver = GetContractResolver(options.JsonCaseStyle, options.JsonResolver)) .AddRazorOptions(rveo => { rveo.FileProviders.Insert(0, new ModuleFileProvider(rveo.FileProviders.FirstOrDefault())); rveo.ViewLocationExpanders.Insert(0, new ModuleViewLocationExpander()); }); //services.ServiceCollection.AddAntiforgery(); break; case MvcFeatures.Core: var coreBuilder = services.ServiceCollection.AddMvcCore(configure); featureBuilder.MvcCoreSetup?.Invoke(coreBuilder); break; case MvcFeatures.Api: var apiBuilder = services.ServiceCollection.AddMvcCore(configure); featureBuilder.MvcCoreSetup?.Invoke(apiBuilder); apiBuilder.AddApiExplorer() .AddAuthorization() .AddFormatterMappings() .AddJsonFormatters(settings => settings.ContractResolver = GetContractResolver(options.JsonCaseStyle, options.JsonResolver)) .AddDataAnnotations() .AddCors(); featureBuilder.AddWebApiConventions(); break; default: return; } }
/// <summary> /// 添加任务调度组件。 /// </summary> /// <param name="builder"><see cref="SchubertServicesBuilder"/> 对象。</param> /// <param name="setup">用于配置调度组件的方法。</param> /// <returns></returns> public static SchubertServicesBuilder AddJobScheduling(this SchubertServicesBuilder builder, Action <SchedulingOptions> setup = null) { if (builder.AddedModules.Add(_module)) { builder.ServiceCollection.AddSmart(ServiceDescriber.Singleton(typeof(IWorkContextProvider), typeof(JobWorkContextProvider), SmartOptions.Append)); } builder.ServiceCollection.AddSmart(ServiceDescriber.Singleton(typeof(ISchedulingServer), typeof(QuartzSchedulingServer), SmartOptions.TryAdd)); var schedulingConfiguration = builder.Configuration.GetSection("Schubert:Scheduling"); builder.ServiceCollection.Configure <SchedulingOptions>(schedulingConfiguration); if (setup != null) { builder.ServiceCollection.Configure(setup); } ShellEvents.EngineStarted -= ShellEvents_OnEngineStarted; ShellEvents.EngineStarted += ShellEvents_OnEngineStarted; return(builder); }
private static SwiftyOptions AddSwiftyOptions(SchubertServicesBuilder builder, Action <SwiftyOptions> setupAction) { SwiftyOptions touchOptions = new SwiftyOptions(); var configuration = builder.Configuration.GetSection("Schubert:Swifty") as IConfiguration ?? new ConfigurationBuilder().Build(); var schubertDataSetup = new ConfigureFromConfigurationOptions <SwiftyOptions>(configuration); builder.ServiceCollection.Configure <SwiftyOptions>(configuration); schubertDataSetup.Configure(touchOptions); if (setupAction != null) { builder.ServiceCollection.Configure(setupAction); setupAction(touchOptions); } builder.ServiceCollection.AddSmart(SwiftyServices.GetServices()); return(touchOptions); }
public SchubertWebBuilder(SchubertServicesBuilder builder) { _builder = builder; }
protected internal abstract void ConfigureServices(SchubertServicesBuilder builder);
private static void InitShell(SchubertServicesBuilder schubertBuilder, Action <ShellCreationScope> setup) { ShellCreationScope shellScope = new ShellCreationScope(); setup?.Invoke(shellScope); var builder = schubertBuilder.ServiceCollection.FillToOther(); builder.AddSmart(SchubertServices.GetServices(schubertBuilder.Configuration)); builder.AddLogging(lb => { shellScope.LoggingConfigure?.Invoke(lb); }); var scopeFactory = builder.BuildServiceProvider().GetRequiredService <IServiceScopeFactory>(); using (IServiceScope scope = scopeFactory.CreateScope()) { IServiceProvider provider = scope.ServiceProvider; var shellLogger = provider.GetRequiredService <ILoggerFactory>().CreateLogger("Schubert"); shellLogger.WriteInformation("开始加载 Shell。"); var sw = Stopwatch.StartNew(); SchubertEngine.Current.LoadEnvironment(provider); var factory = provider.GetRequiredService <IShellContextFactory>(); var context = factory.CreateShellContext(); AddConfiguredOptions(schubertBuilder.ServiceCollection, schubertBuilder.Configuration, context); //微软框架依然存在解决日志组件创建后的销毁问题,只能通过移除日志来达到清理目的。 schubertBuilder.ServiceCollection.Remove(sd => sd.ServiceType.Equals(typeof(ILoggerFactory))); schubertBuilder.ServiceCollection.AddLogging(b => b.AddConfiguration(schubertBuilder.Configuration.GetSection("Logging"))); schubertBuilder.ServiceCollection.AddSingleton(context); schubertBuilder.ServiceCollection.AddSmart(context.Services); schubertBuilder.ServiceCollection.AddSmart(SchubertServices.GetServices(schubertBuilder.Configuration)); SchubertEngine.Current.ShellCreated = true; IOptions <SchubertOptions> schubertOptions = provider.GetRequiredService <IOptions <SchubertOptions> >(); context.RegisteredServices = builder; ShellEvents.NotifyShellInitialized(schubertOptions.Value, context); sw.Stop(); var table = new Tuple <int, int, int, int, String>( context.Blueprint.Modules.Count(), context.Blueprint.Controllers.Count(), context.Blueprint.Dependencies.Count(), context.Blueprint.DependencyDescribers.Count(), context.Blueprint.Modules.ToArrayString(System.Environment.NewLine)); StringBuilder info = new StringBuilder(); info.AppendLine(@" ________ ________ ___ ___ ___ ___ ________ _______ ________ _________ |\ ____\|\ ____\|\ \|\ \|\ \|\ \|\ __ \|\ ___ \ |\ __ \|\___ ___\ \ \ \___|\ \ \___|\ \ \\\ \ \ \\\ \ \ \|\ /\ \ __/|\ \ \|\ \|___ \ \_| \ \_____ \ \ \ \ \ __ \ \ \\\ \ \ __ \ \ \_|/_\ \ _ _\ \ \ \ \|____|\ \ \ \____\ \ \ \ \ \ \\\ \ \ \|\ \ \ \_|\ \ \ \\ \| \ \ \ ____\_\ \ \_______\ \__\ \__\ \_______\ \_______\ \_______\ \__\\ _\ \ \__\ |\_________\|_______|\|__|\|__|\|_______|\|_______|\|_______|\|__|\|__| \|__| \|_________| "); info.AppendLine($"Shell 加载完成,Schubert Version: {typeof(SchubertException).GetTypeInfo().Assembly.GetName().Version.ToString()} ({sw.ElapsedMilliseconds} ms)。"); info.AppendLine(" "); info.AppendLine((new Tuple <int, int, int, int, String>[] { table }).ToStringTable(new String[] { "modules", "controllers", "dependencies", "describers", "moduleList" }, t => t.Item1, t => t.Item2, t => t.Item3, t => t.Item4, t => t.Item5)); info.AppendLine(" "); info.Append(context.Blueprint.Dependencies.GroupBy(d => d.Feature.Descriptor.ModuleName, d => (ShellBlueprintDependencyItem)d).ToStringTable( new string[] { "module", "dependencies", "internfaces", "lifetime" }, f => f.Key, d => d.SelectMany(t => CreateArray(t.Type.Name, t.Interfaces.Count)).ToArrayString(System.Environment.NewLine), d => d.SelectMany(t => t.Interfaces).Select(i => i.Item1.Name).ToArrayString(System.Environment.NewLine), d => d.SelectMany(t => t.Interfaces).Select(i => i.Item2.ToString().ToLower()).ToArrayString(System.Environment.NewLine))); info.AppendLine(" "); shellLogger.WriteInformation(info.ToString()); } }
public abstract void ConfigureServices(SchubertServicesBuilder servicesBuilder, SchubertWebOptions options);
/// <summary> /// 启用Schubert 框架的 Web 特性。 /// </summary> /// <param name="services"></param> /// <param name="setup">加入 Mvc 支持。</param> /// <returns></returns> public static SchubertServicesBuilder AddWebFeature(this SchubertServicesBuilder services, Action <SchubertWebBuilder> setup = null) { SchubertWebOptions options = new SchubertWebOptions(); bool firstInvoke = true; if ((firstInvoke = services.AddedModules.Add(_module))) { IConfiguration configuration = services.Configuration.GetSection("Schubert:Web") as IConfiguration ?? new ConfigurationBuilder().Build(); services.ServiceCollection.Configure <SchubertWebOptions>(configuration); var schubertWebSetup = new SchubertWebOptionsSetup(configuration); schubertWebSetup.Configure(options); } _webBuilder = new SchubertWebBuilder(services); setup?.Invoke(_webBuilder); if (_webBuilder.FeatureSetup != null) { services.ServiceCollection.Configure(setup); } _webBuilder.FeatureSetup?.Invoke(options); services.ServiceCollection.AddDataProtection(); services.ServiceCollection.AddLocalization(); services.ServiceCollection.Replace(ServiceDescriptor.Singleton <IStringLocalizerFactory, SchubertStringLocalizerFactory>()); services.ServiceCollection.TryAddSingleton <IMemoryCache>(s => LocalCache.InnerCache); services.AddCacheForAspNet(); var cookieSetup = _webBuilder.CookieSetup; services.ServiceCollection.ConfigureApplicationCookie(o => { o.LoginPath = "/Login"; o.LogoutPath = "/LogOff"; o.Cookie.HttpOnly = true; o.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; cookieSetup?.Invoke(o); }); var authenticationBuilder = services.ServiceCollection.AddAuthentication(); if (options.UseCookieAuth) { authenticationBuilder.AddCookie(); } if (options.UseSession) { services.ServiceCollection.AddSession(sop => { sop.IdleTimeout = TimeSpan.FromMinutes(options.SessionTimeoutMinutes); }); } services.ServiceCollection.AddSmart(SchubertWebServices.GetServices(options, firstInvoke)); foreach (var s in _webBuilder.WebStarters) { s.ConfigureServices(services, options); } AddMvc(services, _webBuilder, options); return(services); }