Merge pull request #8656 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
0cea1b2a5f
|
|
@ -15,7 +15,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
|||
internal class GetDocumentCommand : ProjectCommandBase
|
||||
{
|
||||
internal const string FallbackDocumentName = "v1";
|
||||
internal const string FallbackMethod = "Generate";
|
||||
internal const string FallbackMethod = "GenerateAsync";
|
||||
internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider";
|
||||
|
||||
private CommandOption _documentName;
|
||||
|
|
@ -139,7 +139,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
|||
AssemblyName = Path.GetFileNameWithoutExtension(assemblyPath),
|
||||
DocumentName = _documentName.Value(),
|
||||
Method = _method.Value(),
|
||||
Output = _output.Value(),
|
||||
OutputPath = _output.Value(),
|
||||
Service = _service.Value(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
|||
|
||||
public string Method { get; set; }
|
||||
|
||||
public string Output { get; set; }
|
||||
public string OutputPath { get; set; }
|
||||
|
||||
public string Service { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
||||
{
|
||||
|
|
@ -56,41 +56,91 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
|||
|
||||
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))
|
||||
Type serviceType = null;
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (method.ReturnType == typeof(bool))
|
||||
serviceType = assembly.GetType(serviceName, throwOnError: false);
|
||||
if (serviceType != null)
|
||||
{
|
||||
success = (bool)method.Invoke(service, new object[] { writer, documentName });
|
||||
}
|
||||
else
|
||||
{
|
||||
method.Invoke(service, new object[] { writer, documentName });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
// As part of the aspnet/Mvc#8425 fix, make all warnings in this method errors unless the file already
|
||||
// exists.
|
||||
if (serviceType == null)
|
||||
{
|
||||
// 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);
|
||||
Reporter.WriteWarning(Resources.FormatServiceTypeNotFound(serviceName));
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
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 finished = Task.WhenAny(resultTask, Task.Delay(TimeSpan.FromMinutes(1)));
|
||||
if (!ReferenceEquals(resultTask, finished))
|
||||
{
|
||||
Reporter.WriteWarning(Resources.FormatMethodTimedOut(methodName, serviceName, 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
writer.Flush();
|
||||
stream.Position = 0L;
|
||||
using (var outStream = File.Create(context.OutputPath))
|
||||
{
|
||||
stream.CopyTo(outStream);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (AggregateException ex) when (ex.InnerException != null)
|
||||
{
|
||||
foreach (var innerException in ex.Flatten().InnerExceptions)
|
||||
{
|
||||
Reporter.WriteWarning(FormatException(innerException));
|
||||
}
|
||||
}
|
||||
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;
|
||||
Reporter.WriteWarning(FormatException(ex));
|
||||
}
|
||||
|
||||
File.Delete(context.OutputPath);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available.
|
||||
|
|
|
|||
|
|
@ -220,6 +220,90 @@ namespace Microsoft.Extensions.ApiDescription.Tool
|
|||
internal static string FormatMissingEntryPoint(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MissingEntryPoint"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find service type '{0}' in loaded assemblies.
|
||||
/// </summary>
|
||||
internal static string ServiceTypeNotFound
|
||||
{
|
||||
get => GetString("ServiceTypeNotFound");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find service type '{0}' in loaded assemblies.
|
||||
/// </summary>
|
||||
internal static string FormatServiceTypeNotFound(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceTypeNotFound"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find method named '{0}' in '{1}' implementation.
|
||||
/// </summary>
|
||||
internal static string MethodNotFound
|
||||
{
|
||||
get => GetString("MethodNotFound");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find method named '{0}' in '{1}' implementation.
|
||||
/// </summary>
|
||||
internal static string FormatMethodNotFound(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodNotFound"), p0, p1);
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find service of type '{0}' in dependency injection container.
|
||||
/// </summary>
|
||||
internal static string ServiceNotFound
|
||||
{
|
||||
get => GetString("ServiceNotFound");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to find service of type '{0}' in dependency injection container.
|
||||
/// </summary>
|
||||
internal static string FormatServiceNotFound(object p0)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceNotFound"), p0);
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.
|
||||
/// </summary>
|
||||
internal static string MethodReturnedNull
|
||||
{
|
||||
get => GetString("MethodReturnedNull");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.
|
||||
/// </summary>
|
||||
internal static string FormatMethodReturnedNull(object p0, object p1, object p2)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodReturnedNull"), p0, p1, p2);
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.
|
||||
/// </summary>
|
||||
internal static string MethodReturnTypeUnsupported
|
||||
{
|
||||
get => GetString("MethodReturnTypeUnsupported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.
|
||||
/// </summary>
|
||||
internal static string FormatMethodReturnTypeUnsupported(object p0, object p1, object p2, object p3)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodReturnTypeUnsupported"), p0, p1, p2, p3);
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.
|
||||
/// </summary>
|
||||
internal static string MethodTimedOut
|
||||
{
|
||||
get => GetString("MethodTimedOut");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.
|
||||
/// </summary>
|
||||
internal static string FormatMethodTimedOut(object p0, object p1, object p2)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodTimedOut"), p0, p1, p2);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -162,4 +162,22 @@
|
|||
<data name="MissingEntryPoint" xml:space="preserve">
|
||||
<value>Assembly '{0}' does not contain an entry point.</value>
|
||||
</data>
|
||||
<data name="ServiceTypeNotFound" xml:space="preserve">
|
||||
<value>Unable to find service type '{0}' in loaded assemblies.</value>
|
||||
</data>
|
||||
<data name="MethodNotFound" xml:space="preserve">
|
||||
<value>Unable to find method named '{0}' in '{1}' implementation.</value>
|
||||
</data>
|
||||
<data name="ServiceNotFound" xml:space="preserve">
|
||||
<value>Unable to find service of type '{0}' in dependency injection container.</value>
|
||||
</data>
|
||||
<data name="MethodReturnedNull" xml:space="preserve">
|
||||
<value>Method '{0}' of service '{1}' returned null. Must return a non-null '{2}'.</value>
|
||||
</data>
|
||||
<data name="MethodReturnTypeUnsupported" xml:space="preserve">
|
||||
<value>Method '{0}' of service '{1}' has unsupported return type '{2}'. Must return a '{3}'.</value>
|
||||
</data>
|
||||
<data name="MethodTimedOut" xml:space="preserve">
|
||||
<value>Method '{0}' of service '{1}' timed out. Must complete execution within {2} minute.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
<DocumentPath />
|
||||
<!--
|
||||
Method Default document generator should invoke on the %(Service) to generate document.
|
||||
Default is set in server project, falling back to "Generate".
|
||||
Default is set in server project, falling back to "GenerateAsync".
|
||||
-->
|
||||
<Method />
|
||||
<!--
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool
|
|||
=> GetString("OutputDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set.
|
||||
/// Unable to retrieve '{0}' project metadata. Ensure '$({1})' is set.
|
||||
/// </summary>
|
||||
internal static string GetMetadataValueFailed
|
||||
{
|
||||
|
|
@ -313,7 +313,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set.
|
||||
/// Unable to retrieve '{0}' project metadata. Ensure '$({1})' is set.
|
||||
/// </summary>
|
||||
internal static string FormatGetMetadataValueFailed(object p0, object p1)
|
||||
=> string.Format(CultureInfo.CurrentCulture, GetString("GetMetadataValueFailed"), p0, p1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue