如何在不中断旧客户端调用的情况下向JSON WebService添加更多参数

本文关键字:WebService JSON 添加 参数 情况下 中断 调用 客户端 | 更新日期: 2023-09-27 18:28:38

我想在不中断旧客户端调用的情况下,向我的JSON WebService添加更多参数。示例:

Service.asmx中的我的WebService

[WebMethod]
public string Ping(string msg, string additionalInfo)
{
    if (string.IsNullOrEmpty(additionalInfo))
    {
        return "Process msg with old version";
    }
    return "Process msg with new version"; ;
}
//My old web service does not have additionalInfo arguments
//public string Ping(string msg) {..}

Web.config告诉我的WebService是基于JSON的

<system.web.extensions>
  <scripting>
       <webServices>
           <jsonSerialization maxJsonLength="50000000" />
       </webServices>
   </scripting>

如果客户端使用所有参数调用我的新Json WebService=>一切都很好

CallWs("http://localhost:48918/Service.asmx/Ping", '{"msg":"hello", "additionalInfo":""}')

但目前所有的客户都不会给出additionalInfo:

CallWs("http://localhost:48918/Service.asmx/Ping", '{"msg":"hello"}')

我的新WebService将立即返回错误:

string(654) "{"Message":"Invalid web service call, missing value for parameter: 'u0027additionalInfo'u0027.","StackTrace":"   at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)'r'n   at System.Web.Script.Services.WebServiceMethodData.CallMethodFromRawParams(Object target, IDictionary`2 parameters)'r'n   at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)'r'n   at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.InvalidOperationException"}"

所以我的客户必须更改他们的e代码才能使用我的新WebService,我不希望这样。我想为我的新WebService提供默认值,最好的方法是什么?

可能的重复:我可以为ASP.NET SOAP web服务提供一个可选参数吗但没有一个回应对我有效。


仅供参考我的客户经常通过PHP调用我的JSON WebService,他们只需向服务端点发出POST请求:

$ch = curl_init("http://localhost:48918/Service.asmx/Ping");
$wsrq = array(
    "msg" => "Hello",
    //"additionalInfo" => "World",
);
curl_setopt_array($ch, array(
    CURLOPT_POST => TRUE,
    CURLOPT_RETURNTRANSFER => TRUE,
    CURLOPT_SSL_VERIFYPEER => FALSE,
    CURLOPT_POSTFIELDS => json_encode($wsrq),
    CURLOPT_HTTPHEADER => array("Content-type: application/json; charset=utf-8"),
));
$response = curl_exec($ch);

如何在不中断旧客户端调用的情况下向JSON WebService添加更多参数

实现这一点的正确方法似乎是为服务方法使用方法重载。此外,对于未来的方法,我建议您使用以下模型:

public class MyModel
{
    public string Message { get; set; }
    public string AdditionalInfo { get; set; }
}

然后:

[WebMethod]
public string Ping(MyModel model)
{
    ...
}

这将为您提供更大的灵活性,因为您将来可以轻松添加属性而不会中断。

话虽如此,您可能会考虑一种方法或一种变通方法:手动反序列化(我完全不推荐,但值得一提)。

让你的WebMethod没有任何参数:

[WebMethod]
public string Ping()

然后通过访问输入流手动读取请求主体:

[WebMethod]
public string Ping()
{
    Context.Request.InputStream.Seek(0, SeekOrigin.Begin);
    using (var inputStream = Context.Request.InputStream)
    using (var reader = new StreamReader(inputStream))
    {
        string body = reader.ReadToEnd();
        // TODO: Worth checking the request headers before attempting JSON deserialization
        // For example the Content-Type header
        var model = JsonConvert.DeserializeObject<MyModel>(body);
        if (string.IsNullOrEmpty(model.AdditionalInfo))
        {
            return "Process msg with old version";
        }
        return "Process msg with new version"; ;
    }
}

为了避免在服务方法中混合多种职责,您可以将正文流的解析转移到一些单独的扩展方法中:

public static class RequestExtensions
{
    public static T ParseRequest<T>(this HttpRequest request)
    {
        request.InputStream.Seek(0, SeekOrigin.Begin);
        using (var inputStream = request.InputStream)
        using (var reader = new StreamReader(inputStream))
        {
            string body = reader.ReadToEnd();
            return JsonConvert.DeserializeObject<T>(body);
        }
    }
}

然后你的WebMethod:

[WebMethod]
public string Ping()
{
    var model = Context.Request.ParseRequest<MyModel>();
    if (string.IsNullOrEmpty(model.AdditionalInfo))
    {
        return "Process msg with old version";
    }
    return "Process msg with new version"; ;
}

现在客户端可以这样调用Ping方法:

POST /WebService1.asmx/Ping HTTP/1.1
Content-type: application/json; charset=utf-8
Host: localhost:14529
Content-Length: 61
{
    "msg": "Hello",
    "additionalInfo": "add info"
}

还是老办法:

POST /WebService1.asmx/Ping HTTP/1.1
Content-type: application/json; charset=utf-8
Host: localhost:14529
Content-Length: 26
{
    "msg": "Hello"
}