Skip to content

Remove dynamic WebAPI interfaces - #1652

Merged
xPaw merged 1 commit into
masterfrom
remove-dynamic
Nov 2, 2026
Merged

xPaw merged 1 commit into
masterfrom
remove-dynamic

Conversation

@xPaw

@xPaw xPaw commented Oct 25, 2026

Copy link
Copy Markdown
Member

Remove dynamic WebAPI interfaces

Closes #1434.

WebAPI.Interface and WebAPI.AsyncInterface no longer derive from DynamicObject. Use Call / CallAsync / CallProtobufAsync. Factories are unchanged.

List arguments are now flattened to name[0], name[1]… by the typed calls too (previously dynamic only).

If #1651 lands first, this PR will also drop the DynamicObject IL3050 suppressions and re-enable PublishAot for sample 021.

Breaking changes

Calls through dynamic still compile but throw RuntimeBinderException at runtime.

// before
dynamic iface = WebAPI.GetInterface( "ISteamNews" );
KeyValue news = iface.GetNewsForApp2( appid: 440, method: HttpMethod.Post );

// after
var iface = WebAPI.GetAsyncInterface( "ISteamNews" );
KeyValue news = await iface.CallAsync( HttpMethod.Post, "GetNewsForApp", 2, new() { [ "appid" ] = 440 } );

The version suffix becomes the version argument, and method: becomes the first argument.

Usage

About 31 of SteamKit's 918 GitHub dependents call through dynamic, mostly stale SteamBot forks and small bots. Nearly all pin SteamKit2 1.x or 2.x; only two are on 3.x. Projects that already use CallAsync, such as ArchiSteamFarm, are unaffected.

[ "appid" ] = "440"
};

KeyValue results = steamNews.Call( "GetNewsForApp", /* version */ 1, newsArgs );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this the last usage of .Call in our own code?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

internal readonly string iface;
internal readonly string apiKey;

[GeneratedRegex( @"(?<name>[a-zA-Z]+)(?<version>[0-9]*)" )]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think WebAPI has to be partial anymore, it was only for this source generator.

foreach ( var (argName, argValue) in methodArgs )
{
// method is a reserved param for selecting the http request method
if ( argName.Equals( "method", StringComparison.OrdinalIgnoreCase ) )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"method" used to be a magic key, now it looks like it gets treated like any other arg and shoved in the query string. This will be a breaking change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was only magic in TryInvokeMember.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if someone is converting from dynamic they may trip up on this, if they weren't using dynamic then no change.

that's probably just something to call out in the release notes then.

@xPaw
xPaw merged commit 1ea0e94 into master Nov 2, 2026
17 checks passed
@xPaw
xPaw deleted the remove-dynamic branch November 2, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Usage of dynamic in WebAPI

2 participants