【问题标题】:How to check EU VAT using VIES SOAP service in C#如何在 C# 中使用 VIES SOAP 服务检查欧盟增值税
【发布时间】:2023-03-18 17:30:01
【问题描述】:

我有一个需要检查用户提供的增值税的 ASP.NET 网站。 VIES Service 可用于公开SOAP API 的内容。

我需要一个关于如何使用此服务验证增值税的非常简单的示例。在 PHP 中,就是这 4 行:https://stackoverflow.com/a/14340495。对于 C#,我发现 2010 年的一些文章不起作用或者是数十甚至数百行“包装器”、“辅助服务”等。

我不需要这些,有人可以提供类似 PHP 的四行代码来检查 C# 中的增值税吗?谢谢。

【问题讨论】:

    标签: c# asp.net soap


    【解决方案1】:

    我发现的最简单的方法就是发送一个 XML 并在它返回时对其进行解析:

    var wc = new WebClient();
    var request = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:ec.europa.eu:taxud:vies:services:checkVat:types"">
        <soapenv:Header/>
        <soapenv:Body>
          <urn:checkVat>
             <urn:countryCode>COUNTRY</urn:countryCode>
             <urn:vatNumber>VATNUMBER</urn:vatNumber>
          </urn:checkVat>
        </soapenv:Body>
        </soapenv:Envelope>";
    
    request = request.Replace("COUNTRY", countryCode);
    request = request.Replace("VATNUMBER", theRest);
    
    String response;
    try
    {
        response = wc.UploadString("http://ec.europa.eu/taxation_customs/vies/services/checkVatService", request);
    }
    catch
    {
        // service throws WebException e.g. when non-EU VAT is supplied
    }
    
    var isValid = response.Contains("<valid>true</valid>");
    

    【讨论】:

    • 什么是类型的WC?这是如何声明的?
    • 已添加 >> var wc = new WebClient();
    【解决方案2】:

    这是一个自给自足的(没有 WCF、没有 WSDL,...)实用程序类,它将检查增值税号并获取有关公司的信息(名称和地址)。如果增值税号无效或发生任何错误,它将返回 null。

    // sample calling code
    Console.WriteLine(EuropeanVatInformation.Get("FR89831948815"));
    
    ...
    
    public class EuropeanVatInformation
    {
        private EuropeanVatInformation() { }
    
        public string CountryCode { get; private set; }
        public string VatNumber { get; private set; }
        public string Address { get; private set; }
        public string Name { get; private set; }
        public override string ToString() => CountryCode + " " + VatNumber + ": " + Name + ", " + Address.Replace("\n", ", ");
    
        public static EuropeanVatInformation Get(string countryCodeAndVatNumber)
        {
            if (countryCodeAndVatNumber == null)
                throw new ArgumentNullException(nameof(countryCodeAndVatNumber));
    
            if (countryCodeAndVatNumber.Length < 3)
                return null;
    
            return Get(countryCodeAndVatNumber.Substring(0, 2), countryCodeAndVatNumber.Substring(2));
        }
    
        public static EuropeanVatInformation Get(string countryCode, string vatNumber)
        {
            if (countryCode == null)
                throw new ArgumentNullException(nameof(countryCode));
    
            if (vatNumber == null)
                throw new ArgumentNullException(nameof(vatNumber));
    
            countryCode = countryCode.Trim();
            vatNumber = vatNumber.Trim().Replace(" ", string.Empty);
    
            const string url = "http://ec.europa.eu/taxation_customs/vies/services/checkVatService";
            const string xml = @"<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><checkVat xmlns='urn:ec.europa.eu:taxud:vies:services:checkVat:types'><countryCode>{0}</countryCode><vatNumber>{1}</vatNumber></checkVat></s:Body></s:Envelope>";
    
            try
            {
                using (var client = new WebClient())
                {
                    var doc = new XmlDocument();
                    doc.LoadXml(client.UploadString(url, string.Format(xml, countryCode, vatNumber)));
                    var response = doc.SelectSingleNode("//*[local-name()='checkVatResponse']") as XmlElement;
                    if (response == null || response["valid"]?.InnerText != "true")
                        return null;
    
                    var info = new EuropeanVatInformation();
                    info.CountryCode = response["countryCode"].InnerText;
                    info.VatNumber = response["vatNumber"].InnerText;
                    info.Name = response["name"]?.InnerText;
                    info.Address = response["address"]?.InnerText;
                    return info;
                }
            }
            catch
            {
                return null;
            }
        }
    }
    

    【讨论】:

    • 三年过去了,这对我来说是最可靠的答案。谢谢!
    • 如果您要部署到 OpenShift,这也是一种有效的方法。我们在此托管方案中使用连接服务时遇到了问题。走“原始”路径是可行的。
    【解决方案3】:

    在 .NET 平台上,使用 Web 服务是很常见的,以便我们生成代理类。这通常可以使用 Visual Studio“添加 Web 引用”来完成,您只需填写 WSDL 的路径。另一种方法是使用wsdl.exesvcutil.exe 生成源类。

    然后只需消费这个类,验证增值税就变成了单行:

    DateTime date = new checkVatPortTypeClient().checkVat(ref countryCode, ref vatNumber, out isValid, out name, out address);
    

    生成代理提供强类型 API 来使用整个服务,我们不需要手动创建肥皂信封和解析输出文本。它比yours 更简单、更安全、更通用的解决方案。

    【讨论】:

    • 我猜这个答案已经过时了,因为该服务不再提供 checkVat 功能。
    • @Ben 所以 OP 的答案也已经过时了。但我的回答仍然有效,因为您可以简单地重新生成代理类并正确更新调用代码。
    【解决方案4】:

    更新:我已将其发布为 NuGet 库。

    https://github.com/TriggerMe/CSharpVatChecker

    var vatQuery = new VATQuery();
    var vatResult = await vatQuery.CheckVATNumberAsync("IE", "3041081MH"); // The Squarespace VAT Number
    
    Console.WriteLine(vatResult.Valid); // Is the VAT Number valid?
    Console.WriteLine(vatResult.Name);  // Name of the organisation
    

    【讨论】:

      【解决方案5】:

      基于 Pavel Hodek 的:

      1. 确保为 Visual Studio 安装了 Microsoft WCF Web Service Reference Provide 扩展(我使用的是 VS 2017 社区)。
      2. 在解决方案资源管理器中右键单击连接的服务 > 添加连接的服务
      3. 选择 WCF 扩展。
      4. 输入 VIES 提供的 URL http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 从 wsdl 生成 Service 类。

      5. 按 Go 并选择服务,为命名空间命名,例如Services.VATCheck

      6. 按完成,这将在 Connected Services 中创建一个新文件夹和一个名为 reference.cs 的文件,将文件重命名为 VATCheck,这也将重命名类。

      在控制器中使用以下代码调用调用,确保它是异步的(最终加载所有数据可能需要一段时间)

          public async Task<IActionResult> CheckVAT()
          {
              var countryCode = "BE";
              var vatNumber = "123456789";
      
              try
              {
                  checkVatPortType test = new checkVatPortTypeClient(checkVatPortTypeClient.EndpointConfiguration.checkVatPort, "http://ec.europa.eu/taxation_customs/vies/services/checkVatService");
                  checkVatResponse response = await test.checkVatAsync(new checkVatRequest { countryCode = countryCode, vatNumber = vatNumber });
              }
              catch (Exception ex)
              {
                  System.Diagnostics.Debug.WriteLine(ex.Message);
              }
      
              return Ok();
          }
      

      请注意,您可以清理此呼叫,但这完全取决于您。

      【讨论】:

      • 可能是最佳答案,因为它使用提供 wsdl 的欧盟提供的支持方法。这突出显示了缺少说明您需要提供端口和 url 的文档,这是所有开发人员陷入困境的地方
      【解决方案6】:
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using BTWCheck.eu.europa.ec;    
      
      namespace BTWCheck
      {
           class Program
          {
              static void Main(string[] args)
              {
                  // VS 2017
                  // add service reference -> button "Advanced" -> button "Add Web Reference" ->
                  // URL = http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl 
      
                  string Landcode = "NL";
                  string BTWNummer = "820471616B01"; // VAT nr BOL.COM 
      
                  checkVatService test = new checkVatService();
                  test.checkVat(ref Landcode, ref BTWNummer, out bool GeldigBTWNr, out string Naam, out string Adres);
      
                  Console.WriteLine(Landcode + BTWNummer + " " + GeldigBTWNr);
                  Console.WriteLine(Naam+Adres);
                  Console.ReadKey();
      
              }
          }
      }
      

      【讨论】:

      • 请为您的答案写一些 cmets/descriptions 以改进它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-11
      • 2014-12-22
      • 1970-01-01
      相关资源
      最近更新 更多