Skip to content

Commit

Permalink
Move HostAbortedException to Abstractions (#70205)
Browse files Browse the repository at this point in the history
* Move HostAbortedException to Abstractions

 HostAbortedException was added directly to Microsoft.Extensions.Hosting, which depends on a lot of other libraries. This causes problems when using the HostFactoryResolver.Sources package because now consumers of HostFactoryResolver need to reference the whole Hosting package and all of its dependencies.

 Fix this by moving the new exception to the Hosting.Abstractions library, which has a minimal set of dependencies.

* Remove direct dependency from HostFactoryResolver on Microsoft.Extensions.Hosting assemblies.

Load the HostAbortedException using Reflection instead. If it can't be found, throw a private exception with the same name.
  • Loading branch information
eerhardt authored Jun 6, 2022
1 parent 2b21dcd commit 542bcf4
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ VisualStudioVersion = 17.2.32516.85
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HostFactoryResolver.Sources", "src\Microsoft.Extensions.HostFactoryResolver.Sources.csproj", "{317C456F-8F26-4441-93F7-9042B0DC7119}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{549715BC-A4E3-49F5-A8AC-84D2F65FAC0F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{41A601F5-19D8-45A9-AE63-33F040315BA6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.HostFactoryResolver.Tests", "tests\Microsoft.Extensions.HostFactoryResolver.Tests.csproj", "{16B58903-715A-467B-B1E4-284CF285394D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -15,10 +21,18 @@ Global
{317C456F-8F26-4441-93F7-9042B0DC7119}.Debug|Any CPU.Build.0 = Debug|Any CPU
{317C456F-8F26-4441-93F7-9042B0DC7119}.Release|Any CPU.ActiveCfg = Release|Any CPU
{317C456F-8F26-4441-93F7-9042B0DC7119}.Release|Any CPU.Build.0 = Release|Any CPU
{16B58903-715A-467B-B1E4-284CF285394D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16B58903-715A-467B-B1E4-284CF285394D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16B58903-715A-467B-B1E4-284CF285394D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16B58903-715A-467B-B1E4-284CF285394D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{317C456F-8F26-4441-93F7-9042B0DC7119} = {549715BC-A4E3-49F5-A8AC-84D2F65FAC0F}
{16B58903-715A-467B-B1E4-284CF285394D} = {41A601F5-19D8-45A9-AE63-33F040315BA6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {80C3C947-5A43-4A55-9E1C-D62738588863}
EndGlobalSection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public object CreateHost()
// build to throw
_hostTcs.TrySetException(new InvalidOperationException("The entry point exited without ever building an IHost."));
}
catch (TargetInvocationException tie) when (tie.InnerException is HostAbortedException)
catch (TargetInvocationException tie) when (tie.InnerException?.GetType().Name == "HostAbortedException")
{
// The host was stopped by our own logic
}
Expand Down Expand Up @@ -341,10 +341,30 @@ public void OnNext(KeyValuePair<string, object?> value)
if (_stopApplication)
{
// Stop the host from running further
throw new HostAbortedException();
ThrowHostAborted();
}
}
}

// HostFactoryResolver is used by tools that explicitly don't want to reference Microsoft.Extensions.Hosting assemblies.
// So don't depend on the public HostAbortedException directly. Instead, load the exception type dynamically if it can
// be found. If it can't (possibly because the app is using an older version), throw a private exception with the same name.
private void ThrowHostAborted()
{
Type? publicHostAbortedExceptionType = Type.GetType("Microsoft.Extensions.Hosting.HostAbortedException, Microsoft.Extensions.Hosting.Abstractions", throwOnError: false);
if (publicHostAbortedExceptionType != null)
{
throw (Exception)Activator.CreateInstance(publicHostAbortedExceptionType)!;
}
else
{
throw new HostAbortedException();
}
}

private sealed class HostAbortedException : Exception
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public static partial class Environments
public static readonly string Production;
public static readonly string Staging;
}
public sealed partial class HostAbortedException : System.Exception
{
public HostAbortedException() { }
public HostAbortedException(string? message) { }
public HostAbortedException(string? message, System.Exception? innerException) { }
}
public partial class HostBuilderContext
{
public HostBuilderContext(System.Collections.Generic.IDictionary<object, object> properties) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="HostAbortedExceptionMessage" xml:space="preserve">
<value>The host was aborted.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ public static partial class Host
public static Microsoft.Extensions.Hosting.IHostBuilder CreateDefaultBuilder() { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder CreateDefaultBuilder(string[]? args) { throw null; }
}
public sealed partial class HostAbortedException : System.Exception
{
public HostAbortedException() { }
public HostAbortedException(string? message) { }
public HostAbortedException(string? message, System.Exception? innerException) { }
}
public sealed partial class HostApplicationBuilder
{
public HostApplicationBuilder() { }
Expand Down Expand Up @@ -80,25 +74,25 @@ public static partial class HostingHostBuilderExtensions
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.HostBuilderContext, Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureLogging(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Logging.ILoggingBuilder> configureLogging) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder ConfigureServices(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> configureDelegate) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static System.Threading.Tasks.Task RunConsoleAsync(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> configureOptions, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static System.Threading.Tasks.Task RunConsoleAsync(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static Microsoft.Extensions.Hosting.IHostBuilder UseConsoleLifetime(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public static Microsoft.Extensions.Hosting.IHostBuilder UseConsoleLifetime(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> configureOptions) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder UseContentRoot(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, string contentRoot) { throw null; }
public static Microsoft.Extensions.Hosting.IHostBuilder UseDefaultServiceProvider(this Microsoft.Extensions.Hosting.IHostBuilder hostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.ServiceProviderOptions> configure) { throw null; }
Expand All @@ -124,10 +118,10 @@ public void NotifyStarted() { }
public void NotifyStopped() { }
public void StopApplication() { }
}
[System.Runtime.Versioning.UnsupportedOSPlatform("android")]
[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatform("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")]
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")]
public partial class ConsoleLifetime : Microsoft.Extensions.Hosting.IHostLifetime, System.IDisposable
{
public ConsoleLifetime(Microsoft.Extensions.Options.IOptions<Microsoft.Extensions.Hosting.ConsoleLifetimeOptions> options, Microsoft.Extensions.Hosting.IHostEnvironment environment, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime, Microsoft.Extensions.Options.IOptions<Microsoft.Extensions.Hosting.HostOptions> hostOptions) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@
<data name="EnvironmentNameChangeNotSupoprted" xml:space="preserve">
<value>The environment name changed from "{0}" to "{1}". Changing host configuration is not supported.</value>
</data>
<data name="HostAbortedExceptionMessage" xml:space="preserve">
<value>The host was aborted.</value>
</data>
<data name="IHostApplicationLifetimeReplacementNotSupported" xml:space="preserve">
<value>Replacing IHostApplicationLifetime is not supported.</value>
</data>
Expand Down

0 comments on commit 542bcf4

Please sign in to comment.