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

Invalid Cast Exception when using Subscriptions #586

Open
adlartuten opened this issue Aug 3, 2023 · 2 comments
Open

Invalid Cast Exception when using Subscriptions #586

adlartuten opened this issue Aug 3, 2023 · 2 comments

Comments

@adlartuten
Copy link

I have been running into System.InvalidCastException when trying to set up a GraphQL subscription. I have tracked the error occuring to line 318 of GraphQLHttpWebSocket in the repo:

var certs = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates;

I am using .NET Maui and am not entirely sure if I am doing something wrong or if it is a MAUI or repo issue.

@rose-a
Copy link
Collaborator

rose-a commented Aug 3, 2023

We've seen limitations at this point before (in earlier cases with WASM, see https://github.com/graphql-dotnet/graphql-client#blazor-webassembly-limitations).

Could you try to find out what type Options.HttpMessageHandler actually is in your app (because it obviously isn't of type HttpClientHandler or derived from it)?

@adlartuten
Copy link
Author

Ah, I definitely see my issue here now. My MessageHandler is a custom class in order to get around SSL when using the Android emulator for testing. It was the best solution I found for MAUI testing when connecting to localhost:
dotnet/maui#8131
https://gist.github.com/Eilon/49e3c5216abfa3eba81e453d45cba2d4

The code I'm using looks like this:

public GraphQLHttpClient Client { get; set; }

var options = new GraphQLHttpClientOptions { HttpMessageHandler = GetInsecureHandler(), EndPoint = new Uri(endpoint) };
Client = new GraphQLHttpClient(options, new NewtonsoftJsonSerializer());

public HttpMessageHandler GetInsecureHandler()
{
    var handler = new CustomAndroidMessageHandler();
    handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
    {
        if (cert.Issuer.Equals("CN=localhost")) return true;
        return errors == System.Net.Security.SslPolicyErrors.None;
    };
    return handler;
}

internal sealed class CustomAndroidMessageHandler : Xamarin.Android.Net.AndroidMessageHandler
{
    protected override Javax.Net.Ssl.IHostnameVerifier GetSSLHostnameVerifier(Javax.Net.Ssl.HttpsURLConnection connection)
        => new CustomHostnameVerifier();

    private sealed class CustomHostnameVerifier : Java.Lang.Object, Javax.Net.Ssl.IHostnameVerifier
    {
        public bool Verify(string? hostname, Javax.Net.Ssl.ISSLSession? session)
        {
            return
                Javax.Net.Ssl.HttpsURLConnection.DefaultHostnameVerifier.Verify(hostname, session)
                || hostname == "10.0.2.2" && session.PeerPrincipal?.Name == "CN=localhost";
        }
    }
}

I am honestly not very familiar with SSL connections and backend development in general, could this solution be modified to be compatible? Or would the better option just be to somehow get a valid SSL certificate set up on the Android emulator?

Thank you so much for your patience and help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants