public override void Initialize() { Func <IMenuRepository> menuRepFactory = () => new ContentRepositoryImpl(_connectionStringName, _container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); _container.RegisterInstance(menuRepFactory); _container.RegisterType <IMenuService, MenuServiceImpl>(); var settingsManager = _container.Resolve <ISettingsManager>(); var blobConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["CmsContentConnectionString"].ConnectionString); Func <string, IContentBlobStorageProvider> contentProviderFactory = (chrootPath) => { if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var storagePath = Path.Combine(NormalizePath(blobConnectionString.RootPath), chrootPath.Replace("/", "\\")); var publicUrl = blobConnectionString.PublicUrl + "/" + chrootPath; //Do not export default theme (Themes/default) its will distributed with code return(new FileSystemContentBlobStorageProvider(storagePath, publicUrl, "/Themes/default")); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { return(new AzureContentBlobStorageProvider(blobConnectionString.ConnectionString, Path.Combine(blobConnectionString.RootPath, chrootPath))); } throw new NotImplementedException(); }; _container.RegisterInstance(contentProviderFactory); }
public override void Initialize() { Func <IMenuRepository> menuRepFactory = () => new ContentRepositoryImpl(_connectionStringName, _container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); _container.RegisterInstance(menuRepFactory); _container.RegisterType <IMenuService, MenuServiceImpl>(); var connectionString = ConnectionStringHelper.GetConnectionString("CmsContentConnectionString"); if (string.IsNullOrEmpty(connectionString)) { var settingsManager = _container.Resolve <ISettingsManager>(); connectionString = settingsManager.GetValue("VirtoCommerce.Content.CmsContentConnectionString", string.Empty); } if (string.IsNullOrEmpty(connectionString)) { throw new InvalidOperationException("CmsContentConnectionString is not defined. Please define module setting VirtoCommerce.Content.CmsContentConnectionString or in web.config"); } Func <string, IContentBlobStorageProvider> contentProviderFactory = chrootPath => { var blobConnectionString = BlobConnectionString.Parse(connectionString); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var storagePath = Path.Combine(NormalizePath(blobConnectionString.RootPath), chrootPath.Replace("/", "\\")); //Use content api/content as public url by default var publicUrl = VirtualPathUtility.ToAbsolute("~/api/content/" + chrootPath) + "?relativeUrl="; if (!string.IsNullOrEmpty(blobConnectionString.PublicUrl)) { publicUrl = blobConnectionString.PublicUrl + "/" + chrootPath; } //Do not export default theme (Themes/default) its will distributed with code return(new FileSystemContentBlobStorageProvider(storagePath, publicUrl)); } if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { return(new AzureContentBlobStorageProvider(blobConnectionString.ConnectionString, Path.Combine(blobConnectionString.RootPath, chrootPath))); } throw new InvalidOperationException("Unknown storage provider: " + blobConnectionString.Provider); }; _container.RegisterInstance(contentProviderFactory); }
private static void InitializePlatform( IAppBuilder app, IUnityContainer container, IPathMapper pathMapper, string connectionString, HangfireLauncher hangfireLauncher, string modulesPath, ModuleInitializerOptions moduleInitializerOptions) { container.RegisterType <ICurrentUser, CurrentUser>(new HttpContextLifetimeManager()); container.RegisterType <IUserNameResolver, UserNameResolver>(); #region Setup database using (var db = new SecurityDbContext(connectionString)) { new IdentityDatabaseInitializer().InitializeDatabase(db); } using (var context = new PlatformRepository(connectionString, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor())) { new PlatformDatabaseInitializer().InitializeDatabase(context); } hangfireLauncher.ConfigureDatabase(); #endregion Func <IPlatformRepository> platformRepositoryFactory = () => new PlatformRepository(connectionString, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); container.RegisterType <IPlatformRepository>(new InjectionFactory(c => platformRepositoryFactory())); container.RegisterInstance(platformRepositoryFactory); var moduleCatalog = container.Resolve <IModuleCatalog>(); #region Caching //Cure for System.Runtime.Caching.MemoryCache freezing //https://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol app.SanitizeThreadCulture(); ICacheManager <object> cacheManager = null; var redisConnectionString = ConfigurationHelper.GetConnectionStringValue("RedisConnectionString"); //Try to load cache configuration from web.config first //Should be aware to using Web cache cache handle because it not worked in native threads. (Hangfire jobs) if (ConfigurationManager.GetSection(CacheManagerSection.DefaultSectionName) is CacheManagerSection cacheManagerSection) { CacheManagerConfiguration configuration = null; var defaultCacheManager = cacheManagerSection.CacheManagers.FirstOrDefault(p => p.Name.EqualsInvariant("platformCache")); if (defaultCacheManager != null) { configuration = ConfigurationBuilder.LoadConfiguration(defaultCacheManager.Name); } var redisCacheManager = cacheManagerSection.CacheManagers.FirstOrDefault(p => p.Name.EqualsInvariant("redisPlatformCache")); if (redisConnectionString != null && redisCacheManager != null) { configuration = ConfigurationBuilder.LoadConfiguration(redisCacheManager.Name); } if (configuration != null) { configuration.LoggerFactoryType = typeof(CacheManagerLoggerFactory); configuration.LoggerFactoryTypeArguments = new object[] { container.Resolve <ILog>() }; cacheManager = CacheFactory.FromConfiguration <object>(configuration); } } // Create a default cache manager if there is no any others if (cacheManager == null) { cacheManager = CacheFactory.Build("platformCache", settings => { settings.WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memCacheHandle") .WithExpiration(ExpirationMode.Sliding, TimeSpan.FromMinutes(5)); }); } container.RegisterInstance(cacheManager); #endregion #region Settings var platformModuleManifest = new ModuleManifest { Id = "VirtoCommerce.Platform", Version = PlatformVersion.CurrentVersion.ToString(), PlatformVersion = PlatformVersion.CurrentVersion.ToString(), Settings = new[] { new ModuleSettingsGroup { Name = "Platform|Notifications|SendGrid", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.ApiKey", ValueType = ModuleSetting.TypeSecureString, Title = "SendGrid API key", Description = "Your SendGrid API key" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SendingJob", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendingJob.TakeCount", ValueType = ModuleSetting.TypeInteger, Title = "Job Take Count", Description = "Take count for sending job" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SmtpClient", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Host", ValueType = ModuleSetting.TypeString, Title = "Smtp server host", Description = "Smtp server host" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Port", ValueType = ModuleSetting.TypeInteger, Title = "Smtp server port", Description = "Smtp server port" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Login", ValueType = ModuleSetting.TypeString, Title = "Smtp server login", Description = "Smtp server login" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Password", ValueType = ModuleSetting.TypeSecureString, Title = "Smtp server password", Description = "Smtp server password" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.UseSsl", ValueType = ModuleSetting.TypeBoolean, Title = "Use SSL", Description = "Use secure connection" }, } }, new ModuleSettingsGroup { Name = "Platform|Security", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Security.AccountTypes", ValueType = ModuleSetting.TypeString, Title = "Account types", Description = "Dictionary for possible account types", IsArray = true, ArrayValues = Enum.GetNames(typeof(AccountType)), DefaultValue = AccountType.Manager.ToString() } } }, new ModuleSettingsGroup { Name = "Platform|User Profile", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.MainMenu.State", ValueType = ModuleSetting.TypeJson, Title = "Persisted state of main menu" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Language", ValueType = ModuleSetting.TypeString, Title = "Language", Description = "Default language (two letter code from ISO 639-1, case-insensitive). Example: en, de", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.RegionalFormat", ValueType = ModuleSetting.TypeString, Title = "Regional format", Description = "Default regional format (CLDR locale code, with dash or underscore as delemiter, case-insensitive). Example: en, en_US, sr_Cyrl, sr_Cyrl_RS", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.TimeZone", ValueType = ModuleSetting.TypeString, Title = "Time zone", Description = "Default time zone (IANA time zone name [tz database], exactly as in database, case-sensitive). Examples: America/New_York, Europe/Moscow" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.ShowMeridian", ValueType = ModuleSetting.TypeBoolean, Title = "Meridian labels based on user preferences", Description = "When set to true (by default), system will display time in format like '12 hour format' when possible", DefaultValue = true.ToString() }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.UseTimeAgo", ValueType = ModuleSetting.TypeBoolean, Title = "Use time ago format when is possible", Description = "When set to true (by default), system will display date in format like 'a few seconds ago' when possible", DefaultValue = true.ToString() }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThreshold", ValueType = ModuleSetting.TypeInteger, Title = "Full date threshold", Description = "Number of units after time ago format will be switched to full date format" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThresholdUnit", ValueType = ModuleSetting.TypeString, Title = "Full date threshold unit", Description = "Unit of full date threshold", DefaultValue = "Never", AllowedValues = new[] { "Never", "Seconds", "Minutes", "Hours", "Days", "Weeks", "Months", "Quarters", "Years" } }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FourDecimalsInMoney", ValueType = ModuleSetting.TypeBoolean, Title = "Show 4 decimal digits for money", Description = "Set to true to show 4 decimal digits for money. By default - false, 2 decimal digits are shown.", DefaultValue = "false", }, } }, new ModuleSettingsGroup { Name = "Platform|User Interface", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Customization", ValueType = ModuleSetting.TypeJson, Title = "Customization", Description = "JSON contains personalization settings of manager UI", DefaultValue = "{\n" + " \"title\": \"Virto Commerce\",\n" + " \"logo\": \"Content/themes/main/images/logo.png\",\n" + " \"contrast_logo\": \"Content/themes/main/images/contrast-logo.png\",\n" + " \"favicon\": \"favicon.ico\"\n" + "}" } } } } }; var settingsManager = new SettingsManager(moduleCatalog, platformRepositoryFactory, cacheManager, new[] { new ManifestModuleInfo(platformModuleManifest) }); container.RegisterInstance <ISettingsManager>(settingsManager); #endregion #region Dynamic Properties container.RegisterType <IDynamicPropertyService, DynamicPropertyService>(new ContainerControlledLifetimeManager()); #endregion #region Notifications // Redis if (!string.IsNullOrEmpty(redisConnectionString)) { // Cache RedisConfigurations.AddConfiguration(new RedisConfiguration("redisConnectionString", redisConnectionString)); // SignalR // https://stackoverflow.com/questions/29885470/signalr-scaleout-on-azure-rediscache-connection-issues GlobalHost.DependencyResolver.UseRedis(new RedisScaleoutConfiguration(redisConnectionString, "VirtoCommerce.Platform.SignalR")); } // SignalR var tempCounterManager = new TempPerformanceCounterManager(); GlobalHost.DependencyResolver.Register(typeof(IPerformanceCounterManager), () => tempCounterManager); var hubConfiguration = new HubConfiguration { EnableJavaScriptProxies = false }; app.MapSignalR("/" + moduleInitializerOptions.RoutePrefix + "signalr", hubConfiguration); var hubSignalR = GlobalHost.ConnectionManager.GetHubContext <ClientPushHub>(); var notifier = new InMemoryPushNotificationManager(hubSignalR); container.RegisterInstance <IPushNotificationManager>(notifier); var resolver = new LiquidNotificationTemplateResolver(); container.RegisterInstance <INotificationTemplateResolver>(resolver); var notificationTemplateService = new NotificationTemplateServiceImpl(platformRepositoryFactory); container.RegisterInstance <INotificationTemplateService>(notificationTemplateService); var notificationManager = new NotificationManager(resolver, platformRepositoryFactory, notificationTemplateService); container.RegisterInstance <INotificationManager>(notificationManager); IEmailNotificationSendingGateway emailNotificationSendingGateway = null; var emailNotificationSendingGatewayName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:Gateway", "Default"); if (string.Equals(emailNotificationSendingGatewayName, "Default", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new DefaultSmtpEmailNotificationSendingGateway(settingsManager); } else if (string.Equals(emailNotificationSendingGatewayName, "SendGrid", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new SendGridEmailNotificationSendingGateway(settingsManager); } if (emailNotificationSendingGateway != null) { container.RegisterInstance(emailNotificationSendingGateway); } ISmsNotificationSendingGateway smsNotificationSendingGateway = null; var smsNotificationSendingGatewayName = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway", "Default"); if (smsNotificationSendingGatewayName.EqualsInvariant("Default")) { smsNotificationSendingGateway = new DefaultSmsNotificationSendingGateway(); } else if (smsNotificationSendingGatewayName.EqualsInvariant("Twilio")) { smsNotificationSendingGateway = new TwilioSmsNotificationSendingGateway(new TwilioSmsGatewayOptions { AccountId = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountId"), AccountPassword = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountPassword"), Sender = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:Sender"), }); } else if (smsNotificationSendingGatewayName.EqualsInvariant("ASPSMS")) { smsNotificationSendingGateway = new AspsmsSmsNotificationSendingGateway(new AspsmsSmsGatewayOptions { AccountId = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountId"), AccountPassword = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:AccountPassword"), Sender = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:Sender"), JsonApiUri = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:Notifications:SmsGateway:ASPSMS:JsonApiUri"), }); } if (smsNotificationSendingGateway != null) { container.RegisterInstance(smsNotificationSendingGateway); } #endregion #region Assets var blobConnectionString = BlobConnectionString.Parse(ConfigurationHelper.GetConnectionStringValue("AssetsConnectionString")); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var fileSystemBlobProvider = new FileSystemBlobProvider(NormalizePath(pathMapper, blobConnectionString.RootPath), blobConnectionString.PublicUrl); container.RegisterInstance <IBlobStorageProvider>(fileSystemBlobProvider); container.RegisterInstance <IBlobUrlResolver>(fileSystemBlobProvider); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var azureBlobProvider = new AzureBlobProvider(blobConnectionString.ConnectionString, blobConnectionString.CdnUrl); container.RegisterInstance <IBlobStorageProvider>(azureBlobProvider); container.RegisterInstance <IBlobUrlResolver>(azureBlobProvider); } container.RegisterType <IAssetEntryService, AssetEntryService>(new ContainerControlledLifetimeManager()); container.RegisterType <IAssetEntrySearchService, AssetEntryService>(new ContainerControlledLifetimeManager()); #endregion #region Modularity var modulesDataSources = ConfigurationHelper.SplitAppSettingsStringValue("VirtoCommerce:ModulesDataSources"); var externalModuleCatalog = new ExternalManifestModuleCatalog(moduleCatalog.Modules, modulesDataSources, container.Resolve <ILog>()); container.RegisterType <ModulesController>(new InjectionConstructor(externalModuleCatalog, new ModuleInstaller(modulesPath, externalModuleCatalog), notifier, container.Resolve <IUserNameResolver>(), settingsManager)); #endregion #region ChangeLogging var changeLogService = new ChangeLogService(platformRepositoryFactory); container.RegisterInstance <IChangeLogService>(changeLogService); #endregion #region Security container.RegisterInstance <IPermissionScopeService>(new PermissionScopeService()); container.RegisterType <IRoleManagementService, RoleManagementService>(new ContainerControlledLifetimeManager()); var apiAccountProvider = new ApiAccountProvider(platformRepositoryFactory, cacheManager); container.RegisterInstance <IApiAccountProvider>(apiAccountProvider); container.RegisterType <IClaimsIdentityProvider, ApplicationClaimsIdentityProvider>(new ContainerControlledLifetimeManager()); container.RegisterInstance(app.GetDataProtectionProvider()); container.RegisterType <SecurityDbContext>(new InjectionConstructor(connectionString)); container.RegisterType <IUserStore <ApplicationUser>, ApplicationUserStore>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <ApplicationUserManager>(); container.RegisterType <ApplicationSignInManager>(); var nonEditableUsers = ConfigurationHelper.GetAppSettingsValue("VirtoCommerce:NonEditableUsers", string.Empty); container.RegisterInstance <ISecurityOptions>(new SecurityOptions(nonEditableUsers)); container.RegisterType <ISecurityService, SecurityService>(); container.RegisterType <IPasswordCheckService, PasswordCheckService>(); #endregion #region ExportImport container.RegisterType <IPlatformExportImportManager, PlatformExportImportManager>(); #endregion #region Serialization container.RegisterType <IExpressionSerializer, XmlExpressionSerializer>(); #endregion #region Events var inProcessBus = new InProcessBus(); container.RegisterInstance <IHandlerRegistrar>(inProcessBus); container.RegisterInstance <IEventPublisher>(inProcessBus); inProcessBus.RegisterHandler <UserChangedEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); inProcessBus.RegisterHandler <UserPasswordChangedEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); inProcessBus.RegisterHandler <UserResetPasswordEvent>(async(message, token) => await container.Resolve <LogChangesUserChangedEventHandler>().Handle(message)); #endregion }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); services.AddResponseCaching(); services.Configure <StorefrontOptions>(Configuration.GetSection("VirtoCommerce")); //The IHttpContextAccessor service is not registered by default //https://github.com/aspnet/Hosting/issues/793 services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IWorkContextAccessor, WorkContextAccessor>(); services.AddSingleton <IUrlBuilder, UrlBuilder>(); services.AddSingleton <IStorefrontUrlBuilder, StorefrontUrlBuilder>(); services.AddSingleton <IStoreService, StoreService>(); services.AddSingleton <ICurrencyService, CurrencyService>(); services.AddSingleton <ISlugRouteService, SlugRouteService>(); services.AddSingleton <IMemberService, MemberService>(); services.AddSingleton <ICustomerOrderService, CustomerOrderService>(); services.AddSingleton <IQuoteService, QuoteService>(); services.AddSingleton <ISubscriptionService, SubscriptionService>(); services.AddSingleton <ICatalogService, CatalogService>(); services.AddSingleton <IInventoryService, InventoryService>(); services.AddSingleton <IPricingService, PricingService>(); services.AddSingleton <ITaxEvaluator, TaxEvaluator>(); services.AddSingleton <IPromotionEvaluator, PromotionEvaluator>(); services.AddSingleton <IDynamicContentEvaluator, DynamicContentEvaluator>(); services.AddSingleton <IMarketingService, MarketingService>(); services.AddSingleton <IStaticContentService, StaticContentService>(); services.AddSingleton <IMenuLinkListService, MenuLinkListServiceImpl>(); services.AddSingleton <IStaticContentItemFactory, StaticContentItemFactory>(); services.AddSingleton <IApiChangesWatcher, ApiChangesWatcher>(); services.AddSingleton <AssociationRecommendationsProvider>(); services.AddSingleton <CognitiveRecommendationsProvider>(); services.AddSingleton <IRecommendationProviderFactory, RecommendationProviderFactory>(provider => new RecommendationProviderFactory(provider.GetService <AssociationRecommendationsProvider>(), provider.GetService <CognitiveRecommendationsProvider>())); services.AddTransient <IQuoteRequestBuilder, QuoteRequestBuilder>(); services.AddSingleton <IBlobChangesWatcher, BlobChangesWatcher>(); services.AddTransient <ICartBuilder, CartBuilder>(); services.AddTransient <ICartService, CartService>(); services.AddTransient <AngularAntiforgeryCookieResultFilter>(); services.AddTransient <AnonymousUserForStoreAuthorizationFilter>(); //Register events framework dependencies services.AddSingleton(new InProcessBus()); services.AddSingleton <IEventPublisher>(provider => provider.GetService <InProcessBus>()); services.AddSingleton <IHandlerRegistrar>(provider => provider.GetService <InProcessBus>()); //Cache services.AddSingleton <IStorefrontMemoryCache, StorefrontMemoryCache>(); //Register platform API clients services.AddPlatformEndpoint(options => { Configuration.GetSection("VirtoCommerce:Endpoint").Bind(options); }); services.AddSingleton <ICountriesService, FileSystemCountriesService>(); services.Configure <FileSystemCountriesOptions>(options => { options.FilePath = HostingEnvironment.MapPath("~/countries.json"); }); var contentConnectionString = BlobConnectionString.Parse(Configuration.GetConnectionString("ContentConnectionString")); if (contentConnectionString.Provider.EqualsInvariant("AzureBlobStorage")) { var azureBlobOptions = new AzureBlobContentOptions(); Configuration.GetSection("VirtoCommerce:AzureBlobStorage").Bind(azureBlobOptions); services.AddAzureBlobContent(options => { options.Container = contentConnectionString.RootPath; options.ConnectionString = contentConnectionString.ConnectionString; options.PollForChanges = azureBlobOptions.PollForChanges; options.ChangesPollingInterval = azureBlobOptions.ChangesPollingInterval; }); } else { var fileSystemBlobOptions = new FileSystemBlobContentOptions(); Configuration.GetSection("VirtoCommerce:FileSystemBlobStorage").Bind(fileSystemBlobOptions); services.AddFileSystemBlobContent(options => { options.Path = HostingEnvironment.MapPath(contentConnectionString.RootPath); }); } //Identity overrides for use remote user storage services.AddScoped <IUserStore <User>, UserStoreStub>(); services.AddScoped <IRoleStore <Role>, UserStoreStub>(); services.AddScoped <UserManager <User>, CustomUserManager>(); services.AddScoped <SignInManager <User>, CustomSignInManager>(); //Resource-based authorization that requires API permissions for some operations services.AddSingleton <IAuthorizationHandler, CanImpersonateAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanReadContentItemAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, OnlyRegisteredUserAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, AnonymousUserForStoreAuthorizationHandler>(); // register the AuthorizationPolicyProvider which dynamically registers authorization policies for each permission defined in the platform services.AddSingleton <IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>(); //Storefront authorization handler for policy based on permissions services.AddSingleton <IAuthorizationHandler, PermissionAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanEditOrganizationResourceAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanAccessOrderAuthorizationHandler>(); services.AddAuthorization(options => { options.AddPolicy(CanImpersonateAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new CanImpersonateAuthorizationRequirement())); options.AddPolicy(CanReadContentItemAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanReadContentItemAuthorizeRequirement())); options.AddPolicy(CanEditOrganizationResourceAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanEditOrganizationResourceAuthorizeRequirement())); options.AddPolicy(OnlyRegisteredUserAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new OnlyRegisteredUserAuthorizationRequirement())); options.AddPolicy(AnonymousUserForStoreAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new AnonymousUserForStoreAuthorizationRequirement())); options.AddPolicy(CanAccessOrderAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new CanAccessOrderAuthorizationRequirement())); }); var auth = services.AddAuthentication(); var facebookSection = Configuration.GetSection("Authentication:Facebook"); if (facebookSection.GetChildren().Any()) { auth.AddFacebook(facebookOptions => { facebookSection.Bind(facebookOptions); }); } var googleSection = Configuration.GetSection("Authentication:Google"); if (googleSection.GetChildren().Any()) { auth.AddGoogle(googleOptions => { googleSection.Bind(googleOptions); }); } var githubSection = Configuration.GetSection("Authentication:Github"); if (githubSection.GetChildren().Any()) { auth.AddGitHub(GitHubAuthenticationOptions => { githubSection.Bind(GitHubAuthenticationOptions); }); } var stackexchangeSection = Configuration.GetSection("Authentication:Stackexchange"); if (stackexchangeSection.GetChildren().Any()) { auth.AddStackExchange(StackExchangeAuthenticationOptions => { stackexchangeSection.Bind(StackExchangeAuthenticationOptions); }); } //This line is required in order to use the old Identity V2 hashes to prevent rehashes passwords for platform users which login in the storefront //and it can lead to platform access denied for them. (TODO: Need to remove after platform migration to .NET Core) services.Configure <PasswordHasherOptions>(option => option.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2); services.Configure <IdentityOptions>(Configuration.GetSection("IdentityOptions")); services.Configure <CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, Configuration.GetSection("CookieAuthenticationOptions")); services.AddIdentity <User, Role>(options => { }).AddDefaultTokenProviders(); services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); // The Tempdata provider cookie is not essential. Make it essential // so Tempdata is functional when tracking is disabled. services.Configure <CookieTempDataProviderOptions>(options => { options.Cookie.IsEssential = true; }); services.Replace(ServiceDescriptor.Transient <CookieAuthenticationHandler, CustomCookieAuthenticationHandler>()); //Add Liquid view engine services.AddLiquidViewEngine(options => { Configuration.GetSection("VirtoCommerce:LiquidThemeEngine").Bind(options); }); var snapshotProvider = services.BuildServiceProvider(); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); services.AddMvc(options => { //Workaround to avoid 'Null effective policy causing exception' (on logout) //https://github.com/aspnet/Mvc/issues/7809 //TODO: Try to remove in ASP.NET Core 2.2 options.AllowCombiningAuthorizeFilters = false; // Thus we disable anonymous users based on "Store:AllowAnonymous" store option options.Filters.AddService <AnonymousUserForStoreAuthorizationFilter>(); options.CacheProfiles.Add("Default", new CacheProfile() { Duration = (int)TimeSpan.FromHours(1).TotalSeconds, VaryByHeader = "host" }); options.CacheProfiles.Add("None", new CacheProfile() { NoStore = true, Location = ResponseCacheLocation.None }); options.Filters.AddService(typeof(AngularAntiforgeryCookieResultFilter)); // To include only Api controllers to swagger document options.Conventions.Add(new ApiExplorerApiControllersConvention()); // Use the routing logic of ASP.NET Core 2.1 or earlier: options.EnableEndpointRouting = false; }).AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new CamelCaseNamingStrategy() }; options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include; options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; options.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore; options.SerializerSettings.Converters.Add(new CartTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new MoneyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new CurrencyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new OrderTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new RecommendationJsonConverter(snapshotProvider.GetService <IRecommendationProviderFactory>())); //Force serialize MutablePagedList type as array, instead of dictionary options.SerializerSettings.Converters.Add(new MutablePagedListAsArrayJsonConverter(options.SerializerSettings)); //Converter for providing back compatibility with old themes was used CustomerInfo type which has contained user and contact data in the single type. //May be removed when all themes will fixed to new User type with nested Contact property. options.SerializerSettings.Converters.Add(new UserBackwardCompatibilityJsonConverter(options.SerializerSettings)); }).AddViewOptions(options => { options.ViewEngines.Add(snapshotProvider.GetService <ILiquidViewEngine>()); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); //Register event handlers via reflection services.RegisterAssembliesEventHandlers(typeof(Startup)); services.AddApplicationInsightsTelemetry(); services.AddApplicationInsightsExtensions(Configuration); //https://github.com/aspnet/HttpAbstractions/issues/315 //Changing the default html encoding options, to not encode non-Latin characters services.Configure <WebEncoderOptions>(options => options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All)); services.Configure <HstsOptions>(options => { options.IncludeSubDomains = true; options.MaxAge = TimeSpan.FromDays(30); }); // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "Storefront REST API documentation", Version = "v1" }); c.DescribeAllEnumsAsStrings(); c.IgnoreObsoleteProperties(); c.IgnoreObsoleteActions(); // To include 401 response type to actions that requires Authorization c.OperationFilter <AuthResponsesOperationFilter>(); c.OperationFilter <OptionalParametersFilter>(); c.OperationFilter <FileResponseTypeFilter>(); // Workaround of problem with int default value for enum parameter: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/868 c.ParameterFilter <EnumDefaultValueParameterFilter>(); // To avoid errors with repeating type names c.CustomSchemaIds(type => (Attribute.GetCustomAttribute(type, typeof(SwaggerSchemaIdAttribute)) as SwaggerSchemaIdAttribute)?.Id ?? type.FriendlyId()); }); services.AddResponseCompression(); }
public void Configuration(IAppBuilder app) { var applicationInsightsKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); if (!string.IsNullOrEmpty(applicationInsightsKey)) { TelemetryConfiguration.Active.InstrumentationKey = applicationInsightsKey; } if (_managerAssembly != null) { AreaRegistration.RegisterAllAreas(); CallChildConfigure(app, _managerAssembly, "VirtoCommerce.Platform.Web.Startup", "Configuration", "~/areas/admin", "admin/"); } var appSettings = ConfigurationManager.AppSettings; UnityWebActivator.Start(); var container = UnityConfig.GetConfiguredContainer(); UnityServiceLocator locator = new UnityServiceLocator(container); ServiceLocator.SetLocatorProvider(() => locator); //Cure for System.Runtime.Caching.MemoryCache freezing //https://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol app.SanitizeThreadCulture(); // Caching configuration // Be cautious with SystemWebCacheHandle because it does not work in native threads (Hangfire jobs). var localCache = CacheFactory.FromConfiguration <object>("storefrontCache"); var localCacheManager = new LocalCacheManager(localCache); container.RegisterInstance <ILocalCacheManager>(localCacheManager); //Because CacheManagerOutputCacheProvider used diff cache manager instance need translate clear region by this way //https://github.com/MichaCo/CacheManager/issues/32 localCacheManager.OnClearRegion += (sender, region) => { try { CacheManagerOutputCacheProvider.Cache.ClearRegion(region.Region); } catch { } }; localCacheManager.OnClear += (sender, args) => { try { CacheManagerOutputCacheProvider.Cache.Clear(); } catch { } }; var distributedCache = CacheFactory.Build("distributedCache", settings => { var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var redisCacheEnabled = appSettings.GetValue("VirtoCommerce:Storefront:RedisCache:Enabled", false); var memoryHandlePart = settings .WithJsonSerializer(jsonSerializerSettings, jsonSerializerSettings) .WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memory") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(1)); if (redisCacheEnabled) { var redisCacheConnectionStringName = appSettings.GetValue("VirtoCommerce:Storefront:RedisCache:ConnectionStringName", "RedisCache"); var redisConnectionString = ConfigurationManager.ConnectionStrings[redisCacheConnectionStringName].ConnectionString; memoryHandlePart .And .WithRedisConfiguration("redis", redisConnectionString) .WithRetryTimeout(100) .WithMaxRetries(1000) .WithRedisBackplane("redis") .WithRedisCacheHandle("redis", true) .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(1)); } }); var distributedCacheManager = new DistributedCacheManager(distributedCache); container.RegisterInstance <IDistributedCacheManager>(distributedCacheManager); var logger = LogManager.GetLogger("default"); container.RegisterInstance <ILogger>(logger); // Create new work context for each request container.RegisterType <WorkContext, WorkContext>(new PerRequestLifetimeManager()); Func <WorkContext> workContextFactory = () => container.Resolve <WorkContext>(); container.RegisterInstance(workContextFactory); // Workaround for old storefront base URL: remove /api/ suffix since it is already included in every resource address in VirtoCommerce.Client library. var baseUrl = ConfigurationManager.ConnectionStrings["VirtoCommerceBaseUrl"].ConnectionString; if (baseUrl != null && baseUrl.EndsWith("/api/", StringComparison.OrdinalIgnoreCase)) { var apiPosition = baseUrl.LastIndexOf("/api/", StringComparison.OrdinalIgnoreCase); if (apiPosition >= 0) { baseUrl = baseUrl.Remove(apiPosition); } } var apiAppId = appSettings["vc-public-ApiAppId"]; var apiSecretKey = appSettings["vc-public-ApiSecretKey"]; container.RegisterInstance(new HmacCredentials(apiAppId, apiSecretKey)); container.RegisterType <VirtoCommerceApiRequestHandler>(new PerRequestLifetimeManager()); ServicePointManager.UseNagleAlgorithm = false; var compressionHandler = new System.Net.Http.HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; var baseUri = new Uri(baseUrl); container.RegisterType <ICartModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new CartModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ICatalogModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new CatalogModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IContentModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new ContentModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ICoreModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new CoreModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ICustomerModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new CustomerModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IInventoryModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new InventoryModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IMarketingModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new MarketingModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IOrdersModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new OrdersModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IPlatformModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new PlatformModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IPricingModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new PricingModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IQuoteModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new QuoteModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ISearchApiModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new SearchApiModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IStoreModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new StoreModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ISitemapsModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new SitemapsModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <ISubscriptionModuleApiClient>(new PerRequestLifetimeManager(), new InjectionFactory(c => new SubscriptionModuleApiClient(baseUri, c.Resolve <VirtoCommerceApiRequestHandler>(), compressionHandler))); container.RegisterType <IMarketingService, MarketingServiceImpl>(); container.RegisterType <IPromotionEvaluator, PromotionEvaluator>(); container.RegisterType <ITaxEvaluator, TaxEvaluator>(); container.RegisterType <IPricingService, PricingServiceImpl>(); container.RegisterType <ICustomerService, CustomerServiceImpl>(); container.RegisterType <IMenuLinkListService, MenuLinkListServiceImpl>(); container.RegisterType <ISeoRouteService, SeoRouteService>(); container.RegisterType <ICartBuilder, CartBuilder>(); container.RegisterType <IQuoteRequestBuilder, QuoteRequestBuilder>(); container.RegisterType <ICatalogSearchService, CatalogSearchServiceImpl>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(context => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <IStorefrontUrlBuilder, StorefrontUrlBuilder>(new PerRequestLifetimeManager()); //Register domain events container.RegisterType <IEventPublisher <OrderPlacedEvent>, EventPublisher <OrderPlacedEvent> >(); container.RegisterType <IEventPublisher <UserLoginEvent>, EventPublisher <UserLoginEvent> >(); container.RegisterType <IEventPublisher <QuoteRequestUpdatedEvent>, EventPublisher <QuoteRequestUpdatedEvent> >(); //Register event handlers (observers) container.RegisterType <IAsyncObserver <OrderPlacedEvent>, CustomerServiceImpl>("Invalidate customer cache when user placed new order"); container.RegisterType <IAsyncObserver <QuoteRequestUpdatedEvent>, CustomerServiceImpl>("Invalidate customer cache when quote request was updated"); container.RegisterType <IAsyncObserver <UserLoginEvent>, CartBuilder>("Merge anonymous cart with loggined user cart"); container.RegisterType <IAsyncObserver <UserLoginEvent>, QuoteRequestBuilder>("Merge anonymous quote request with loggined user quote"); var cmsContentConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["ContentConnectionString"].ConnectionString); var themesBasePath = cmsContentConnectionString.RootPath.TrimEnd('/') + "/" + "Themes"; var staticContentBasePath = cmsContentConnectionString.RootPath.TrimEnd('/') + "/" + "Pages"; //Use always file system provider for global theme var globalThemesBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath("~/App_Data/Themes/default")); IContentBlobProvider themesBlobProvider; IStaticContentBlobProvider staticContentBlobProvider; if ("AzureBlobStorage".Equals(cmsContentConnectionString.Provider, StringComparison.OrdinalIgnoreCase)) { themesBlobProvider = new AzureBlobContentProvider(cmsContentConnectionString.ConnectionString, themesBasePath, localCacheManager); staticContentBlobProvider = new AzureBlobContentProvider(cmsContentConnectionString.ConnectionString, staticContentBasePath, localCacheManager); } else { themesBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath(themesBasePath)); staticContentBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath(staticContentBasePath)); } container.RegisterInstance <IStaticContentBlobProvider>(staticContentBlobProvider); var shopifyLiquidEngine = new ShopifyLiquidThemeEngine(localCacheManager, workContextFactory, () => container.Resolve <IStorefrontUrlBuilder>(), themesBlobProvider, globalThemesBlobProvider, "~/themes/assets", "~/themes/global/assets"); container.RegisterInstance <ILiquidThemeEngine>(shopifyLiquidEngine); //Register liquid engine ViewEngines.Engines.Add(new DotLiquidThemedViewEngine(shopifyLiquidEngine)); // Shopify model binders convert Shopify form fields with bad names to VirtoCommerce model properties. container.RegisterType <IModelBinderProvider, ShopifyModelBinderProvider>("shopify"); //Static content service var staticContentService = new StaticContentServiceImpl(shopifyLiquidEngine, localCacheManager, workContextFactory, () => container.Resolve <IStorefrontUrlBuilder>(), StaticContentItemFactory.GetContentItemFromPath, staticContentBlobProvider); container.RegisterInstance <IStaticContentService>(staticContentService); //Register generate sitemap background job container.RegisterType <GenerateSitemapJob>(new InjectionFactory(c => new GenerateSitemapJob(themesBlobProvider, c.Resolve <ISitemapsModuleApiClient>(), c.Resolve <IStorefrontUrlBuilder>()))); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, workContextFactory, () => container.Resolve <CommonController>()); RouteConfig.RegisterRoutes(RouteTable.Routes, container.Resolve <ISeoRouteService>(), workContextFactory, () => container.Resolve <IStorefrontUrlBuilder>()); AuthConfig.ConfigureAuth(app, () => container.Resolve <IStorefrontUrlBuilder>()); container.Resolve <BundleConfig>().RegisterBundles(BundleTable.Bundles); //This special binders need because all these types not contains default ctor and Money with Currency properties ModelBinders.Binders.Add(typeof(Model.Cart.Shipment), new CartModelBinder <Model.Cart.Shipment>(workContextFactory)); ModelBinders.Binders.Add(typeof(Model.Cart.Payment), new CartModelBinder <Model.Cart.Payment>(workContextFactory)); ModelBinders.Binders.Add(typeof(Model.Order.PaymentIn), new OrderModelBinder <Model.Order.PaymentIn>(workContextFactory)); app.Use <WorkContextOwinMiddleware>(container); app.UseStageMarker(PipelineStage.PostAuthorize); app.Use <StorefrontUrlRewriterOwinMiddleware>(container); app.UseStageMarker(PipelineStage.PostAuthorize); }
private static void InitializePlatform(IAppBuilder app, IUnityContainer container, string connectionStringName, HangfireLauncher hangfireLauncher) { container.RegisterType <ICurrentUser, CurrentUser>(new HttpContextLifetimeManager()); container.RegisterType <IUserNameResolver, UserNameResolver>(); #region Setup database using (var db = new SecurityDbContext(connectionStringName)) { new IdentityDatabaseInitializer().InitializeDatabase(db); } using (var context = new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor())) { new PlatformDatabaseInitializer().InitializeDatabase(context); } hangfireLauncher.ConfigureDatabase(); #endregion Func <IPlatformRepository> platformRepositoryFactory = () => new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); container.RegisterType <IPlatformRepository>(new InjectionFactory(c => platformRepositoryFactory())); container.RegisterInstance(platformRepositoryFactory); var moduleCatalog = container.Resolve <IModuleCatalog>(); var manifestProvider = container.Resolve <IModuleManifestProvider>(); #region Caching var cacheManager = CacheFactory.Build("platformCache", settings => { //Should be aware to using Web cache cache handle because it not worked in native threads. (Hangfire jobs) settings .WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memCacheHandle") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromDays(1)); }); container.RegisterInstance(cacheManager); #endregion #region Settings var platformSettings = new[] { new ModuleManifest { Settings = new[] { new ModuleSettingsGroup { Name = "Platform|Notifications|SendGrid", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.UserName", ValueType = ModuleSetting.TypeString, Title = "SendGrid UserName", Description = "Your SendGrid account username" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.Secret", ValueType = ModuleSetting.TypeString, Title = "SendGrid Password", Description = "Your SendGrid account password" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SendingJob", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendingJob.TakeCount", ValueType = ModuleSetting.TypeInteger, Title = "Job Take Count", Description = "Take count for sending job" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SmtpClient", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Host", ValueType = ModuleSetting.TypeString, Title = "Smtp server host", Description = "Smtp server host" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Port", ValueType = ModuleSetting.TypeInteger, Title = "Smtp server port", Description = "Smtp server port" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Login", ValueType = ModuleSetting.TypeString, Title = "Smtp server login", Description = "Smtp server login" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Password", ValueType = ModuleSetting.TypeString, Title = "Smtp server password", Description = "Smtp server password" } } }, new ModuleSettingsGroup { Name = "Platform|Security", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Security.AccountTypes", ValueType = ModuleSetting.TypeString, Title = "Account types", Description = "Dictionary for possible account types", IsArray = true, ArrayValues = Enum.GetNames(typeof(AccountType)), DefaultValue = AccountType.Manager.ToString() } } } } } }; var settingsManager = new SettingsManager(manifestProvider, platformRepositoryFactory, cacheManager, platformSettings); container.RegisterInstance <ISettingsManager>(settingsManager); #endregion #region Dynamic Properties container.RegisterType <IDynamicPropertyService, DynamicPropertyService>(new ContainerControlledLifetimeManager()); #endregion #region Notifications var hubSignalR = GlobalHost.ConnectionManager.GetHubContext <ClientPushHub>(); var notifier = new InMemoryPushNotificationManager(hubSignalR); container.RegisterInstance <IPushNotificationManager>(notifier); var resolver = new LiquidNotificationTemplateResolver(); var notificationTemplateService = new NotificationTemplateServiceImpl(platformRepositoryFactory); var notificationManager = new NotificationManager(resolver, platformRepositoryFactory, notificationTemplateService); //var emailNotificationSendingGateway = new DefaultEmailNotificationSendingGateway(settingsManager); var emailNotificationSendingGateway = new DefaultSmtpEmailNotificationSendingGateway(settingsManager); var defaultSmsNotificationSendingGateway = new DefaultSmsNotificationSendingGateway(); container.RegisterInstance <INotificationTemplateService>(notificationTemplateService); container.RegisterInstance <INotificationManager>(notificationManager); container.RegisterInstance <INotificationTemplateResolver>(resolver); container.RegisterInstance <IEmailNotificationSendingGateway>(emailNotificationSendingGateway); container.RegisterInstance <ISmsNotificationSendingGateway>(defaultSmsNotificationSendingGateway); #endregion #region Assets var blobConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["AssetsConnectionString"].ConnectionString); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var fileSystemBlobProvider = new FileSystemBlobProvider(NormalizePath(blobConnectionString.RootPath), blobConnectionString.PublicUrl); container.RegisterInstance <IBlobStorageProvider>(fileSystemBlobProvider); container.RegisterInstance <IBlobUrlResolver>(fileSystemBlobProvider); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var azureBlobProvider = new AzureBlobProvider(blobConnectionString.ConnectionString); container.RegisterInstance <IBlobStorageProvider>(azureBlobProvider); container.RegisterInstance <IBlobUrlResolver>(azureBlobProvider); } #endregion #region Packaging var packagesPath = HostingEnvironment.MapPath(VirtualRoot + "/App_Data/InstalledPackages"); var packageService = new ZipPackageService(moduleCatalog, manifestProvider, packagesPath); container.RegisterInstance <IPackageService>(packageService); var uploadsPath = HostingEnvironment.MapPath(VirtualRoot + "/App_Data/Uploads"); container.RegisterType <ModulesController>(new InjectionConstructor(packageService, uploadsPath, notifier, container.Resolve <IUserNameResolver>())); #endregion #region ChangeLogging var changeLogService = new ChangeLogService(platformRepositoryFactory); container.RegisterInstance <IChangeLogService>(changeLogService); #endregion #region Security container.RegisterInstance <IPermissionScopeService>(new PermissionScopeService()); container.RegisterType <IRoleManagementService, RoleManagementService>(new ContainerControlledLifetimeManager()); var apiAccountProvider = new ApiAccountProvider(platformRepositoryFactory, cacheManager); container.RegisterInstance <IApiAccountProvider>(apiAccountProvider); container.RegisterType <IClaimsIdentityProvider, ApplicationClaimsIdentityProvider>(new ContainerControlledLifetimeManager()); container.RegisterInstance(app.GetDataProtectionProvider()); container.RegisterType <SecurityDbContext>(new InjectionConstructor(connectionStringName)); container.RegisterType <IUserStore <ApplicationUser>, ApplicationUserStore>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <ApplicationUserManager>(); container.RegisterType <ApplicationSignInManager>(); var nonEditableUsers = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:NonEditableUsers", string.Empty); container.RegisterInstance <ISecurityOptions>(new SecurityOptions(nonEditableUsers)); container.RegisterType <ISecurityService, SecurityService>(); #endregion #region ExportImport container.RegisterType <IPlatformExportImportManager, PlatformExportImportManager>(); #endregion }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); services.AddResponseCaching(); services.Configure <StorefrontOptions>(Configuration.GetSection("VirtoCommerce")); //The IHttpContextAccessor service is not registered by default //https://github.com/aspnet/Hosting/issues/793 services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IWorkContextAccessor, WorkContextAccessor>(); services.AddSingleton <IUrlBuilder, UrlBuilder>(); services.AddSingleton <IStorefrontUrlBuilder, StorefrontUrlBuilder>(); services.AddSingleton <IStoreService, StoreService>(); services.AddSingleton <ICurrencyService, CurrencyService>(); services.AddSingleton <ISlugRouteService, SlugRouteService>(); services.AddSingleton <IMemberService, MemberService>(); services.AddSingleton <ICustomerOrderService, CustomerOrderService>(); services.AddSingleton <IQuoteService, QuoteService>(); services.AddSingleton <ISubscriptionService, SubscriptionService>(); services.AddSingleton <ICatalogService, CatalogService>(); services.AddSingleton <IInventoryService, InventoryService>(); services.AddSingleton <IPricingService, PricingService>(); services.AddSingleton <ITaxEvaluator, TaxEvaluator>(); services.AddSingleton <IPromotionEvaluator, PromotionEvaluator>(); services.AddSingleton <IMarketingService, MarketingService>(); services.AddSingleton <IStaticContentService, StaticContentService>(); services.AddSingleton <IMenuLinkListService, MenuLinkListServiceImpl>(); services.AddSingleton <IStaticContentItemFactory, StaticContentItemFactory>(); services.AddSingleton <IApiChangesWatcher, ApiChangesWatcher>(); services.AddSingleton <AssociationRecommendationsProvider>(); services.AddSingleton <CognitiveRecommendationsProvider>(); services.AddSingleton <IRecommendationProviderFactory, RecommendationProviderFactory>(provider => new RecommendationProviderFactory(provider.GetService <AssociationRecommendationsProvider>(), provider.GetService <CognitiveRecommendationsProvider>())); services.AddTransient <IQuoteRequestBuilder, QuoteRequestBuilder>(); services.AddSingleton <IBlobChangesWatcher, BlobChangesWatcher>(); services.AddTransient <ICartBuilder, CartBuilder>(); services.AddTransient <ICartService, CartService>(); //Register events framework dependencies services.AddSingleton(new InProcessBus()); services.AddSingleton <IEventPublisher>(provider => provider.GetService <InProcessBus>()); services.AddSingleton <IHandlerRegistrar>(provider => provider.GetService <InProcessBus>()); //Register platform API clients services.AddPlatformEndpoint(options => { Configuration.GetSection("VirtoCommerce:Endpoint").Bind(options); }); services.AddSingleton <ICountriesService, FileSystemCountriesService>(); services.Configure <FileSystemCountriesOptions>(options => { options.FilePath = HostingEnvironment.MapPath("~/countries.json"); }); var contentConnectionString = BlobConnectionString.Parse(Configuration.GetConnectionString("ContentConnectionString")); if (contentConnectionString.Provider.EqualsInvariant("AzureBlobStorage")) { var azureBlobOptions = new AzureBlobContentOptions(); Configuration.GetSection("VirtoCommerce:AzureBlobStorage").Bind(azureBlobOptions); services.AddAzureBlobContent(options => { options.Container = contentConnectionString.RootPath; options.ConnectionString = contentConnectionString.ConnectionString; options.PollForChanges = azureBlobOptions.PollForChanges; options.ChangesPoolingInterval = azureBlobOptions.ChangesPoolingInterval; }); } else { services.AddFileSystemBlobContent(options => { options.Path = HostingEnvironment.MapPath(contentConnectionString.RootPath); }); } //Identity overrides for use remote user storage services.AddSingleton <IUserStore <User>, UserStoreStub>(); services.AddSingleton <IUserClaimsPrincipalFactory <User>, UserPrincipalFactory>(); services.AddScoped <UserManager <User>, CustomUserManager>(); //Resource-based authorization that requires API permissions for some operations services.AddSingleton <IAuthorizationHandler, CanImpersonateAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanReadContentItemAuthorizationHandler>(); // register the AuthorizationPolicyProvider which dynamically registers authorization policies for each permission defined in the platform services.AddSingleton <IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>(); //Storefront authorization handler for policy based on permissions services.AddSingleton <IAuthorizationHandler, PermissionAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanEditOrganizationResourceAuthorizationHandler>(); services.AddAuthorization(options => { options.AddPolicy(CanImpersonateAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new CanImpersonateAuthorizationRequirement())); options.AddPolicy(CanReadContentItemAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanReadContentItemAuthorizeRequirement())); options.AddPolicy(CanEditOrganizationResourceAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanEditOrganizationResourceAuthorizeRequirement())); }); var auth = services.AddAuthentication(); var facebookSection = Configuration.GetSection("Authentication:Facebook"); if (facebookSection.GetChildren().Any()) { auth.AddFacebook(facebookOptions => { facebookSection.Bind(facebookOptions); }); } var googleSection = Configuration.GetSection("Authentication:Google"); if (googleSection.GetChildren().Any()) { auth.AddGoogle(googleOptions => { googleSection.Bind(googleOptions); }); } var githubSection = Configuration.GetSection("Authentication:Github"); if (githubSection.GetChildren().Any()) { auth.AddGitHub(GitHubAuthenticationOptions => { githubSection.Bind(GitHubAuthenticationOptions); }); } var stackexchangeSection = Configuration.GetSection("Authentication:Stackexchange"); if (stackexchangeSection.GetChildren().Any()) { auth.AddStackExchange(StackExchangeAuthenticationOptions => { stackexchangeSection.Bind(StackExchangeAuthenticationOptions); }); } //This line is required in order to use the old Identity V2 hashes to prevent rehashes passwords for platform users which login in the storefront //and it can lead to platform access denied for them. (TODO: Need to remove after platform migration to .NET Core) services.Configure <PasswordHasherOptions>(option => option.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2); services.AddIdentity <User, IdentityRole>(options => { options.Password.RequiredLength = 8; options.Password.RequireLowercase = true; options.Password.RequireUppercase = true; options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.AllowedForNewUsers = true; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15); }).AddDefaultTokenProviders(); services.ConfigureApplicationCookie(options => { // Cookie settings options.Cookie.HttpOnly = true; options.Cookie.Expiration = TimeSpan.FromDays(30); options.LoginPath = "/Account/Login"; // If the LoginPath is not set here, ASP.NET Core will default to /Account/Login options.LogoutPath = "/Account/Logout"; // If the LogoutPath is not set here, ASP.NET Core will default to /Account/Logout options.AccessDeniedPath = "/error/AccessDenied"; options.SlidingExpiration = true; }); //Add Liquid view engine services.AddLiquidViewEngine(options => { Configuration.GetSection("VirtoCommerce:LiquidThemeEngine").Bind(options); }); var snapshotProvider = services.BuildServiceProvider(); services.AddMvc(options => { options.CacheProfiles.Add("Default", new CacheProfile() { Duration = (int)TimeSpan.FromHours(1).TotalSeconds, VaryByHeader = "host" }); }).AddJsonOptions(options => { options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include; options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; options.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore; options.SerializerSettings.Converters.Add(new CartTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new MoneyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new CurrencyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new OrderTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new RecommendationJsonConverter(snapshotProvider.GetService <IRecommendationProviderFactory>())); //Converter for providing back compatibility with old themes was used CustomerInfo type which has contained user and contact data in the single type. //May be removed when all themes will fixed to new User type with nested Contact property. options.SerializerSettings.Converters.Add(new UserBackwardCompatibilityJsonConverter(options.SerializerSettings)); }).AddViewOptions(options => { options.ViewEngines.Add(snapshotProvider.GetService <ILiquidViewEngine>()); }); //Register event handlers via reflection services.RegisterAssembliesEventHandlers(typeof(Startup)); services.AddApplicationInsightsTelemetry(); }
private static void InitializePlatform(IAppBuilder app, IUnityContainer container, string connectionStringName, HangfireLauncher hangfireLauncher, string modulesPath) { container.RegisterType <ICurrentUser, CurrentUser>(new HttpContextLifetimeManager()); container.RegisterType <IUserNameResolver, UserNameResolver>(); #region Setup database using (var db = new SecurityDbContext(connectionStringName)) { new IdentityDatabaseInitializer().InitializeDatabase(db); } using (var context = new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor())) { new PlatformDatabaseInitializer().InitializeDatabase(context); } hangfireLauncher.ConfigureDatabase(); #endregion Func <IPlatformRepository> platformRepositoryFactory = () => new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); container.RegisterType <IPlatformRepository>(new InjectionFactory(c => platformRepositoryFactory())); container.RegisterInstance(platformRepositoryFactory); var moduleCatalog = container.Resolve <IModuleCatalog>(); #region Caching ICacheManager <object> cacheManager = null; //Try to load cache configuration from web.config first if (ConfigurationManager.GetSection(CacheManagerSection.DefaultSectionName) != null) { cacheManager = CacheFactory.FromConfiguration <object>("platformCache"); } else { cacheManager = CacheFactory.Build("platformCache", settings => { //Should be aware to using Web cache cache handle because it not worked in native threads. (Hangfire jobs) settings.WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memCacheHandle") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromDays(1)); }); } container.RegisterInstance(cacheManager); #endregion #region Settings var platformModuleManifest = new ModuleManifest { Id = "VirtoCommerce.Platform", Version = PlatformVersion.CurrentVersion.ToString(), PlatformVersion = PlatformVersion.CurrentVersion.ToString(), Settings = new[] { new ModuleSettingsGroup { Name = "Platform|Notifications|SendGrid", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.ApiKey", ValueType = ModuleSetting.TypeString, Title = "SendGrid API key", Description = "Your SendGrid API key" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SendingJob", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendingJob.TakeCount", ValueType = ModuleSetting.TypeInteger, Title = "Job Take Count", Description = "Take count for sending job" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SmtpClient", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Host", ValueType = ModuleSetting.TypeString, Title = "Smtp server host", Description = "Smtp server host" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Port", ValueType = ModuleSetting.TypeInteger, Title = "Smtp server port", Description = "Smtp server port" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Login", ValueType = ModuleSetting.TypeString, Title = "Smtp server login", Description = "Smtp server login" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Password", ValueType = ModuleSetting.TypeSecureString, Title = "Smtp server password", Description = "Smtp server password" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.UseSsl", ValueType = ModuleSetting.TypeBoolean, Title = "Use SSL", Description = "Use secure connection" }, } }, new ModuleSettingsGroup { Name = "Platform|Security", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Security.AccountTypes", ValueType = ModuleSetting.TypeString, Title = "Account types", Description = "Dictionary for possible account types", IsArray = true, ArrayValues = Enum.GetNames(typeof(AccountType)), DefaultValue = AccountType.Manager.ToString() } } }, new ModuleSettingsGroup { Name = "Platform|User Profile", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.MainMenu.State", ValueType = ModuleSetting.TypeJson, Title = "Persisted state of main menu" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Language", ValueType = ModuleSetting.TypeString, Title = "Language", Description = "Default language (two letter code from ISO 639-1)", DefaultValue = "en" } } }, new ModuleSettingsGroup { Name = "Platform|User Interface", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Customization", ValueType = ModuleSetting.TypeJson, Title = "Customization", Description = "JSON contains personalization settings of manager UI", DefaultValue = "{\n" + " \"title\": \"Virto Commerce\",\n" + " \"logo\": \"Content/themes/main/images/logo.png\",\n" + " \"contrast_logo\": \"Content/themes/main/images/contrast-logo.png\"\n" + "}" } } } } }; var settingsManager = new SettingsManager(moduleCatalog, platformRepositoryFactory, cacheManager, new[] { new ManifestModuleInfo(platformModuleManifest) }); container.RegisterInstance <ISettingsManager>(settingsManager); #endregion #region Dynamic Properties container.RegisterType <IDynamicPropertyService, DynamicPropertyService>(new ContainerControlledLifetimeManager()); #endregion #region Notifications var hubSignalR = GlobalHost.ConnectionManager.GetHubContext <ClientPushHub>(); var notifier = new InMemoryPushNotificationManager(hubSignalR); container.RegisterInstance <IPushNotificationManager>(notifier); var resolver = new LiquidNotificationTemplateResolver(); container.RegisterInstance <INotificationTemplateResolver>(resolver); var notificationTemplateService = new NotificationTemplateServiceImpl(platformRepositoryFactory); container.RegisterInstance <INotificationTemplateService>(notificationTemplateService); var notificationManager = new NotificationManager(resolver, platformRepositoryFactory, notificationTemplateService); container.RegisterInstance <INotificationManager>(notificationManager); IEmailNotificationSendingGateway emailNotificationSendingGateway = null; var emailNotificationSendingGatewayName = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:Notifications:Gateway", "Default"); if (string.Equals(emailNotificationSendingGatewayName, "Default", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new DefaultSmtpEmailNotificationSendingGateway(settingsManager); } else if (string.Equals(emailNotificationSendingGatewayName, "SendGrid", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new SendGridEmailNotificationSendingGateway(settingsManager); } if (emailNotificationSendingGateway != null) { container.RegisterInstance(emailNotificationSendingGateway); } var defaultSmsNotificationSendingGateway = new DefaultSmsNotificationSendingGateway(); container.RegisterInstance <ISmsNotificationSendingGateway>(defaultSmsNotificationSendingGateway); #endregion #region Assets var blobConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["AssetsConnectionString"].ConnectionString); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var fileSystemBlobProvider = new FileSystemBlobProvider(NormalizePath(blobConnectionString.RootPath), blobConnectionString.PublicUrl); container.RegisterInstance <IBlobStorageProvider>(fileSystemBlobProvider); container.RegisterInstance <IBlobUrlResolver>(fileSystemBlobProvider); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var azureBlobProvider = new AzureBlobProvider(blobConnectionString.ConnectionString); container.RegisterInstance <IBlobStorageProvider>(azureBlobProvider); container.RegisterInstance <IBlobUrlResolver>(azureBlobProvider); } #endregion #region Modularity var modulesDataSources = ConfigurationManager.AppSettings.SplitStringValue("VirtoCommerce:ModulesDataSources"); var externalModuleCatalog = new ExternalManifestModuleCatalog(moduleCatalog.Modules, modulesDataSources, container.Resolve <ILog>()); container.RegisterType <ModulesController>(new InjectionConstructor(externalModuleCatalog, new ModuleInstaller(modulesPath, externalModuleCatalog), notifier, container.Resolve <IUserNameResolver>(), settingsManager)); #endregion #region ChangeLogging var changeLogService = new ChangeLogService(platformRepositoryFactory); container.RegisterInstance <IChangeLogService>(changeLogService); #endregion #region Security container.RegisterInstance <IPermissionScopeService>(new PermissionScopeService()); container.RegisterType <IRoleManagementService, RoleManagementService>(new ContainerControlledLifetimeManager()); var apiAccountProvider = new ApiAccountProvider(platformRepositoryFactory, cacheManager); container.RegisterInstance <IApiAccountProvider>(apiAccountProvider); container.RegisterType <IClaimsIdentityProvider, ApplicationClaimsIdentityProvider>(new ContainerControlledLifetimeManager()); container.RegisterInstance(app.GetDataProtectionProvider()); container.RegisterType <SecurityDbContext>(new InjectionConstructor(connectionStringName)); container.RegisterType <IUserStore <ApplicationUser>, ApplicationUserStore>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <ApplicationUserManager>(); container.RegisterType <ApplicationSignInManager>(); var nonEditableUsers = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:NonEditableUsers", string.Empty); container.RegisterInstance <ISecurityOptions>(new SecurityOptions(nonEditableUsers)); container.RegisterType <ISecurityService, SecurityService>(); #endregion #region ExportImport container.RegisterType <IPlatformExportImportManager, PlatformExportImportManager>(); #endregion #region Serialization container.RegisterType <IExpressionSerializer, XmlExpressionSerializer>(); #endregion }
public void Configuration(IAppBuilder app) { if (_managerAssembly != null) { AreaRegistration.RegisterAllAreas(); CallChildConfigure(app, _managerAssembly, "VirtoCommerce.Platform.Web.Startup", "Configuration", "~/areas/admin", "admin/"); } UnityWebActivator.Start(); var container = UnityConfig.GetConfiguredContainer(); // Caching configuration // Be cautious with SystemWebCacheHandle because it does not work in native threads (Hangfire jobs). var localCache = CacheFactory.FromConfiguration <object>("storefrontCache"); var localCacheManager = new LocalCacheManager(localCache); container.RegisterInstance <ILocalCacheManager>(localCacheManager); //Because CacheManagerOutputCacheProvider used diff cache manager instance need translate clear region by this way //https://github.com/MichaCo/CacheManager/issues/32 localCacheManager.OnClearRegion += (sender, region) => { try { CacheManagerOutputCacheProvider.Cache.ClearRegion(region.Region); } catch { } }; localCacheManager.OnClear += (sender, args) => { try { CacheManagerOutputCacheProvider.Cache.Clear(); } catch { } }; var distributedCache = CacheFactory.Build("distributedCache", settings => { var jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; var redisCacheEnabled = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:Storefront:RedisCache:Enabled", false); var memoryHandlePart = settings .WithJsonSerializer(jsonSerializerSettings, jsonSerializerSettings) .WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memory") .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(1)); if (redisCacheEnabled) { var redisCacheConnectionStringName = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:Storefront:RedisCache:ConnectionStringName", "RedisCache"); var redisConnectionString = ConfigurationManager.ConnectionStrings[redisCacheConnectionStringName].ConnectionString; memoryHandlePart .And .WithRedisConfiguration("redis", redisConnectionString) .WithRetryTimeout(100) .WithMaxRetries(1000) .WithRedisBackplane("redis") .WithRedisCacheHandle("redis", true) .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromHours(1)); } }); var distributedCacheManager = new DistributedCacheManager(distributedCache); container.RegisterInstance <IDistributedCacheManager>(distributedCacheManager); var logger = LogManager.GetLogger("default"); container.RegisterInstance <ILogger>(logger); // Create new work context for each request container.RegisterType <WorkContext, WorkContext>(new PerRequestLifetimeManager()); Func <WorkContext> workContextFactory = () => container.Resolve <WorkContext>(); container.RegisterInstance(workContextFactory); // Workaround for old storefront base URL: remove /api/ suffix since it is already included in every resource address in VirtoCommerce.Client library. var baseUrl = ConfigurationManager.ConnectionStrings["VirtoCommerceBaseUrl"].ConnectionString; if (baseUrl != null && baseUrl.EndsWith("/api/", StringComparison.OrdinalIgnoreCase)) { var apiPosition = baseUrl.LastIndexOf("/api/", StringComparison.OrdinalIgnoreCase); if (apiPosition >= 0) { baseUrl = baseUrl.Remove(apiPosition); } } var apiAppId = ConfigurationManager.AppSettings["vc-public-ApiAppId"]; var apiSecretKey = ConfigurationManager.AppSettings["vc-public-ApiSecretKey"]; var hmacHandler = new HmacRestRequestHandler(apiAppId, apiSecretKey); var currentUserHandler = new CurrentUserRestRequestHandler(workContextFactory); container.RegisterInstance <IVirtoCommerceCartApi>(new VirtoCommerceCartApi(new CartModule.Client.Client.ApiClient(baseUrl, new CartModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceCatalogApi>(new VirtoCommerceCatalogApi(new CatalogModule.Client.Client.ApiClient(baseUrl, new CatalogModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceContentApi>(new VirtoCommerceContentApi(new ContentModule.Client.Client.ApiClient(baseUrl, new ContentModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceCoreApi>(new VirtoCommerceCoreApi(new CoreModule.Client.Client.ApiClient(baseUrl, new CoreModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceCustomerApi>(new VirtoCommerceCustomerApi(new CustomerModule.Client.Client.ApiClient(baseUrl, new CustomerModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceInventoryApi>(new VirtoCommerceInventoryApi(new InventoryModule.Client.Client.ApiClient(baseUrl, new InventoryModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceMarketingApi>(new VirtoCommerceMarketingApi(new MarketingModule.Client.Client.ApiClient(baseUrl, new MarketingModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommercePlatformApi>(new VirtoCommercePlatformApi(new Platform.Client.Client.ApiClient(baseUrl, new Platform.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommercePricingApi>(new VirtoCommercePricingApi(new PricingModule.Client.Client.ApiClient(baseUrl, new PricingModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceOrdersApi>(new VirtoCommerceOrdersApi(new OrderModule.Client.Client.ApiClient(baseUrl, new OrderModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceQuoteApi>(new VirtoCommerceQuoteApi(new QuoteModule.Client.Client.ApiClient(baseUrl, new QuoteModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceSearchApi>(new VirtoCommerceSearchApi(new SearchModule.Client.Client.ApiClient(baseUrl, new SearchModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterInstance <IVirtoCommerceStoreApi>(new VirtoCommerceStoreApi(new StoreModule.Client.Client.ApiClient(baseUrl, new StoreModule.Client.Client.Configuration(), hmacHandler.PrepareRequest, currentUserHandler.PrepareRequest))); container.RegisterType <IMarketingService, MarketingServiceImpl>(); container.RegisterType <IPromotionEvaluator, PromotionEvaluator>(); container.RegisterType <ICartValidator, CartValidator>(); container.RegisterType <IPricingService, PricingServiceImpl>(); container.RegisterType <ICustomerService, CustomerServiceImpl>(); container.RegisterType <IMenuLinkListService, MenuLinkListServiceImpl>(); container.RegisterType <ICartBuilder, CartBuilder>(); container.RegisterType <IQuoteRequestBuilder, QuoteRequestBuilder>(); container.RegisterType <ICatalogSearchService, CatalogSearchServiceImpl>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(context => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <IStorefrontUrlBuilder, StorefrontUrlBuilder>(new PerRequestLifetimeManager()); //Register domain events container.RegisterType <IEventPublisher <OrderPlacedEvent>, EventPublisher <OrderPlacedEvent> >(); container.RegisterType <IEventPublisher <UserLoginEvent>, EventPublisher <UserLoginEvent> >(); container.RegisterType <IEventPublisher <QuoteRequestUpdatedEvent>, EventPublisher <QuoteRequestUpdatedEvent> >(); //Register event handlers (observers) container.RegisterType <IAsyncObserver <OrderPlacedEvent>, CustomerServiceImpl>("Invalidate customer cache when user placed new order"); container.RegisterType <IAsyncObserver <QuoteRequestUpdatedEvent>, CustomerServiceImpl>("Invalidate customer cache when quote request was updated"); container.RegisterType <IAsyncObserver <UserLoginEvent>, CartBuilder>("Merge anonymous cart with loggined user cart"); container.RegisterType <IAsyncObserver <UserLoginEvent>, QuoteRequestBuilder>("Merge anonymous quote request with loggined user quote"); var cmsContentConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["ContentConnectionString"].ConnectionString); var themesBasePath = cmsContentConnectionString.RootPath.TrimEnd('/') + "/" + "Themes"; var staticContentBasePath = cmsContentConnectionString.RootPath.TrimEnd('/') + "/" + "Pages"; //Use always file system provider for global theme var globalThemesBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath("~/App_Data/Themes/default")); IContentBlobProvider themesBlobProvider; IStaticContentBlobProvider staticContentBlobProvider; if ("AzureBlobStorage".Equals(cmsContentConnectionString.Provider, StringComparison.OrdinalIgnoreCase)) { themesBlobProvider = new AzureBlobContentProvider(cmsContentConnectionString.ConnectionString, themesBasePath, localCacheManager); staticContentBlobProvider = new AzureBlobContentProvider(cmsContentConnectionString.ConnectionString, staticContentBasePath, localCacheManager); } else { themesBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath(themesBasePath)); staticContentBlobProvider = new FileSystemContentBlobProvider(ResolveLocalPath(staticContentBasePath)); } container.RegisterInstance <IStaticContentBlobProvider>(staticContentBlobProvider); var shopifyLiquidEngine = new ShopifyLiquidThemeEngine(localCacheManager, workContextFactory, () => container.Resolve <IStorefrontUrlBuilder>(), themesBlobProvider, globalThemesBlobProvider, "~/themes/assets", "~/themes/global/assets"); container.RegisterInstance <ILiquidThemeEngine>(shopifyLiquidEngine); //Register liquid engine ViewEngines.Engines.Add(new DotLiquidThemedViewEngine(shopifyLiquidEngine)); // Shopify model binders convert Shopify form fields with bad names to VirtoCommerce model properties. container.RegisterType <IModelBinderProvider, ShopifyModelBinderProvider>("shopify"); //Static content service var staticContentService = new StaticContentServiceImpl(shopifyLiquidEngine, localCacheManager, workContextFactory, () => container.Resolve <IStorefrontUrlBuilder>(), StaticContentItemFactory.GetContentItemFromPath, staticContentBlobProvider); container.RegisterInstance <IStaticContentService>(staticContentService); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, workContextFactory, () => container.Resolve <CommonController>()); RouteConfig.RegisterRoutes(RouteTable.Routes, workContextFactory, container.Resolve <IVirtoCommerceCoreApi>(), container.Resolve <IStaticContentService>(), localCacheManager); AuthConfig.ConfigureAuth(app, () => container.Resolve <IStorefrontUrlBuilder>()); app.Use <WorkContextOwinMiddleware>(container); app.UseStageMarker(PipelineStage.PostAuthorize); app.Use <StorefrontUrlRewriterOwinMiddleware>(container); app.UseStageMarker(PipelineStage.PostAuthorize); }
private static void InitializePlatform(IAppBuilder app, IUnityContainer container, string connectionStringName, HangfireLauncher hangfireLauncher, string modulesPath) { container.RegisterType <ICurrentUser, CurrentUser>(new HttpContextLifetimeManager()); container.RegisterType <IUserNameResolver, UserNameResolver>(); #region Setup database using (var db = new SecurityDbContext(connectionStringName)) { new IdentityDatabaseInitializer().InitializeDatabase(db); } using (var context = new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor())) { new PlatformDatabaseInitializer().InitializeDatabase(context); } hangfireLauncher.ConfigureDatabase(); #endregion Func <IPlatformRepository> platformRepositoryFactory = () => new PlatformRepository(connectionStringName, container.Resolve <AuditableInterceptor>(), new EntityPrimaryKeyGeneratorInterceptor()); container.RegisterType <IPlatformRepository>(new InjectionFactory(c => platformRepositoryFactory())); container.RegisterInstance(platformRepositoryFactory); var moduleCatalog = container.Resolve <IModuleCatalog>(); #region Caching //Cure for System.Runtime.Caching.MemoryCache freezing //https://www.zpqrtbnk.net/posts/appdomains-threads-cultureinfos-and-paracetamol app.SanitizeThreadCulture(); ICacheManager <object> cacheManager = null; //Try to load cache configuration from web.config first //Should be aware to using Web cache cache handle because it not worked in native threads. (Hangfire jobs) var cacheManagerSection = ConfigurationManager.GetSection(CacheManagerSection.DefaultSectionName) as CacheManagerSection; if (cacheManagerSection != null && cacheManagerSection.CacheManagers.Any(p => p.Name.EqualsInvariant("platformCache"))) { var configuration = ConfigurationBuilder.LoadConfiguration("platformCache") as CacheManagerConfiguration; if (configuration != null) { configuration.LoggerFactoryType = typeof(CacheManagerLoggerFactory); configuration.LoggerFactoryTypeArguments = new[] { container.Resolve <ILog>() }; cacheManager = CacheFactory.FromConfiguration <object>(configuration); } } if (cacheManager == null) { cacheManager = CacheFactory.Build("platformCache", settings => { settings.WithUpdateMode(CacheUpdateMode.Up) .WithSystemRuntimeCacheHandle("memCacheHandle") .WithExpiration(ExpirationMode.Sliding, TimeSpan.FromMinutes(5)); }); } container.RegisterInstance(cacheManager); #endregion #region Settings var platformModuleManifest = new ModuleManifest { Id = "VirtoCommerce.Platform", Version = PlatformVersion.CurrentVersion.ToString(), PlatformVersion = PlatformVersion.CurrentVersion.ToString(), Settings = new[] { new ModuleSettingsGroup { Name = "Platform|Notifications|SendGrid", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendGrid.ApiKey", ValueType = ModuleSetting.TypeSecureString, Title = "SendGrid API key", Description = "Your SendGrid API key" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SendingJob", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SendingJob.TakeCount", ValueType = ModuleSetting.TypeInteger, Title = "Job Take Count", Description = "Take count for sending job" } } }, new ModuleSettingsGroup { Name = "Platform|Notifications|SmtpClient", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Host", ValueType = ModuleSetting.TypeString, Title = "Smtp server host", Description = "Smtp server host" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Port", ValueType = ModuleSetting.TypeInteger, Title = "Smtp server port", Description = "Smtp server port" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Login", ValueType = ModuleSetting.TypeString, Title = "Smtp server login", Description = "Smtp server login" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.Password", ValueType = ModuleSetting.TypeSecureString, Title = "Smtp server password", Description = "Smtp server password" }, new ModuleSetting { Name = "VirtoCommerce.Platform.Notifications.SmptClient.UseSsl", ValueType = ModuleSetting.TypeBoolean, Title = "Use SSL", Description = "Use secure connection" }, } }, new ModuleSettingsGroup { Name = "Platform|Security", Settings = new [] { new ModuleSetting { Name = "VirtoCommerce.Platform.Security.AccountTypes", ValueType = ModuleSetting.TypeString, Title = "Account types", Description = "Dictionary for possible account types", IsArray = true, ArrayValues = Enum.GetNames(typeof(AccountType)), DefaultValue = AccountType.Manager.ToString() } } }, new ModuleSettingsGroup { Name = "Platform|User Profile", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.MainMenu.State", ValueType = ModuleSetting.TypeJson, Title = "Persisted state of main menu" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Language", ValueType = ModuleSetting.TypeString, Title = "Language", Description = "Default language (two letter code from ISO 639-1, case-insensitive). Example: en, de", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.RegionalFormat", ValueType = ModuleSetting.TypeString, Title = "Regional format", Description = "Default regional format (CLDR locale code, with dash or underscore as delemiter, case-insensitive). Example: en, en_US, sr_Cyrl, sr_Cyrl_RS", DefaultValue = "en" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.TimeZone", ValueType = ModuleSetting.TypeString, Title = "Time zone", Description = "Default time zone (IANA time zone name [tz database], exactly as in database, case-sensitive). Examples: America/New_York, Europe/Moscow" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.UseTimeAgo", ValueType = ModuleSetting.TypeBoolean, Title = "Use time ago format when is possible", Description = "When set to true (by default), system will display date in format like 'a few seconds ago' when possible", DefaultValue = true.ToString() }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThreshold", ValueType = ModuleSetting.TypeInteger, Title = "Full date threshold", Description = "Number of units after time ago format will be switched to full date format" }, new ModuleSetting { Name = "VirtoCommerce.Platform.UI.FullDateThresholdUnit", ValueType = ModuleSetting.TypeString, Title = "Full date threshold unit", Description = "Unit of full date threshold", DefaultValue = "Never", AllowedValues = new[] { "Never", "Seconds", "Minutes", "Hours", "Days", "Weeks", "Months", "Quarters", "Years" } } } }, new ModuleSettingsGroup { Name = "Platform|User Interface", Settings = new[] { new ModuleSetting { Name = "VirtoCommerce.Platform.UI.Customization", ValueType = ModuleSetting.TypeJson, Title = "Customization", Description = "JSON contains personalization settings of manager UI", DefaultValue = "{\n" + " \"title\": \"Virto Commerce\",\n" + " \"logo\": \"Content/themes/main/images/logo.png\",\n" + " \"contrast_logo\": \"Content/themes/main/images/contrast-logo.png\"\n" + "}" } } } } }; var settingsManager = new SettingsManager(moduleCatalog, platformRepositoryFactory, cacheManager, new[] { new ManifestModuleInfo(platformModuleManifest) }); container.RegisterInstance <ISettingsManager>(settingsManager); #endregion #region Dynamic Properties container.RegisterType <IDynamicPropertyService, DynamicPropertyService>(new ContainerControlledLifetimeManager()); #endregion #region Notifications var hubSignalR = GlobalHost.ConnectionManager.GetHubContext <ClientPushHub>(); var notifier = new InMemoryPushNotificationManager(hubSignalR); container.RegisterInstance <IPushNotificationManager>(notifier); var resolver = new LiquidNotificationTemplateResolver(); container.RegisterInstance <INotificationTemplateResolver>(resolver); var notificationTemplateService = new NotificationTemplateServiceImpl(platformRepositoryFactory); container.RegisterInstance <INotificationTemplateService>(notificationTemplateService); var notificationManager = new NotificationManager(resolver, platformRepositoryFactory, notificationTemplateService); container.RegisterInstance <INotificationManager>(notificationManager); IEmailNotificationSendingGateway emailNotificationSendingGateway = null; var emailNotificationSendingGatewayName = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:Notifications:Gateway", "Default"); if (string.Equals(emailNotificationSendingGatewayName, "Default", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new DefaultSmtpEmailNotificationSendingGateway(settingsManager); } else if (string.Equals(emailNotificationSendingGatewayName, "SendGrid", StringComparison.OrdinalIgnoreCase)) { emailNotificationSendingGateway = new SendGridEmailNotificationSendingGateway(settingsManager); } if (emailNotificationSendingGateway != null) { container.RegisterInstance(emailNotificationSendingGateway); } var defaultSmsNotificationSendingGateway = new DefaultSmsNotificationSendingGateway(); container.RegisterInstance <ISmsNotificationSendingGateway>(defaultSmsNotificationSendingGateway); #endregion #region Assets var blobConnectionString = BlobConnectionString.Parse(ConfigurationManager.ConnectionStrings["AssetsConnectionString"].ConnectionString); if (string.Equals(blobConnectionString.Provider, FileSystemBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var fileSystemBlobProvider = new FileSystemBlobProvider(NormalizePath(blobConnectionString.RootPath), blobConnectionString.PublicUrl); container.RegisterInstance <IBlobStorageProvider>(fileSystemBlobProvider); container.RegisterInstance <IBlobUrlResolver>(fileSystemBlobProvider); } else if (string.Equals(blobConnectionString.Provider, AzureBlobProvider.ProviderName, StringComparison.OrdinalIgnoreCase)) { var azureBlobProvider = new AzureBlobProvider(blobConnectionString.ConnectionString); container.RegisterInstance <IBlobStorageProvider>(azureBlobProvider); container.RegisterInstance <IBlobUrlResolver>(azureBlobProvider); } #endregion #region Modularity var modulesDataSources = ConfigurationManager.AppSettings.SplitStringValue("VirtoCommerce:ModulesDataSources"); var externalModuleCatalog = new ExternalManifestModuleCatalog(moduleCatalog.Modules, modulesDataSources, container.Resolve <ILog>()); container.RegisterType <ModulesController>(new InjectionConstructor(externalModuleCatalog, new ModuleInstaller(modulesPath, externalModuleCatalog), notifier, container.Resolve <IUserNameResolver>(), settingsManager)); #endregion #region ChangeLogging var changeLogService = new ChangeLogService(platformRepositoryFactory); container.RegisterInstance <IChangeLogService>(changeLogService); #endregion #region Security container.RegisterInstance <IPermissionScopeService>(new PermissionScopeService()); container.RegisterType <IRoleManagementService, RoleManagementService>(new ContainerControlledLifetimeManager()); var apiAccountProvider = new ApiAccountProvider(platformRepositoryFactory, cacheManager); container.RegisterInstance <IApiAccountProvider>(apiAccountProvider); container.RegisterType <IClaimsIdentityProvider, ApplicationClaimsIdentityProvider>(new ContainerControlledLifetimeManager()); container.RegisterInstance(app.GetDataProtectionProvider()); container.RegisterType <SecurityDbContext>(new InjectionConstructor(connectionStringName)); container.RegisterType <IUserStore <ApplicationUser>, ApplicationUserStore>(); container.RegisterType <IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)); container.RegisterType <ApplicationUserManager>(); container.RegisterType <ApplicationSignInManager>(); var nonEditableUsers = ConfigurationManager.AppSettings.GetValue("VirtoCommerce:NonEditableUsers", string.Empty); container.RegisterInstance <ISecurityOptions>(new SecurityOptions(nonEditableUsers)); container.RegisterType <ISecurityService, SecurityService>(); #endregion #region ExportImport container.RegisterType <IPlatformExportImportManager, PlatformExportImportManager>(); #endregion #region Serialization container.RegisterType <IExpressionSerializer, XmlExpressionSerializer>(); #endregion }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); services.AddResponseCaching(); services.Configure <StorefrontOptions>(Configuration.GetSection("VirtoCommerce")); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); //The IHttpContextAccessor service is not registered by default //https://github.com/aspnet/Hosting/issues/793 services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton <IWorkContextAccessor, WorkContextAccessor>(); services.AddSingleton <IUrlBuilder, UrlBuilder>(); services.AddSingleton <IStorefrontUrlBuilder, StorefrontUrlBuilder>(); services.AddSingleton <IStoreService, StoreService>(); services.AddSingleton <ICurrencyService, CurrencyService>(); services.AddSingleton <ISlugRouteService, SlugRouteService>(); services.AddSingleton <IMemberService, MemberService>(); services.AddSingleton <ICustomerOrderService, CustomerOrderService>(); services.AddSingleton <IQuoteService, QuoteService>(); services.AddSingleton <ISubscriptionService, SubscriptionService>(); services.AddSingleton <ICatalogService, CatalogService>(); services.AddSingleton <IInventoryService, InventoryService>(); services.AddSingleton <IPricingService, PricingService>(); services.AddSingleton <ITaxEvaluator, TaxEvaluator>(); services.AddSingleton <IPromotionEvaluator, PromotionEvaluator>(); services.AddSingleton <IMarketingService, MarketingService>(); services.AddSingleton <IStaticContentService, StaticContentService>(); services.AddSingleton <IMenuLinkListService, MenuLinkListServiceImpl>(); services.AddSingleton <IStaticContentItemFactory, StaticContentItemFactory>(); services.AddSingleton <IApiChangesWatcher, ApiChangesWatcher>(); services.AddSingleton <AssociationRecommendationsProvider>(); services.AddSingleton <CognitiveRecommendationsProvider>(); services.AddSingleton <IRecommendationProviderFactory, RecommendationProviderFactory>(provider => new RecommendationProviderFactory(provider.GetService <AssociationRecommendationsProvider>(), provider.GetService <CognitiveRecommendationsProvider>())); services.AddTransient <IQuoteRequestBuilder, QuoteRequestBuilder>(); services.AddSingleton <IBlobChangesWatcher, BlobChangesWatcher>(); services.AddTransient <ICartBuilder, CartBuilder>(); services.AddTransient <ICartService, CartService>(); //Register events framework dependencies services.AddSingleton(new InProcessBus()); services.AddSingleton <IEventPublisher>(provider => provider.GetService <InProcessBus>()); services.AddSingleton <IHandlerRegistrar>(provider => provider.GetService <InProcessBus>()); //Register platform API clients services.AddPlatformEndpoint(options => { Configuration.GetSection("VirtoCommerce:Endpoint").Bind(options); }); services.AddSingleton <ICountriesService, FileSystemCountriesService>(); services.Configure <FileSystemCountriesOptions>(options => { options.FilePath = HostingEnvironment.MapPath("~/countries.json"); }); var contentConnectionString = BlobConnectionString.Parse(Configuration.GetConnectionString("ContentConnectionString")); if (contentConnectionString.Provider.EqualsInvariant("AzureBlobStorage")) { var azureBlobOptions = new AzureBlobContentOptions(); Configuration.GetSection("VirtoCommerce:AzureBlobStorage").Bind(azureBlobOptions); services.AddAzureBlobContent(options => { options.Container = contentConnectionString.RootPath; options.ConnectionString = contentConnectionString.ConnectionString; options.PollForChanges = azureBlobOptions.PollForChanges; options.ChangesPoolingInterval = azureBlobOptions.ChangesPoolingInterval; }); } else { var fileSystemBlobOptions = new FileSystemBlobContentOptions(); Configuration.GetSection("VirtoCommerce:FileSystemBlobStorage").Bind(fileSystemBlobOptions); services.AddFileSystemBlobContent(options => { options.Path = HostingEnvironment.MapPath(contentConnectionString.RootPath); }); } //Identity overrides for use remote user storage services.AddScoped <IUserStore <User>, UserStoreStub>(); services.AddScoped <IRoleStore <Role>, UserStoreStub>(); services.AddScoped <UserManager <User>, CustomUserManager>(); services.AddScoped <SignInManager <User>, CustomSignInManager>(); //Resource-based authorization that requires API permissions for some operations services.AddSingleton <IAuthorizationHandler, CanImpersonateAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanReadContentItemAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, OnlyRegisteredUserAuthorizationHandler>(); // register the AuthorizationPolicyProvider which dynamically registers authorization policies for each permission defined in the platform services.AddSingleton <IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>(); //Storefront authorization handler for policy based on permissions services.AddSingleton <IAuthorizationHandler, PermissionAuthorizationHandler>(); services.AddSingleton <IAuthorizationHandler, CanEditOrganizationResourceAuthorizationHandler>(); services.AddAuthorization(options => { options.AddPolicy(CanImpersonateAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new CanImpersonateAuthorizationRequirement())); options.AddPolicy(CanReadContentItemAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanReadContentItemAuthorizeRequirement())); options.AddPolicy(CanEditOrganizationResourceAuthorizeRequirement.PolicyName, policy => policy.Requirements.Add(new CanEditOrganizationResourceAuthorizeRequirement())); options.AddPolicy(OnlyRegisteredUserAuthorizationRequirement.PolicyName, policy => policy.Requirements.Add(new OnlyRegisteredUserAuthorizationRequirement())); }); var auth = services.AddAuthentication(); var facebookSection = Configuration.GetSection("Authentication:Facebook"); if (facebookSection.GetChildren().Any()) { auth.AddFacebook(facebookOptions => { facebookSection.Bind(facebookOptions); }); } var googleSection = Configuration.GetSection("Authentication:Google"); if (googleSection.GetChildren().Any()) { auth.AddGoogle(googleOptions => { googleSection.Bind(googleOptions); }); } var githubSection = Configuration.GetSection("Authentication:Github"); if (githubSection.GetChildren().Any()) { auth.AddGitHub(GitHubAuthenticationOptions => { githubSection.Bind(GitHubAuthenticationOptions); }); } var stackexchangeSection = Configuration.GetSection("Authentication:Stackexchange"); if (stackexchangeSection.GetChildren().Any()) { auth.AddStackExchange(StackExchangeAuthenticationOptions => { stackexchangeSection.Bind(StackExchangeAuthenticationOptions); }); } //This line is required in order to use the old Identity V2 hashes to prevent rehashes passwords for platform users which login in the storefront //and it can lead to platform access denied for them. (TODO: Need to remove after platform migration to .NET Core) services.Configure <PasswordHasherOptions>(option => option.CompatibilityMode = PasswordHasherCompatibilityMode.IdentityV2); services.Configure <IdentityOptions>(Configuration.GetSection("IdentityOptions")); services.Configure <CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, Configuration.GetSection("CookieAuthenticationOptions")); services.AddIdentity <User, Role>(options => { }).AddDefaultTokenProviders(); services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); // The Tempdata provider cookie is not essential. Make it essential // so Tempdata is functional when tracking is disabled. services.Configure <CookieTempDataProviderOptions>(options => { options.Cookie.IsEssential = true; }); services.Replace(ServiceDescriptor.Transient <CookieAuthenticationHandler, CustomCookieAuthenticationHandler>()); //Add Liquid view engine services.AddLiquidViewEngine(options => { Configuration.GetSection("VirtoCommerce:LiquidThemeEngine").Bind(options); }); var snapshotProvider = services.BuildServiceProvider(); services.AddMvc(options => { //Workaround to avoid 'Null effective policy causing exception' (on logout) //https://github.com/aspnet/Mvc/issues/7809 //TODO: Try to remove in ASP.NET Core 2.2 options.AllowCombiningAuthorizeFilters = false; options.CacheProfiles.Add("Default", new CacheProfile() { Duration = (int)TimeSpan.FromHours(1).TotalSeconds, VaryByHeader = "host" }); }).AddJsonOptions(options => { options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include; options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; options.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore; options.SerializerSettings.Converters.Add(new CartTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new MoneyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new CurrencyJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new OrderTypesJsonConverter(snapshotProvider.GetService <IWorkContextAccessor>())); options.SerializerSettings.Converters.Add(new RecommendationJsonConverter(snapshotProvider.GetService <IRecommendationProviderFactory>())); //Converter for providing back compatibility with old themes was used CustomerInfo type which has contained user and contact data in the single type. //May be removed when all themes will fixed to new User type with nested Contact property. options.SerializerSettings.Converters.Add(new UserBackwardCompatibilityJsonConverter(options.SerializerSettings)); }).AddViewOptions(options => { options.ViewEngines.Add(snapshotProvider.GetService <ILiquidViewEngine>()); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); //Register event handlers via reflection services.RegisterAssembliesEventHandlers(typeof(Startup)); services.AddApplicationInsightsTelemetry(); services.AddApplicationInsightsExtensions(Configuration); services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); }