Blazor Hybrid / .NET MAUI support
This commit is contained in:
		
							
								
								
									
										154
									
								
								Oqtane.Maui/MauiProgram.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								Oqtane.Maui/MauiProgram.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| using System.IO.Compression; | ||||
| using System.Reflection; | ||||
| using System.Runtime.Loader; | ||||
| using System.Diagnostics; | ||||
| using Oqtane.Modules; | ||||
| using Oqtane.Services; | ||||
| using System.Text.Json; | ||||
| using System.Text.Json.Nodes; | ||||
|  | ||||
| namespace Oqtane.Maui; | ||||
|  | ||||
| public static class MauiProgram | ||||
| { | ||||
|     static string url = "http://localhost:44357"; // can be overridden in an appsettings.json in AppDataDirectory | ||||
|  | ||||
|     public static MauiApp CreateMauiApp() | ||||
| 	{ | ||||
| 		var builder = MauiApp.CreateBuilder(); | ||||
| 		builder | ||||
| 			.UseMauiApp<App>() | ||||
| 			.ConfigureFonts(fonts => | ||||
| 			{ | ||||
| 				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); | ||||
| 			}); | ||||
|  | ||||
| 		builder.Services.AddMauiBlazorWebView(); | ||||
| 		#if DEBUG | ||||
| 		builder.Services.AddBlazorWebViewDeveloperTools(); | ||||
| #endif | ||||
|  | ||||
|         LoadAppSettings(); | ||||
|  | ||||
|         var httpClient = new HttpClient { BaseAddress = new Uri(url) }; | ||||
|         httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Shared.Constants.MauiUserAgent); | ||||
|         builder.Services.AddSingleton(httpClient); | ||||
|         builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase | ||||
|  | ||||
|         // dynamically load client assemblies | ||||
|         LoadClientAssemblies(httpClient); | ||||
|  | ||||
|         // register localization services | ||||
|         builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); | ||||
|  | ||||
|         // register auth services | ||||
|         builder.Services.AddOqtaneAuthorization(); | ||||
|  | ||||
|         // register scoped core services | ||||
|         builder.Services.AddOqtaneScopedServices(); | ||||
|  | ||||
|         var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); | ||||
|         foreach (var assembly in assemblies) | ||||
|         { | ||||
|             // dynamically register module services | ||||
|             RegisterModuleServices(assembly, builder.Services); | ||||
|  | ||||
|             // register client startup services | ||||
|             RegisterClientStartups(assembly, builder.Services); | ||||
|         } | ||||
|  | ||||
|         return builder.Build(); | ||||
| 	} | ||||
|  | ||||
|     private static void LoadAppSettings() | ||||
|     { | ||||
|         string file = Path.Combine(FileSystem.Current.AppDataDirectory, "appsettings.json"); | ||||
|         using FileStream stream = File.OpenRead(file); | ||||
|         using StreamReader reader = new StreamReader(stream); | ||||
|         var content = reader.ReadToEnd(); | ||||
|         var obj = JsonSerializer.Deserialize<JsonObject>(content)!; | ||||
|         if (!string.IsNullOrEmpty((string)obj["Url"])) | ||||
|         { | ||||
|             url = (string)obj["Url"]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void LoadClientAssemblies(HttpClient http) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             // get list of loaded assemblies on the client | ||||
|             var assemblies = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToList(); | ||||
|  | ||||
|             // get assemblies from server and load into client app domain | ||||
|             var zip = http.GetByteArrayAsync($"/api/Installation/load").Result; | ||||
|  | ||||
|             // asemblies and debug symbols are packaged in a zip file | ||||
|             using (ZipArchive archive = new ZipArchive(new MemoryStream(zip))) | ||||
|             { | ||||
|                 var dlls = new Dictionary<string, byte[]>(); | ||||
|                 var pdbs = new Dictionary<string, byte[]>(); | ||||
|  | ||||
|                 foreach (ZipArchiveEntry entry in archive.Entries) | ||||
|                 { | ||||
|                     if (!assemblies.Contains(Path.GetFileNameWithoutExtension(entry.FullName))) | ||||
|                     { | ||||
|                         using (var memoryStream = new MemoryStream()) | ||||
|                         { | ||||
|                             entry.Open().CopyTo(memoryStream); | ||||
|                             byte[] file = memoryStream.ToArray(); | ||||
|                             switch (Path.GetExtension(entry.FullName)) | ||||
|                             { | ||||
|                                 case ".dll": | ||||
|                                     dlls.Add(entry.FullName, file); | ||||
|                                     break; | ||||
|                                 case ".pdb": | ||||
|                                     pdbs.Add(entry.FullName, file); | ||||
|                                     break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 foreach (var item in dlls) | ||||
|                 { | ||||
|                     if (pdbs.ContainsKey(item.Key)) | ||||
|                     { | ||||
|                         AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(item.Value), new MemoryStream(pdbs[item.Key])); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(item.Value)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             Debug.WriteLine($"Oqtane Error: Loading Client Assemblies {ex}"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void RegisterModuleServices(Assembly assembly, IServiceCollection services) | ||||
|     { | ||||
|         // dynamically register module scoped services | ||||
|         var implementationTypes = assembly.GetInterfaces<IService>(); | ||||
|         foreach (var implementationType in implementationTypes) | ||||
|         { | ||||
|             if (implementationType.AssemblyQualifiedName != null) | ||||
|             { | ||||
|                 var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}")); | ||||
|                 services.AddScoped(serviceType ?? implementationType, implementationType); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static void RegisterClientStartups(Assembly assembly, IServiceCollection services) | ||||
|     { | ||||
|         var startUps = assembly.GetInstances<IClientStartup>(); | ||||
|         foreach (var startup in startUps) | ||||
|         { | ||||
|             startup.ConfigureServices(services); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker