我想在不破坏旧客户端的电话的情况下,为我的 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 =&gt;一切都很好
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"}"
所以我的客户必须更改代码才能使用我的新WebService,我不希望这样。我想为我的新WebService提供默认值,最好的方法是什么?
可能重复:Can I have an optional parameter for an ASP.NET SOAP web service 但是没有一个回复对我有用。
FYI 我的客户经常通过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);
答案 0 :(得分:1)
实现这一点的正确方法似乎是为您的服务方法使用方法重载。同样对于未来的方法,我建议你使用模型:
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"
}