.Net WebServices和out/ref WebMethod参数

12

我从我们的一位供应商那里收到了关于他们正在发布的一个Web服务的一些文档,他们非常明确地表示,在他们的某个WebMethod中,一个参数具有out修饰符(?不确定是否是正确的描述),例如请考虑以下WebMethod签名:

[WebMethod]
public void HelloWorld(out string strVal) 
{ 
    strVal = "Hello World";
}

[显然,实际方法并不是一个“Hello World”方法]

我从未考虑过设计一个带有out/ref参数的WebMethod,并且我想知道为什么他们会使用它。

为了理解这种设计决策的应用,我创建了一个原型,其中包括几个基本的“Hello World”样式的webmethod...一个带有单个out字符串参数,一个带有两个out字符串参数,以及一个不接收任何参数但返回一个字符串的webmethod。

当我尝试从另一个应用程序引用我的webmethods时,我注意到我必须像定义方法输出字符串一样访问带有单个out字符串参数的方法,以便在客户端看来:

public string HelloWorld1()
{
  return "Hello World";
}

public void HelloWorld2(out string strVal)
{
  strVal = "Hello World";
}

两者完全相同……在这种情况下,我必须将它们都称为如此 [其中 x 被替换为正确的方法]:

string val = HelloWorldX();

我试图以与访问非网络方法相同的方式引用这些方法,就像这样:

string val = string.Empty;
MyService1.HelloWorld(out val);
Console.WriteLine(val);

出现编译错误,指出没有方法参数可接受1个输入。为什么会这样呢?很明显有一个Web方法可以接受一个参数——我正在查看它[HelloWorld2]。

检查SOAP响应后,我注意到HelloWorld1响应的内容是:

<HelloWorld1Response xmlns="http://tempuri.org/">
  <HelloWorld1Result>string</HelloWorld1Result>
</HelloWorld1Response>

而 HelloWorld2 则是:

<HelloWorld2Response xmlns="http://tempuri.org/">
  <strVal>string</strVal>
</HelloWorld2Response>

进一步思考后,我想,如果有两个 ref 参数会怎样……

public void HelloWorld3(out string strVal1, out string strVal2)
{
    strVal1 = "Hello World";
    strVal2 = "Hello World Again!";
}

这将生成SOAP内容:

<HelloWorld3Response xmlns="http://tempuri.org/">
  <strVal1>string</strVal1>
  <strVal2>string</strVal2>
</HelloWorld3Response>

我认为这很公平,那么从理论上讲 [只要我能找到一种方法将ref参数传递给WebMethods] 这意味着我只需传入两个参数,这些参数可以由该方法设置,但当我这样做时:

string val1 = string.Empty;
string val2 = string.Empty;
MyService1.HelloWorld3(out val1,out val2);
Console.WriteLine(val1);
Console.WriteLine(val2);

我希望能看到与我以这种方式引用HelloWorld2时看到的相同编译错误。除了明显的异常,即它抱怨有两个参数而不是一个[实际上,我测试过它并且确实得到了相同的异常]。

  • 为什么会出现这种情况?
  • 是否存在在WebMethods中使用out/ref参数的原因或方法,我是否遗漏了什么?
  • 如果存在,如何引用具有多个out/ref参数的WebMethods?
2个回答

17

我不知道如何回答自己的问题,但是Steven Behnke提供的文章为我推断解决这种奇怪情况提供了一些线索。而且,我不想让其他人去猜测影响是什么,所以我想分享我的发现。

那么,请考虑我WebService中定义的以下WebMethods:

[WebMethod]
public string Method1()
{
    return "This is my return value";
}

[WebMethod]
public void Method2(out string strVal1)
{
    strVal1 = "This is my value passed as an output";
    //No return value
}

[WebMethod]
public void Method3(out string strVal1, out string strVal2)
{
    strVal1 = "This is my strVal1 value passed as an output";
    strVal2 = "This is my strVal2 value passed as an output";
    //No return value
}

[WebMethod]
public string Method4(out string strVal1, out string strVal2)
{
    strVal1 = "This is my strVal1 value passed as an output";
    strVal2 = "This is my strVal2 value passed as an output";
    return "This is my return value";
}

根据文档所述,如果方法的返回类型为 void,则第一个参数被自动用作返回值参数。因此,我将按以下方式访问我的每个方法:

Method1:

public string Method1() {}

var str = svc.Method1();
Console.WriteLine(str);

方法2:

public void Method2(out string strVal1) {}

var str = svc.Method2();
Console.WriteLine(str);

所以你需要以完全相同的方式访问它们,这非常令人困惑。没有人会在未经他人告知的情况下想到这一点,我无法理解这怎么可能是个好主意。

方法3:

public void Method3(out string strVal1, out string strVal) {}

var str2 = String.Empty;
var str1 = svc.Method3(out str2);
Console.WriteLine(str1);
Console.WriteLine(str2);

方法4:

public string Method4(out string strVal1, out string strVal2) {}

var str1 = String.Empty;
var str2 = String.Empty;
var str3 = svc.Method4(out str1, out str2);
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);
因此,正如你所注意到的 - 如果方法签名没有提供返回值[即返回 void],那么第一个参数就成为返回值。如果它已经提供了返回值,那么就不会这样做。 对于从未接触过该文档的人来说,这可能非常令人困惑。感谢 Steven 提供链接 - 我非常感激。 至于决定将设计模式写入.NET Framework的人 - 我无法想象是什么使你认为那是个好主意。在经历了所有这些之后,我真的非常厌恶你。 补充说明: 我刚刚意识到要增加混淆,如果你使用ref而不是out,那么你不需要这样做,你将像调用应用程序内的普通方法一样处理 WebMethods。
[WebMethod()]
public void Method3(ref string strVal1, ref string strVal2)
{
    strVal1 = "First argument return value";
    strVal2 = "Second argument return value";
}

现在你需要使用以下代码来调用它:

string val1 = String.Empty;
string val2 = String.Empty;
svc.Method3(ref val1, ref val2);
Console.WriteLine(val1);
Console.WriteLine(val2);

这种不一致性令人难以置信。而且这是故意设计的事实,这对我来说是无法理解的。


当你的声望达到2000时,我相信正确的协议应该是编辑Steven Behnke的答案……尽管可能会感到有些冒犯。但是很好的工作发表了你的摘要。+1 - John MacIntyre

2

好的,谢谢 - 那篇文章非常有启发性。我对那个设计想法唯一的评论是:“到底是谁想出这个主意的,太糟糕了!” - BenAlabaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接