如何使用C#调用远程iis上托管的wcf服务

如何使用C#调用远程iis上托管的wcf服务

问题描述:

如何使用C#调用远程iis上托管的wcf服务而不添加引用

服务我尝试此代码但它返回null

How to call wcf service hosted on remote iis using C# without add reference
of service i try this code but it return null

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
namespace Test
{
      [System.Web.Services.WebServiceBindingAttribute(Name = "MyWebService", Namespace = "http://microsoft.com/webservices/")]
    public class SoapProtocol : SoapHttpClientProtocol
    {

       public SoapProtocol():base()
        {
            this.Url = "http://localhost:8080/WebService.asmx"; //"http://localhost/wcf/WebService.asmx";
        }
          [System.Diagnostics.DebuggerStepThroughAttribute()]
       //     [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace = "http://tempuri.org", ResponseNamespace = "http://tempuri.org", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
          [SoapDocumentMethod("http://tempuri.org/HelloWorld", ResponseElementName = "HelloWorldResponse", RequestNamespace = "http://tempuri.org/", ResponseNamespace = "http://schemas.xmlsoap.org/soap/envelope/",Use=System.Web.Services.Description.SoapBindingUse.Literal,ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
         // [return:XmlArray("string",Namespace="",IsNullable = false)]

          public object[] HelloWorld(ref string data)
       {

         var res =   this.Invoke("HelloWorld", new object[]{});
     int g;

                 System.Windows.Forms.MessageBox.Show(res[0].ToString());

              return res;
       }


    }
}




/////////// soap request
POST /WebService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/HelloWorld"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <HelloWorld xmlns="http://tempuri.org/" />
  </soap:Body>
</soap:Envelope>
///////////// soap response
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <HelloWorldResponse xmlns="http://tempuri.org/">
      <HelloWorldResult>string</HelloWorldResult>
    </HelloWorldResponse>
  </soap:Body>
</soap:Envelope>

您好Mahmoud_Gamal



如果您不想添加服务引用(为什么?),您可以通过自己管理每个服务的WcfProxy和通信通道来解决此问题。但是你必须知道这个解决方案的服务合同(意味着你可以参考定义合同的程序集) - 我不知道你是否可以这样做......



来自我的代码库的示例:( IService只是我所有服务的基本接口,可以将它们识别为服务,它什么都不实现)



Hi Mahmoud_Gamal

If you don't want to add a service reference (why?) you could solve this by managing a WcfProxy and a communication channel for each Service by yourself. But you will have to "know" the service contract with this solution (means you can reference the assembly where the contract is defined) - I don't know if this is possible for you...

Example from my codebase: (IService is just a base interface for all my Services to identify them as service, it implements nothing)

public interface ICommandDispatcher
{
    TResult ExecuteCommand<TService, TResult>(Func<TService, TResult> command)
        where TResult : class
        where TService : class, IService;
}







可能的实现方式如下:






A possible implementation could look like this:

public class WcfCommandDispatcher : ICommandDispatcher
{
    class WcfProxy<TService> : ClientBase<TService>
        where TService : class, IService
    {
        public TService WcfChannel
        {
            get { return Channel; }
        }
    }
    public TResult ExecuteCommand<TService, TResult>(Func<TService, TResult> command)
        where TResult : class
        where TService : class, IService
    {
        WcfProxy<TService> proxy = new WcfProxy<TService>();
        try
        {
            TResult result = command.Invoke(proxy.WcfChannel);
            proxy.InnerChannel.Close();
            return result;
        }
        catch (Exception)
        {
            proxy.Abort();
            throw;
        }
    }
}





有了这个助手,您可以通过拨打任何服务知道这是合同。



来自我的代码库的示例,我从 ICultureService 获取了一些文化列表





With this helper in place you can call any service by "knowing" it's contract.

Example from my codebase where I get some list of "Cultures" from my ICultureService

WcfCommandDispatcher dispatcher = new WcfCommandDispatcher();
IEnumerable<Culture> cultures = dispatcher.ExecuteCommand<ICultureService, IEnumerable<Culture>>(s =>
{
    return s.GetAll();
}



所以你看,你可以在ExecuteCommand函数中使用该服务并且可以做无论你想要什么。不要忘记添加对System.ServiceModel和Service-Contract程序集的引用。以与服务引用相同的方式配置你的服务。(App.config)



我希望这会有所帮助。



亲切的问候

Johannes


So you see, you can just use the service inside the ExecuteCommand function and can do whatever you want. Don't Forget to add a reference to System.ServiceModel and your Service-Contract assembly. Configure your service in the same way you would do with a service reference. (App.config)

I hope this helps.

Kind regards
Johannes