/// <summary> /// Creates and starts a persistence-less App Host that doesn't have a database connection. A transient host is very light-weight and /// although its state is not persisted (the Orchard shell state; any persistence you do will work of course) it's kept until the /// Host is disposed. That means you can still enabled/disable features for example and the shell state will change as expected. /// </summary> /// <param name="settings">Settings for the App Host.</param> /// <param name="registrations">Dependency registrations for the App Host.</param> /// <param name="enabledStartupFeatures">Names of features to enable already when the shell starts.</param> public static Task <IOrchardAppHost> StartTransientHost(AppHostSettings settings, AppHostRegistrations registrations, IEnumerable <ShellFeature> enabledStartupFeatures) { if (registrations == null) { registrations = new AppHostRegistrations(); } var appRegistrations = (registrations.HostRegistrations == null) ? builder => { } : registrations.HostRegistrations; registrations.HostRegistrations = builder => { var shellSettingsManager = new TransientShellSettingsManager(); shellSettingsManager.SaveSettings(new ShellSettings { Name = ShellSettings.DefaultName, State = TenantState.Running }); builder.RegisterInstance(shellSettingsManager).As <IShellSettingsManager>().SingleInstance(); builder.RegisterType <HostTransientStore>().As <IHostTransientStore>().SingleInstance(); appRegistrations(builder); }; var shellRegistrations = (registrations.ShellRegistrations == null) ? builder => { } : registrations.ShellRegistrations; registrations.ShellRegistrations = builder => { if (enabledStartupFeatures == null) { enabledStartupFeatures = Enumerable.Empty <ShellFeature>(); } enabledStartupFeatures = enabledStartupFeatures.Union(new[] { new ShellFeature { Name = "Orchard.Framework" }, new ShellFeature { Name = "Lombiq.OrchardAppHost.TransientHost" } }); builder .RegisterInstance(new DefaultTransientShellDescriptorProvider(new ShellDescriptor { Features = enabledStartupFeatures })) .As <IDefaultTransientShellDescriptorProvider>(); builder.RegisterType <TransientShellDescriptorManager>().As <IShellDescriptorManager>().SingleInstance(); builder.RegisterType <TransientShellStateManager>().As <IShellStateManager>().SingleInstance(); builder.RegisterType <TransientStore>().As <ITransientStore>().SingleInstance(); // These below are only needed if Core extensions are not loaded (i.e. their path not set in AppHostSettings). // Needed too early in ShellContextFactory, since the minimum shell doesn't include any external feautures. builder.RegisterType <NullSiteService>().As <ISiteService>().SingleInstance(); builder.RegisterType <NullContentDefinitionManager>().As <IContentDefinitionManager>().SingleInstance(); shellRegistrations(builder); }; return(StartHost(settings, registrations)); }
/// <summary> /// Creates and starts an App Host. /// </summary> /// <param name="settings">Settings for the App Host.</param> /// <param name="registrations">Dependency registrations for the App Host.</param> public static async Task <IOrchardAppHost> StartHost(AppHostSettings settings, AppHostRegistrations registrations) { var host = new OrchardAppHost(settings, registrations); await host.Startup(); return(host); }
public static async Task RunSample(AppHostSettings settings) { Console.WriteLine("=== Loop sample starts === "); Console.WriteLine("Press Ctrl+C to exit the loop."); using (var host = await OrchardAppHostFactory.StartHost(settings)) { var run = true; // Hit Ctrl+C to exit the loop, but not the app (other samples will follow up). Console.CancelKeyPress += (sender, e) => { e.Cancel = true; run = false; }; while (run) { Console.WriteLine("Cycle starts."); await host.Run <ILoggerService, IClock>((logger, clock) => Task.Run(() => { logger.Error("Test log entry."); Console.WriteLine(clock.UtcNow.ToString()); })); // Another overload of Run() for simple transaction handling and for using the work context scope // directly. await host.RunInTransaction(async scope => { Console.WriteLine(scope.Resolve <ISiteService>().GetSiteSettings().SiteName); // Simulating an async call. Because of this the delegate is marked as async (and we don't // need to wrap it into a Task.Run()). await Task.Delay(3000); Console.WriteLine(scope.Resolve <ISiteService>().GetSiteSettings().SiteName); Console.WriteLine(scope.Resolve <ShellSettings>().Name); }); Console.WriteLine("Cycle ends."); Console.WriteLine(); } } Console.WriteLine("=== Loop sample ended === "); }
public OrchardAppHost( AppHostSettings settings, AppHostRegistrations registrations) { if (settings == null) { settings = new AppHostSettings(); } if (registrations == null) { registrations = new AppHostRegistrations(); } _settings = settings; _registrations = registrations; }
static void Main(string[] args) { Task.Run(async() => { // There are a lot of settings you can use. var settings = new AppHostSettings { // A random App_Data folder so the setup sample can run from a fresh state. AppDataFolderPath = "~/App_Data" + new Random().Next(), ModuleFolderPaths = new[] { @"~/../../../Orchard/src/Orchard.Web/Modules" }, CoreModuleFolderPaths = new[] { @"~/../../../Orchard/src/Orchard.Web/Core" }, ThemeFolderPaths = new[] { @"~/../../../Orchard/src/Orchard.Web/Themes" }, ImportedExtensions = new[] { typeof(Program).Assembly }, DefaultShellFeatureStates = new[] { new DefaultShellFeatureState { ShellName = ShellSettings.DefaultName, EnabledFeatures = new[] { "Lombiq.OrchardAppHost.Sample", "Lombiq.OrchardAppHost.Sample.ShellEvents" } } }, DisableConfiguratonCaches = true, DisableExtensionMonitoring = true, // Configuring the logging of SQL queries (see: // http://weblogs.asp.net/bleroy/logging-sql-queries-in-orchard). // This needs a reference to the Log4Net assembly. Log4NetConfigurator = loggerRespository => ((Logger)loggerRespository.GetLogger("NHibernate.SQL")).Level = Level.Debug }; // Samples are being run below, check out the static classes. await SetupSample.RunSample(settings); Console.WriteLine(); await LoopSample.RunSample(settings); Console.WriteLine(); await TransientHostSample.RunSample(settings); Console.ReadKey(); }).Wait(); // This is a workaround just to be able to run all this from inside a console app. }
public static async Task RunSample(AppHostSettings settings) { Console.WriteLine("=== Transient host sample starts === "); using (var host = await OrchardAppHostFactory.StartTransientHost(settings, null, null)) { await host.Run <ITestService, ILoggerService, IClock>((testService, logger, clock) => Task.Run(() => { testService.Test(); // Custom dependencies from imported and enabled extensions work too. logger.Error("Test log entry from transient shell."); Console.WriteLine(clock.UtcNow.ToString()); })); // You can even run such "getters" to just fetch something from Orchard. var utcNow = await host.RunGet(scope => Task.Run(() => scope.Resolve <IClock>().UtcNow)); } Console.WriteLine("=== Transient host sample ended === "); }
public static async Task RunSample(AppHostSettings settings) { Console.WriteLine("=== Setup sample starts === "); using (var host = await OrchardAppHostFactory.StartHost(settings)) { // We can even run the setup on a new shell. A project reference to Orchard.Setup is needed. // The setup shouldn't run in a transaction. await host.Run <ISetupService, ShellSettings>((setupService, shellSettings) => Task.Run(() => { Console.WriteLine("Running setup for the following shell: " + shellSettings.Name); setupService.Setup(new SetupContext { SiteName = "Test", AdminUsername = "******", AdminPassword = "******", DatabaseProvider = "SqlCe", Recipe = setupService.Recipes().Where(recipe => recipe.Name == "Default").Single() }); Console.WriteLine("Setup done"); }), wrapInTransaction : false); } using (var host = await OrchardAppHostFactory.StartHost(settings)) { // After setup everything else should be run in a newly started host. await host.Run <ISiteService, ShellSettings>((siteService, shellSettings) => Task.Run(() => { Console.WriteLine(siteService.GetSiteSettings().SiteName); Console.WriteLine(shellSettings.Name); })); } Console.WriteLine("=== Setup host sample ended === "); }
private async Task LoadHost() { var moduleFolderPaths = new List <string>(); // Since Hast.Core either exists or not we need to start by probing for the Hast.Abstractions folder. var abstractionsPath = Path.GetDirectoryName(GetType().Assembly.Location); var currentDirectory = Path.GetFileName(abstractionsPath); if (currentDirectory.Equals("Debug", StringComparison.OrdinalIgnoreCase) || currentDirectory.Equals("Release", StringComparison.OrdinalIgnoreCase)) { abstractionsPath = Path.GetDirectoryName(abstractionsPath); } currentDirectory = Path.GetFileName(abstractionsPath); if (currentDirectory.Equals("bin", StringComparison.OrdinalIgnoreCase)) { abstractionsPath = Path.GetDirectoryName(abstractionsPath); } // Now we're at the level above the current project's folder. abstractionsPath = Path.GetDirectoryName(abstractionsPath); var coreFound = false; while (abstractionsPath != null && !coreFound) { var abstractionsSubFolder = Path.Combine(abstractionsPath, "Hast.Abstractions"); if (Directory.Exists(abstractionsSubFolder)) { abstractionsPath = abstractionsSubFolder; coreFound = true; } else { abstractionsPath = Path.GetDirectoryName(abstractionsPath); } } // There won't be an Abstractions folder, nor a Core one when the app is being run from a deployment folder // (as opposed to a solution). if (!string.IsNullOrEmpty(abstractionsPath)) { moduleFolderPaths.Add(abstractionsPath); } if (_configuration.Flavor == HastlayerFlavor.Developer) { var corePath = !string.IsNullOrEmpty(abstractionsPath) ? Path.Combine(Path.GetDirectoryName(abstractionsPath), "Hast.Core") : null; if (corePath != null && Directory.Exists(corePath)) { moduleFolderPaths.Add(corePath); } } var importedExtensions = new[] { typeof(Hastlayer).Assembly, typeof(IProxyGenerator).Assembly, typeof(IHardwareImplementationComposer).Assembly, typeof(ITransformer).Assembly, typeof(Nexys4DdrManifestProvider).Assembly } .ToList(); if (_configuration.Flavor == HastlayerFlavor.Client) { importedExtensions.Add(typeof(Remote.Client.RemoteTransformer).Assembly); } // Adding imported extensions last so they can override anything. importedExtensions.AddRange(_configuration.Extensions); var settings = new AppHostSettings { // Setting a custom path so if the parent app is also an AppHost app then with the default settings // those won't clash. AppDataFolderPath = "~/Hastlayer/App_Data", ImportedExtensions = importedExtensions, DefaultShellFeatureStates = new[] { new DefaultShellFeatureState { ShellName = ShellName, EnabledFeatures = importedExtensions.Select(extension => extension.ShortName()) } }, ModuleFolderPaths = moduleFolderPaths }; var registrations = new AppHostRegistrations { HostRegistrations = builder => builder .RegisterType <HardwareExecutionEventHandlerHolder>() .As <IHardwareExecutionEventHandlerHolder>() .SingleInstance() }; _host = await OrchardAppHostFactory.StartTransientHost(settings, registrations, null); await _host.Run <IHardwareExecutionEventHandlerHolder>(proxy => Task.Run(() => proxy.RegisterExecutedOnHardwareEventHandler(eventArgs => ExecutedOnHardware?.Invoke(this, eventArgs)))); // Enable all loaded features. This is needed so extensions just added to the solution, but not referenced // anywhere in the current app can contribute dependencies. await _host .Run <Orchard.Environment.Features.IFeatureManager>( (featureManager) => { featureManager.EnableFeatures(featureManager.GetAvailableFeatures().Select(feature => feature.Id), true); return(Task.CompletedTask); }, ShellName, false); }
// Having an overload without "registrations" enables calling it without the caller having a reference to Autofac. public OrchardAppHost(AppHostSettings settings) : this(settings, null) { }
public ExtensionPathsProvider(AppHostSettings hostSettings, IVirtualPathProvider virtualPathProvider) { _hostSettings = hostSettings; _virtualPathProvider = virtualPathProvider; }
/// <summary> /// Creates and starts an App Host. /// </summary> /// <param name="settings">Settings for the App Host.</param> public static Task <IOrchardAppHost> StartHost(AppHostSettings settings) { return(StartHost(settings, null)); }
public static IContainer CreateHostContainer(IOrchardAppHost appHost, AppHostSettings settings, AppHostRegistrations registrations) { return(OrchardStarter.CreateHostContainer(builder => { builder.RegisterType <AppHostEnvironment>().As <IHostEnvironment>().SingleInstance(); // Needed also for shells, separately. RegisterAppDataFolderRoot(builder, settings.AppDataFolderPath).SingleInstance(); RegisterVolatileProvider <AppHostVirtualPathMonitor, IVirtualPathMonitor>(builder); RegisterVolatileProvider <AppHostVirtualPathProvider, IVirtualPathProvider>(builder); RegisterVolatileProvider <AppHostWebSiteFolder, IWebSiteFolder>(builder); var shellRegistrations = new ShellContainerRegistrations { Registrations = shellBuilder => { // Despite imported assemblies being handled these registrations are necessary, because they are needed too early. // Adding them as normal services, even with OrchardSuppressDependency, wouldn't work. RegisterAppDataFolderRoot(shellBuilder, settings.AppDataFolderPath).InstancePerMatchingLifetimeScope("shell"); RegisterVolatileProviderForShell <AppHostVirtualPathMonitor, IVirtualPathMonitor>(shellBuilder); RegisterVolatileProviderForShell <AppHostVirtualPathProvider, IVirtualPathProvider>(shellBuilder); RegisterVolatileProviderForShell <AppHostWebSiteFolder, IWebSiteFolder>(shellBuilder); if (registrations.ShellRegistrations != null) { registrations.ShellRegistrations(shellBuilder); } } }; builder.RegisterInstance(shellRegistrations).As <IShellContainerRegistrations>(); // Handling imported assemblies. if (settings.ImportedExtensions != null && settings.ImportedExtensions.Any()) { builder.RegisterType <ImportedExtensionsProvider>().As <IExtensionFolders, IExtensionLoader>().SingleInstance() .WithParameter(new NamedParameter("extensions", settings.ImportedExtensions)); } // Configuring extension loading. builder.RegisterType <ExtensionPathsProvider>().As <IExtensionPathsProvider>().SingleInstance() .WithParameter(new NamedParameter("hostSettings", settings)); builder.RegisterType <AppHostExtensionFolders>().As <IExtensionFolders>().SingleInstance(); builder.RegisterType <AppHostCoreExtensionLoader>().As <IExtensionLoader>().SingleInstance(); builder.RegisterType <AppHostRawThemeExtensionLoader>().As <IExtensionLoader>().SingleInstance(); if (settings.DisableConfiguratonCaches) { builder.RegisterModule <ConfigurationCacheDisablingModule>(); } if (settings.DisableExtensionMonitoring) { builder.RegisterModule <ExtensionMonitoringDisablingModule>(); } // Either we register MVC singletons or we need at least a new IOrchardShell implementation. builder.Register(ctx => RouteTable.Routes).SingleInstance(); builder.Register(ctx => ModelBinders.Binders).SingleInstance(); builder.Register(ctx => ViewEngines.Engines).SingleInstance(); builder.RegisterType <LoggerService>().As <ILoggerService>().SingleInstance(); builder.RegisterInstance(appHost).As <IOrchardAppHost>().ExternallyOwned(); if (registrations.HostRegistrations != null) { registrations.HostRegistrations(builder); } })); }