关于c#:使用反射来调用ASP.NET Web服务

关于c#:使用反射来调用ASP.NET Web服务

Using reflection to call an ASP.NET web service

假设我有一个ASMX Web服务MyService。 该服务具有方法MyMethod。 我可以在服务器端执行MyMethod,如下所示:

1
2
MyService service = new MyService();
service.MyMethod();

我需要执行类似的操作,直到运行时才知道服务和方法。

我假设反思是解决问题的方法。 不幸的是,我很难使它工作。 当我执行此代码时:

1
Type.GetType("MyService", true);

它引发此错误:

Could not load type 'MyService' from assembly 'App_Web__ktsp_r0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

任何指导将不胜感激。


//试试这个->

1
2
3
    Type t = System.Web.Compilation.BuildManager.GetType("MyServiceClass", true);
    object act = Activator.CreateInstance(t);                
    object o = t.GetMethod("hello").Invoke(act, null);

我不确定这是否是解决问题的最佳方法。对我而言,最明显的方法是发出HTTP请求,然后使用实际的HTTP GET或POST调用Web服务。使用您的方法,我不确定要如何设置要发送到Web服务的数据。我在VB.Net中添加了一些示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Dim HTTPRequest As HttpWebRequest
Dim HTTPResponse As HttpWebResponse
Dim ResponseReader As StreamReader
Dim URL AS String
Dim ResponseText As String

URL ="http://www.example.com/MyWebSerivce/MyMethod?arg1=A&arg2=B"

HTTPRequest = HttpWebRequest.Create(URL)
HTTPRequest.Method ="GET"

HTTPResponse = HTTPRequest.GetResponse()

ResponseReader = New StreamReader(HTTPResponse.GetResponseStream())
ResponseText = ResponseReader.ReadToEnd()


这是一个简短的答案,有人可能会对此进行扩展。

当您使用WSDL模板应用程序(WSDL.exe)生成服务包装器时,它将构建一个类型为SoapHttpClientProtocol的类。您也可以手动进行操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyService : SoapHttpClientProtocol
{
    public MyService(string url)
    {
        this.Url = url;
        // plus set credentials, etc.
    }

    [SoapDocumentMethod("{service url}", RequestNamespace="{namespace}", ResponseNamespace="{namespace}", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
    public int MyMethod(string arg1)
    {
        object[] results = this.Invoke("MyMethod", new object[] { arg1 });
        return ((int)(results[0]));
    }
}

我尚未测试此代码,但我想它可以独立运行而无需运行WSDL工具。

我提供的代码是通过远程调用连接到Web服务的调用者代码(即使出于某种原因,您实际上并不希望它是远程的。)Invoke方法负责将其打包为肥皂电话。如果您想通过HTTP绕过Web服务调用,则@Dave Ward的代码是正确的-只要您实际上能够引用该类即可。也许内部类型不是" MyService"-您必须检查控件的代码才能


尽管我不知道反射为什么不在那里起作用(我假设编译器可能正在根据您的[WebService]注释创建一个新类),但是这里有一些建议可以解决您的问题:

简而言之,使您的WebService简单,简短:Facade Pattern的实现。

使您的服务将计算委托给实现类,该实现类应易于通过反射调用。这样,您的WebService类就只是系统的前端-您甚至可以添加电子邮件处理程序,XML-RPC前端等,因为您的逻辑不是耦合到WebService,而是耦合到实际的业务层对象。

将WebService类视为体系结构中的UI层对象。


我回头看了这个问题,我认为您所面临的是,ASMX代码将以随机名称内置到DLL中,作为站点动态编译的一部分。默认情况下,用于查找类型的代码将仅搜索其自己的程序集(根据收到的错误的外观,为另一个App_Code DLL)和核心库。您可以为GetType()提供一个特定的程序集引用" TypeName,AssemblyName",但对于自动生成的程序集则是不可能的,因为在每次重新编译后都有新名称。

解决方案...。我自己以前没有做过,但是我相信您应该可以使用以下方法:

1
System.Web.Compilation.BuildManager.GetType("MyService", true)

因为BuildManager知道它已经创建的DLL,并且知道在哪里查找。

我想这确实与Web服务无关,但是如果它是您自己的代码,那么Daren对Facade模式是正确的。


@Radu:我能够创建一个实例并完全像这样调用该方法。例如,如果我有此ASMX:

1
2
3
4
5
6
7
8
9
10
11
[WebService(Namespace ="http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyService : System.Web.Services.WebService
{
  [WebMethod]
  public string HelloWorld()
  {
    return"Hello World";
  }
}

我可以从ASPX页面的代码中调用它,如下所示:

1
2
MyService service = new MyService();
Response.Write(service.HelloWorld());

您是说不行吗?


尽管我无法从您的帖子中得知:

要记住的一件事是,如果使用反射,则需要创建自动生成的Web服务类的实例(该实例是从Web服务的WSDL创建的)。不要创建对服务的服务器端负责的类。

因此,如果您有网络服务

1
2
3
4
5
6
7
    [WebService(Namespace ="http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    public class WebService1 : System.Web.Services.WebService
    {
     ...
    }

您不能在客户端中引用该程序集,而是执行以下操作:

1
2
WebService1  ws = new WebService1 ();
ws.SomeMethod();

@Kibbee:我需要避免HTTP性能下降。这不会是远程呼叫,因此所有这些额外的开销都应该是不必要的。

@Daren:我绝对同意那种设计理念。这里的问题是,我不会控制该服务或其底层业务逻辑。

这是针对服务器控件的,它需要针对任意服务/方法执行,与Web服务本身的实现方式正交。


推荐阅读