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:
Doug Bunting 2018-10-27 16:53:19 -07:00 committed by GitHub
commit 0cea1b2a5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 182 additions and 30 deletions

View File

@ -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(),
};

View File

@ -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; }
}

View File

@ -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.

View File

@ -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);

View File

@ -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>

View File

@ -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 />
<!--

View File

@ -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);