public static int Process(GetDocumentCommandContext context) { var assemblyName = new AssemblyName(context.AssemblyName); var assembly = Assembly.Load(assemblyName); var entryPointType = assembly.EntryPoint?.DeclaringType; if (entryPointType == null) { Reporter.WriteError(Resources.FormatMissingEntryPoint(context.AssemblyPath)); return(2); } var services = GetServices(entryPointType, context.AssemblyPath, context.AssemblyName); if (services == null) { return(3); } var success = TryProcess(context, services); if (!success) { // As part of the aspnet/Mvc#8425 fix, return 4 here. return(0); } return(0); }
public static bool TryProcess(GetDocumentCommandContext context, IServiceProvider services) { var documentName = string.IsNullOrEmpty(context.DocumentName) ? GetDocumentCommand.FallbackDocumentName : context.DocumentName; var methodName = string.IsNullOrEmpty(context.Method) ? GetDocumentCommand.FallbackMethod : context.Method; var serviceName = string.IsNullOrEmpty(context.Service) ? GetDocumentCommand.FallbackService : context.Service; Reporter.WriteInformation(Resources.FormatUsingDocument(documentName)); Reporter.WriteInformation(Resources.FormatUsingMethod(methodName)); Reporter.WriteInformation(Resources.FormatUsingService(serviceName)); try { var serviceType = Type.GetType(serviceName, throwOnError: true); var method = serviceType.GetMethod(methodName, new[] { typeof(TextWriter), typeof(string) }); var service = services.GetRequiredService(serviceType); var success = true; using (var writer = File.CreateText(context.Output)) { if (method.ReturnType == typeof(bool)) { success = (bool)method.Invoke(service, new object[] { writer, documentName }); } else { method.Invoke(service, new object[] { writer, documentName }); } } if (!success) { // As part of the aspnet/Mvc#8425 fix, make this an error unless the file already exists. var message = Resources.FormatMethodInvocationFailed(methodName, serviceName, documentName); Reporter.WriteWarning(message); } return(success); } catch (Exception ex) { var message = FormatException(ex); // As part of the aspnet/Mvc#8425 fix, make this an error unless the file already exists. Reporter.WriteWarning(message); return(false); } }
public static int Process(GetDocumentCommandContext context) { var assemblyName = new AssemblyName(context.AssemblyName); var assembly = Assembly.Load(assemblyName); var entryPointType = assembly.EntryPoint?.DeclaringType; if (entryPointType == null) { Reporter.WriteError(Resources.FormatMissingEntryPoint(context.AssemblyPath)); return(3); } try { var serviceFactory = HostFactoryResolver.ResolveServiceProviderFactory(assembly); if (serviceFactory == null) { Reporter.WriteError(Resources.FormatMethodsNotFound( HostFactoryResolver.BuildWebHost, HostFactoryResolver.CreateHostBuilder, HostFactoryResolver.CreateWebHostBuilder, entryPointType)); return(4); } var services = serviceFactory(Array.Empty <string>()); if (services == null) { Reporter.WriteError(Resources.FormatServiceProviderNotFound( typeof(IServiceProvider), HostFactoryResolver.BuildWebHost, HostFactoryResolver.CreateHostBuilder, HostFactoryResolver.CreateWebHostBuilder, entryPointType)); return(5); } var success = GetDocuments(context, services); if (!success) { return(6); } } catch (Exception ex) { Reporter.WriteError(ex.ToString()); return(7); } return(0); }
public static bool TryProcess(GetDocumentCommandContext context, IServiceProvider services) { var documentName = string.IsNullOrEmpty(context.DocumentName) ? GetDocumentCommand.FallbackDocumentName : context.DocumentName; var methodName = string.IsNullOrEmpty(context.Method) ? GetDocumentCommand.FallbackMethod : context.Method; var serviceName = string.IsNullOrEmpty(context.Service) ? GetDocumentCommand.FallbackService : context.Service; Reporter.WriteInformation(Resources.FormatUsingDocument(documentName)); Reporter.WriteInformation(Resources.FormatUsingMethod(methodName)); Reporter.WriteInformation(Resources.FormatUsingService(serviceName)); try { Type serviceType = null; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { serviceType = assembly.GetType(serviceName, throwOnError: false); if (serviceType != null) { break; } } // As part of the aspnet/Mvc#8425 fix, make all warnings in this method errors unless the file already // exists. if (serviceType == null) { Reporter.WriteWarning(Resources.FormatServiceTypeNotFound(serviceName)); return(false); } var method = serviceType.GetMethod(methodName, new[] { typeof(string), typeof(TextWriter) }); if (method == null) { Reporter.WriteWarning(Resources.FormatMethodNotFound(methodName, serviceName)); return(false); } else if (!typeof(Task).IsAssignableFrom(method.ReturnType)) { Reporter.WriteWarning(Resources.FormatMethodReturnTypeUnsupported( methodName, serviceName, method.ReturnType, typeof(Task))); return(false); } var service = services.GetService(serviceType); if (service == null) { Reporter.WriteWarning(Resources.FormatServiceNotFound(serviceName)); return(false); } // Create the output FileStream last to avoid corrupting an existing file or writing partial data. var stream = new MemoryStream(); using (var writer = new StreamWriter(stream)) { var resultTask = (Task)method.Invoke(service, new object[] { documentName, writer }); if (resultTask == null) { Reporter.WriteWarning( Resources.FormatMethodReturnedNull(methodName, serviceName, nameof(Task))); return(false); } var finishedIndex = Task.WaitAny(resultTask, Task.Delay(TimeSpan.FromMinutes(1))); if (finishedIndex != 0) { Reporter.WriteWarning(Resources.FormatMethodTimedOut(methodName, serviceName, 1)); return(false); } writer.Flush(); if (stream.Length > 0L) { stream.Position = 0L; using (var outStream = File.Create(context.OutputPath)) { stream.CopyTo(outStream); outStream.Flush(); } } } return(true); } catch (AggregateException ex) when(ex.InnerException != null) { foreach (var innerException in ex.Flatten().InnerExceptions) { Reporter.WriteWarning(FormatException(innerException)); } } catch (Exception ex) { Reporter.WriteWarning(FormatException(ex)); } File.Delete(context.OutputPath); return(false); }
public GetDocumentCommandWorker(GetDocumentCommandContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); _reporter = context.Reporter; }
protected override int Execute() { var thisAssembly = typeof(GetDocumentCommand).Assembly; var toolsDirectory = ToolsDirectory.Value(); var packagedAssemblies = Directory .EnumerateFiles(toolsDirectory, "*.dll") .Except(new[] { Path.GetFullPath(thisAssembly.Location) }) .ToDictionary(path => Path.GetFileNameWithoutExtension(path), path => new AssemblyInfo(path)); // Explicitly load all assemblies we need first to preserve target project as much as possible. This // executable is always run in the target project's context (either through location or .deps.json file). foreach (var keyValuePair in packagedAssemblies) { try { keyValuePair.Value.Assembly = Assembly.Load(new AssemblyName(keyValuePair.Key)); } catch { // Ignore all failures because missing assemblies should be loadable from tools directory. } } #if NETCOREAPP2_1 AssemblyLoadContext.Default.Resolving += (loadContext, assemblyName) => { var name = assemblyName.Name; if (!packagedAssemblies.TryGetValue(name, out var info)) { return(null); } var assemblyPath = info.Path; if (!File.Exists(assemblyPath)) { throw new InvalidOperationException( $"Referenced assembly '{name}' was not found in '{toolsDirectory}'."); } return(loadContext.LoadFromAssemblyPath(assemblyPath)); }; #elif NET461 AppDomain.CurrentDomain.AssemblyResolve += (source, eventArgs) => { var assemblyName = new AssemblyName(eventArgs.Name); var name = assemblyName.Name; if (!packagedAssemblies.TryGetValue(name, out var info)) { return(null); } var assembly = info.Assembly; if (assembly != null) { // Loaded already return(assembly); } var assemblyPath = info.Path; if (!File.Exists(assemblyPath)) { throw new InvalidOperationException( $"Referenced assembly '{name}' was not found in '{toolsDirectory}'."); } return(Assembly.LoadFile(assemblyPath)); }; #else #error Target frameworks need to be updated. #endif // Now safe to reference the application's code. try { var assemblyPath = AssemblyPath.Value(); var context = new GetDocumentCommandContext { AssemblyPath = assemblyPath, AssemblyName = Path.GetFileNameWithoutExtension(assemblyPath), FileListPath = _fileListPath.Value(), OutputDirectory = _output.Value(), ProjectName = ProjectName.Value(), }; return(GetDocumentCommandWorker.Process(context)); } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); return(2); } }
private static bool GetDocuments(GetDocumentCommandContext context, IServiceProvider services) { Type serviceType = null; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { serviceType = assembly.GetType(DocumentService, throwOnError: false); if (serviceType != null) { break; } } if (serviceType == null) { Reporter.WriteError(Resources.FormatServiceTypeNotFound(DocumentService)); return(false); } var getDocumentsMethod = GetMethod( GetDocumentsMethodName, serviceType, GetDocumentsParameterTypes, GetDocumentsReturnType); if (getDocumentsMethod == null) { return(false); } var generateMethod = GetMethod( GenerateMethodName, serviceType, GenerateMethodParameterTypes, GenerateMethodReturnType); if (generateMethod == null) { return(false); } var service = services.GetService(serviceType); if (service == null) { Reporter.WriteError(Resources.FormatServiceNotFound(DocumentService)); return(false); } var documentNames = (IEnumerable <string>)InvokeMethod(getDocumentsMethod, service, GetDocumentsArguments); if (documentNames == null) { return(false); } // Write out the documents. Directory.CreateDirectory(context.OutputDirectory); var filePathList = new List <string>(); foreach (var documentName in documentNames) { var filePath = GetDocument( documentName, context.ProjectName, context.OutputDirectory, generateMethod, service); if (filePath == null) { return(false); } filePathList.Add(filePath); } // Write out the cache file. var stream = File.Create(context.FileListPath); using var writer = new StreamWriter(stream); writer.WriteLine(string.Join(Environment.NewLine, filePathList)); return(true); }