Search code examples
c#asp.net-core-mvcweb-hostingdotnet-httpclientasp.net-core-3.1

1and1 restricts request to another server using ASP.NET CORE


I am trying to make a request to Paypal endpoint via SDK in my .NET Core application. The request works on local server just fine. But when I pulished the application on 1and1 hosting server, I get this error.

A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

The reason I found out is that 1and1 doesn't allow direct calls so I need to use proxy. Some people have asked the same question already. But there is no real answer for me.

Here are two of them:

I also did contact 1and1 for support (2x times). They sent me the same link (in german) which I have already found and tried. No success.

Here are some senairos, that I have tried:

1. Add proxy server to web.config file

My config file looks something like this

<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath=".\MyApp.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
    </system.webServer>
  </location>
  <system.net>
    <defaultProxy>
        <proxy  proxyaddress="http://1and1proxy:123"
                bypassonlocal="true"/>
    </defaultProxy>
  </system.net>
</configuration>

2. Add AspNetCore.Proxy to startup.cs file

 public void ConfigureServices(IServiceCollection services) {
  ...
  services.AddProxies();
  ...
 }

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
  ...
  app.RunProxy(proxy => proxy.UseHttp("http://1and1proxy:123"));
  ...
 }

3. Make another simple request to another server (using webproxy but also failed)

public async Task < IActionResult > callingGet() {
 var proxiedHttpClientHandler = new HttpClientHandler() {
  UseProxy = true
 };
 proxiedHttpClientHandler.Proxy = new WebProxy("http://1and1proxy:123");
 HttpClient client = new HttpClient(proxiedHttpClientHandler);
 using
 var client = new HttpClient();
 var result = await client.GetAsync("https://reqres.in/api/users/2");
 return View(new Model {
  Message = result.ToString()
 });
}

Did I miss something here or do I have to switch to another provider? PS: this is my first time publishing a website


Solution

  • It turns out that the third did work (but I still don't know why the first and second one do not).

    So I created an issue on GitHub page to ask if there is any option for me to create a proxy while calling request to PayPal service. I've got no response from any SDK's developers but a member, who had the same request. He had to create on his own this option, because there is no official way to set proxy using PayPal .Net SDK yet. So I am going to repost his answer here. I think it could help someone. Thanks to WSSC-Jonathan again.

    using System;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Reflection;
    using PayPalCheckoutSdk.Core;
    namespace MongMi.Application.Paypal
    {
        public class ProxiedPayPalHttpClient : PayPalHttp.HttpClient
        {
            private WebProxy _proxy;
            private PayPalEnvironment _environment;
    
            private PayPalHttp.IInjector _gzipInjector;
            private PayPalHttp.IInjector _authInjector;
    
            public ProxiedPayPalHttpClient(PayPalEnvironment environment, WebProxy proxy)
                : base(environment)
            {
                _environment = environment;
                _proxy = proxy;
    
                OverrideClient();
                SetupInjectors();
            }
    
            public ProxiedPayPalHttpClient(PayPalEnvironment environment, string url, string username = "", string password = "")
                : base(environment)
            {
                _environment = environment;
                _proxy = SetupProxy(url, username, password);
    
                OverrideClient();
                SetupInjectors();
            }
    
            public WebProxy SetupProxy(string url, string username, string password)
            {
                var proxy = new WebProxy(url)
                {
                    BypassProxyOnLocal = true,
                    UseDefaultCredentials = true
                };
    
                if (!string.IsNullOrEmpty(username) || !string.IsNullOrEmpty(password))
                    proxy.Credentials = new NetworkCredential(username, password);
    
                return proxy;
            }
    
            private void OverrideClient()
            {
                var handler = new HttpClientHandler
                {
                    Proxy = _proxy
                };
    
                var client = new HttpClient(handler, true) { BaseAddress = new Uri(environment.BaseUrl()) };
                client.DefaultRequestHeaders.Add("User-Agent", GetUserAgent());
    
                SetClient(client);
            }
    
            private void SetupInjectors()
            {
                _gzipInjector = new GzipInjector();
                _authInjector = new AuthorizationInjector(_proxy, _environment);
    
                AddInjector(_gzipInjector);
                AddInjector(_authInjector);
            }
    
            protected void SetClient(HttpClient client)
            {
                var type = GetType();
    
                while (type != null)
                {
                    var field = type.GetField("client", BindingFlags.Instance | BindingFlags.NonPublic);
    
                    if (field != null)
                    {
                        field.SetValue(this, client);
                        break;
                    }
    
                    type = type.BaseType;
                }
            }
    
            private class AuthorizationInjector : PayPalHttp.IInjector
            {
                private WebProxy _proxy;
                private PayPalEnvironment _environment;
    
                private AccessToken _accessToken;
    
                public AuthorizationInjector(WebProxy proxy, PayPalEnvironment environment)
                {
                    _environment = environment;
                    _proxy = proxy;
                }
    
                public void Inject(PayPalHttp.HttpRequest request)
                {
                    if (!request.Headers.Contains("Authorization") && !(request is AccessTokenRequest || request is RefreshTokenRequest))
                    {
                        if (_accessToken == null || _accessToken.IsExpired())
                            _accessToken = FetchAccessToken().Result<AccessToken>();
    
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken.Token);
                    }
                }
    
                private PayPalHttp.HttpResponse FetchAccessToken()
                {
                    var client = new ProxiedPayPalHttpClient(_environment, _proxy);
                    var request = new AccessTokenRequest(_environment, null);
    
                    return Task.Run(async () => await client.Execute(request).ConfigureAwait(false)).Result;
                }
            }
    
            private class GzipInjector : PayPalHttp.IInjector
            {
                public void Inject(PayPalHttp.HttpRequest request)
                {
                    request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
                }
            }
        }
    }