Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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
        }
Пример #4
0
        // 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();
        }
Пример #5
0
        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);
        }
Пример #6
0
        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
        }
Пример #7
0
        // 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();
        }
Пример #8
0
        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
        }
Пример #9
0
        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);
        }
Пример #10
0
        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
        }
Пример #11
0
        // 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");
        }