如何在不中断旧客户端调用的情况下向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);
实现这一点的正确方法似乎是为服务方法使用方法重载。此外,对于未来的方法,我建议您使用以下模型:
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"
}