Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider using a Feature Switch for CFNetworkHandler and NSUrlSessionHandler #14298

Open
eerhardt opened this issue Mar 3, 2022 · 8 comments
Labels
app-size dotnet An issue or pull request related to .NET (6) enhancement The issue or pull request is an enhancement good first issue This is a good first issue for someone to start working with our code
Milestone

Comments

@eerhardt
Copy link
Contributor

eerhardt commented Mar 3, 2022

In .NET 5 we introduced the concept of a "Feature Switch". This allows .NET apps to change behavior by setting switches at build/publish time. It also allows for the trimmer to remove unused code based on the switch setting.

You can see the current list of Feature Switches the .NET Runtime has for ideas on how these work.

Today, we have code that reads which HttpMessageHandler (CFNetworkHandler or NSUrlSessionHandler) to use at runtime based on a setting in a Resource NSDictionary:

internal static RuntimeOptions Read ()
{
// for iOS NSBundle.ResourcePath returns the path to the root of the app bundle
// for macOS apps NSBundle.ResourcePath returns foo.app/Contents/Resources
// for macOS frameworks NSBundle.ResourcePath returns foo.app/Versions/Current/Resources
Class bundle_finder = new Class (typeof (NSObject.NSObject_Disposer));
var resource_dir = NSBundle.FromClass (bundle_finder).ResourcePath;
var plist_path = GetFileName (resource_dir);
if (!File.Exists (plist_path))
return null;
using (var plist = NSDictionary.FromFile (plist_path)) {
var options = new RuntimeOptions ();
options.http_message_handler = (NSString) plist ["HttpMessageHandler"];
return options;
}
}
internal static HttpMessageHandler GetHttpMessageHandler ()
{
var options = RuntimeOptions.Read ();
// all types will be present as this is executed only when the linker is not enabled
var handler_name = options?.http_message_handler;
#if NET
switch (handler_name) {
case CFNetworkHandlerValue:
return new CFNetworkHandler ();
case SocketsHandlerValue:
return new SocketsHttpHandler ();
default:
if (handler_name != null && handler_name != NSUrlSessionHandlerValue)
Runtime.NSLog ($"{handler_name} is not a valid HttpMessageHandler, defaulting to System.Net.Http.NSUrlSessionHandlerValue");
return new NSUrlSessionHandler ();

This has the following disadvantages:

  1. No matter which one is picked, they are both always compiled into the application. Using a feature switch would allow us to trim the unused implementation.
  2. It is inconsistent from a user's perspective on how to configure the HttpMessageHandler in their application. If they want to use the SocketsHttpHandler that is built into .NET, they need to set the UseNativeHttpHandler MSBuild property to false in their .csproj. But if they want to switch between CFNetworkHandler or NSUrlSessionHandler, they need to set this setting in the resource file. Using a feature switch here would make it a consistent experience with the built-in .NET SocketsHttpHandler.

cc @rolfbjarne

@rolfbjarne rolfbjarne added this to the .NET 6 milestone Mar 3, 2022
@rolfbjarne rolfbjarne added dotnet An issue or pull request related to .NET (6) dotnet-pri3 .NET 6: wishlist for stable release labels Mar 3, 2022
@rolfbjarne rolfbjarne modified the milestones: .NET 6, .NET 7 Mar 25, 2022
@rolfbjarne rolfbjarne added enhancement The issue or pull request is an enhancement and removed dotnet-pri3 .NET 6: wishlist for stable release labels Mar 25, 2022
@rolfbjarne rolfbjarne modified the milestones: .NET 7, .NET 8 Aug 26, 2022
@rolfbjarne rolfbjarne modified the milestones: .NET 8, .NET 9 Sep 11, 2023
@rolfbjarne rolfbjarne added the good first issue This is a good first issue for someone to start working with our code label Sep 11, 2023
@Agnik7
Copy link

Agnik7 commented Sep 11, 2023

Hi, I would like to work on this issue. Requesting the maintainers to kindly assign the issue to me

@rolfbjarne
Copy link
Member

@Agnik7 done!

Feel free to ask any questions, either here, or in our Discord channel (https://discord.com/channels/732297728826277939/732297808148824115)

@Agnik7
Copy link

Agnik7 commented Sep 11, 2023

Thanks a lot @rolfbjarne !! Sure, I'll ask whenever I need help

@Agnik7
Copy link

Agnik7 commented Sep 11, 2023

Hi @rolfbjarne , I am new to open-source and contributing. It will be really appreciated if you could kindly guide me as to which file(s) needs to be updated, and give a basic idea about how to update them. Eagerly waiting for your guidance at the earliest. Thank you!!!

@rolfbjarne
Copy link
Member

The idea would be to:

  1. Add two internal static bool properties in ObjCRuntime.Runtime, named "UseCFNetworkHandler" and "UseNSUrlSessionHandler" around here:

  2. Compute the values for these two properties:

    <_IsCFNetworkHandlerFeature Condition="'$(UseNativeHttpHandler)' == 'true' And '$(MtouchHttpClientHandler)' == 'CFNetworkHandler'">true</_IsCFNetworkHandlerFeature>
    <_IsCFNetworkHandlerFeature Condition="'$(_IsCFNetworkHandlerFeature)' == ''">false</_IsCFNetworkHandlerFeature>
    <_IsNSUrlSessionHandlerFeature Condition="'$(UseNativeHttpHandler)' == 'true' And '$(MtouchHttpClientHandler)' == 'NSUrlSessionHandler'">true</_IsNSUrlSessionHandlerFeature>
    <_IsNSUrlSessionHandlerFeature Condition="'$(_IsNSUrlSessionHandlerFeature)' == ''">false</_IsNSUrlSessionHandlerFeature>

    at the end here (note this is from the net8.0 branch):

    <PropertyGroup>
    <!-- Set linker feature flags for device/simulator builds -->
    <_IsSimulatorFeature Condition="('$(_PlatformName)' == 'iOS' Or '$(_PlatformName)' == 'tvOS') And '$(_SdkIsSimulator)' == 'true'">true</_IsSimulatorFeature>
    <_IsSimulatorFeature Condition="'$(_IsSimulatorFeature)' == ''">false</_IsSimulatorFeature>
    <!-- Set managed static registrar value -->
    <_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' == 'managed-static'">true</_IsManagedStaticRegistrarFeature>
    <_IsManagedStaticRegistrarFeature Condition="'$(Registrar)' != 'managed-static'">false</_IsManagedStaticRegistrarFeature>
    <!-- Set NativeAOT value -->
    <_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' == 'NativeAOT'">true</_IsNativeAOTFeature>
    <_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' != 'NativeAOT'">false</_IsNativeAOTFeature>
    </PropertyGroup>

  3. Add two new RuntimeHostConfigurationOption entries here (note this is from the net8.0 branch):

    <RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsNativeAOT" Value="$(_IsNativeAOTFeature)" Trim="true" />

    Something like this:

    <RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.UseCFNetworkHandler" Value="$(_IsCFNetworkHandlerFeature)" Trim="true" />
    <RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.UseNSUrlSessionHandler" Value="$(_IsNSUrlSessionHandlerFeature)" Trim="true" />
  4. Rework the code in this file to use the two new Runtime properties instead of reading from a file:

    https://github.com/xamarin/xamarin-macios/blob/net8.0/src/ObjCRuntime/RuntimeOptions.cs

Note: these changes must be done for `#if NET" only.

@Agnik7
Copy link

Agnik7 commented Sep 12, 2023

Ok, so I need to make the changes in the net8.0 branch right?

@rolfbjarne
Copy link
Member

Yes.

@Agnik7
Copy link

Agnik7 commented Sep 12, 2023

@rolfbjarne I have created a PR #19003 , where I have tried to implemented your valuable guidance. Kindly review it, and do tell me if there are any changes to be made or not. Thanks a lot!!

@rolfbjarne rolfbjarne modified the milestones: .NET 9, .NET 10 Sep 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app-size dotnet An issue or pull request related to .NET (6) enhancement The issue or pull request is an enhancement good first issue This is a good first issue for someone to start working with our code
Projects
None yet
Development

No branches or pull requests

3 participants