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

Could not find a base address that matches scheme https for the endpoint with binding WebHttpBinding. Registered base address schemes are [http]. #659

Open
alexey-kostylev opened this issue May 10, 2022 · 9 comments
Labels
enhancement New feature or request Triaged
Milestone

Comments

@alexey-kostylev
Copy link

Hi guys,
I'm runningCoreWcf service in azure as a WebApp and getting this exception in azure console:
Unhandled exception. System.InvalidOperationException: Could not find a base address that matches scheme https for the endpoint with binding WebHttpBinding. Registered base address schemes are [http].
at CoreWCF.ServiceHostBase.MakeAbsoluteUri(Uri relativeOrAbsoluteUri, Binding binding, UriSchemeKeyedCollection baseAddresses)
at CoreWCF.Description.DispatcherBuilder.BuildDispatcher[TService](ServiceConfiguration1 serviceConfig, IServiceProvider services) at CoreWCF.Configuration.ServiceConfiguration1.GetDispatchers()
at CoreWCF.Configuration.DispatcherBuilderImpl.BuildDispatchers(Type serviceType)
at CoreWCF.Channels.ServiceModelHttpMiddleware.BuildBranch()
at CoreWCF.Channels.ServiceModelHttpMiddleware.EnsureBranchBuilt()
at CoreWCF.Channels.ServiceModelHttpMiddleware.ServiceBuilderOpenedCallback(Object sender, EventArgs e)
at System.EventHandler.Invoke(Object sender, EventArgs e)
at CoreWCF.Channels.CommunicationObject.OnOpened()
--- End of stack trace from previous location ---
at CoreWCF.Configuration.WrappingIServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)

I use the following configuration:
`public static void ConfigureCoreWcfApp(this IApplicationBuilder app)
{
app.UseServiceModel(builder =>
{
var readerQuoates = new XmlDictionaryReaderQuotas
{
MaxBytesPerRead = 4096,
MaxDepth = 32,
MaxArrayLength = 16384,
MaxStringContentLength = 16384,
MaxNameTableCharCount = 16384
};

            builder.AddService<PSService>();
            builder.AddServiceWebEndpoint<PSService, IPSService>(
                new WebHttpBinding()
            , "rest", behavior =>
            {
                behavior.HelpEnabled = true;
                behavior.AutomaticFormatSelectionEnabled = true;
            });

            builder.AddServiceWebEndpoint<PSService, IPSService>(
                new WebHttpBinding(WebHttpSecurityMode.Transport)
                , "rest", behavior =>
                {
                    behavior.HelpEnabled = true;
                    behavior.AutomaticFormatSelectionEnabled = true;
                });
                builder.AddServiceEndpoint<PSService, IPSService>(
                    new BasicHttpBinding(), "soap"
                );
        });

        var serviceMetadataBehavior = app.ApplicationServices.GetRequiredService<CoreWCF.Description.ServiceMetadataBehavior>();
        serviceMetadataBehavior.HttpGetEnabled = true;
        serviceMetadataBehavior.HttpsGetEnabled = true;
    }

    public static void ConfigureCoreWcf(this IWebHostBuilder webBuilder)
    {
        webBuilder.ConfigureKestrel(serverOptions =>
        {
            serverOptions.AllowSynchronousIO = true;
        });
    }`

.NET 5, CoreWcf 1.0.1 Locally it works smoothly on https://localhost:5001/rest or soap

@allderidge
Copy link

It looks like your remote server hasn't got HTTPS enabled and CoreWcf 1.0.0 now cares that your binding is asking for a secure transport with the code WebHttpSecurityMode.Transport. It tries to find a HTTPS base address that the server exposes and then throws that exception as the server is only exposing a HTTP address.

I've fixed this kind of issue with some 'hacky' code that makes CoreWcf think both http and https schemes are available. Take a look at the related issue below.

I've raised a related issue #663

@allderidge
Copy link

I've tested a CoreWcf based service hosted with a linux App Service Plan in Azure and the host does not start with a HTTPS endpoint (note the actual Azure service exposes a HTTPS endpoint but the Kestral host does not). With the fix/hack in #663 the wsdl ports illustrate this:

<wsdl:port name="BasicHttpBinding_ServiceName" binding="tns:BasicHttpBinding_ServiceName">
<soap:address location="http://[::]:8080/ServiceName"/>
</wsdl:port>
<wsdl:port name="BasicHttpBinding_ServiceName1" binding="tns:BasicHttpBinding_ServiceName1">
<soap:address location="https://[::]:0/soap/ServiceName.svc"/>
</wsdl:port>

HTTPS has a 0 port as the fix added it back in a one of the base addresses. This would suggest it is impossible to expose HTTPS based binding in an Azure App Service without a fix. Potentially a Windows/IIS based service plan would work.

@mconnew
Copy link
Member

mconnew commented May 12, 2022

Hosting in the cloud is a common scenario where https offload is reasonably common. The workaround to modify the wsdl is a little ugly and requires way too much code so I think this deserves being a feature to simply tell CoreWCF that SSL offload is happening and to advertise it as https even though it's http.

@mconnew mconnew added enhancement New feature or request Triaged labels May 12, 2022
@mconnew mconnew added this to the 1.x Servicing milestone May 12, 2022
@seciq
Copy link

seciq commented Mar 31, 2023

Thx @allderidge.

The hack worked for me. I do have an asp.net (core) 7.0 service packaged in a docker container and hosted in Azure Container Apps. The container expose port 8080 (http) and the Envoy proxy terminates the TLS.

I was able to get the service working on both HTTP and HTTPS using but the generated wsdl has an ugly <soap:address location="http://[::]:8080/Service.svc"/>.

app.UseForwardedHeaders();

...

app.UseServiceModel(serviceBuilder =>
{
    var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();

    serviceMetadataBehavior.HttpGetEnabled = true;
    serviceMetadataBehavior.HttpsGetEnabled = true;
    
    serviceBuilder
        .AddService<MySampleService>()
        .AddServiceEndpoint<MySampleService, IService>(new BasicHttpBinding(), "http://[::]:8080/Service.svc")
        .AddServiceEndpoint<MySampleService, IService>(new BasicHttpBinding(BasicHttpSecurityMode.Transport), "https://[::]:0/Service.svc");
});

If I follow the basic sample and use the AddService<T> with additional base addresses everything works as expected (https:// behind reverse proxy with the container exposing only the http://).

const string WSDL_HOST= "mydomain.com";
...

app.UseForwardedHeaders();

...

app.UseServiceModel(serviceBuilder =>
{
    var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();

    serviceMetadataBehavior.HttpGetEnabled = true;
    serviceMetadataBehavior.HttpsGetEnabled = true;

    serviceBuilder
        .AddService<MySampleService>(serviceOptions =>
        {
            serviceOptions.BaseAddresses.Add(new Uri($"http://{WSDL_HOST}"));
            serviceOptions.BaseAddresses.Add(new Uri($"https://{WSDL_HOST}"));
        })
        .AddServiceEndpoint<MySampleService, IService>(new BasicHttpBinding(), "/Service.svc")
        .AddServiceEndpoint<MySampleService, IService>(new BasicHttpBinding(BasicHttpSecurityMode.Transport), "/Service.svc");
});

The generated WSDL has now the correct address: <soap:address location="https://mydomain.com/Service.svc"/>

@pjt33
Copy link

pjt33 commented Jun 21, 2024

I had the same issue with IIS as the server host, because it starts Kestrel and apparently (warning: speculation) doesn't pass through the external address in the way that Kestrel expects. The workaround which works for me, and which might also work in Linux Azure hosting contexts, is to put the base address in appsettings.json and configure it explicitly.

appsettings.json:

{
  "AppSettings": {
    "WebRoot": "https://example.com/",
    ...

Startup code:

        var builder = WebApplication.CreateBuilder(args);

        ...

        // WCF
        var app = builder.Build();

        // HACK to work around failure to properly integrate with IIS
        var server = app.Services.GetService<IServer>();
        var serverAddresses = new ServerAddressesFeature();
        serverAddresses.Addresses.Add(builder.Configuration.GetValue<string>("AppSettings:WebRoot"));
        server.Features.Set<IServerAddressesFeature>(serverAddresses);

@mconnew
Copy link
Member

mconnew commented Jun 24, 2024

I've recently done an investigation into an issue around Azure Linux App Service hosting. The problem is because Azure do some tricks under the hood in their hosting, but they don't do a complete job of it. They configure Kestrel to listen on HTTP (no SSL). The actual endpoint clients talk to are a reverse proxy which handles the SSL negotiation, and it forwards the request over HTTP to your app. But because the request originally came in over HTTPS, they fix up the HttpRequest to make it look like it's an HTTPS request. They should have fixed up the listen url's in the WebHost to reflect the external url's as they are saying they are only listening on HTTP, but presenting HTTPS requests, and there's breaking the CoreWCF logic. I did work out a simple workaround though. You configure CoreWCF as though it's accepting HTTPS request (e.g. BasicHttpBinding with security mode of Transport to trigger use of SSL), and then you override the base addresses for your service to have an https address. By default we copy over the addresses from IServerAddressesFeature, which as mentioned won't match. The trick is to clear all the base addresses before adding the new one:

    serviceBuilder.AddService<MyService>(serviceOptions =>
    {
        serviceOptions.BaseAddresses.Clear();
        serviceOptions.BaseAddresses.Add(new Uri("https://localhost/"));
    });

CoreWCF doesn't care about the hostname or the port number when setting up the listeners, it just matches on the scheme (http vs https). If you want a different hostname to appear in the WSDL, you can put that hostname in here.

Hopefully this helps.

@Havunen
Copy link

Havunen commented Sep 9, 2024

Did anybody get this working in IIS configuration where the WCF service is hosted in sub path?

image

@mconnew
Copy link
Member

mconnew commented Sep 11, 2024

@Havunen, what exception are you getting?

@Havunen
Copy link

Havunen commented Sep 11, 2024

The server responds bad request 400 and nothing else.
I later found that there is already issue for that: #741

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Triaged
Projects
None yet
Development

No branches or pull requests

6 participants