2011年3月2日星期三

IIS7導致WebService無效?

今天工作上的ASP.NET Project莫名其妙出現兩個錯誤。
我的開發環境和Project架構都很簡單 :
  1. VWD 2010
  2. ASP.NET 4.0
  3. jQuery 1.4.4
  4. JSON.NET
  5. ASP.NET內建的Dev Server
  6. CodePlex上的CassiniDev
整個Project已經做了個多月,一直在本機上沒有問題,今天想試試上傳去Windows Server 2008的IIS7.5上試試運行,誰不知就出現jQuery Ajax失靈,唯有用IE的Developer Tool看看,使用jQuery.Ajax的error function觀看responseText properties,得出Exception Message說原因來自WebService。
System.InvalidOperationException: Request format is unrecognized for URL unexpectedly ending in '/getRecords'.
System.Web.Services.Protocols.WebServiceHandlerFactory.CoreGetHandler(Type type, HttpContext context, HttpRequest request, HttpResponse response)
System.Web.Services.Protocols.WebServiceHandlerFactory.GetHandler(HttpContext context, String verb, String url, String filePath)
System.Web.MaterializeHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
來看看Code部份:
function getRecords(RecordID) {
   $.ajax({
            type: "POST",
            url: "WebService/ClientCallBack.asmx/getRecords",
            data: "{ 'RecordID': '" + RecordID + "' }",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (msg) {
            var json = JSON.parse(msg.d);
            $.each(json, function (idx, item) {
                alert(json[idx].Title);
                //Do Something Else
            });
        },
        error: function (err) {
            alert("error : " + err.responseText);
        }
    });
}
using Newtonsoft.Json;

[WebMethod]
public string getRecords(int RecordID)
{
List<DataContractClass.Records> jsonlist = new List<DataContractClass.Records>();
DataContractClass.Records r = null;
using (ReferralDBEntities de = new ReferralDBEntities())
{
int id = 0;
var records = from pack in de.ReferralPackages
where pack.RecordID == RecordID 
orderby pack.CreatedDate descending
select pack, item;

foreach (var rec in records)
{
r = new DataContractClass.PatientRecords();
r.PackageID = rec.pack.PackageID;
r.Title = rec.pack.Title;
//and more...
jsonlist.Add(r);
} 
}
return JsonConvert.SerializeObject(jsonlist);
}

由於那個WebService是用EF4加JSON.NET回傳Json String,所以我在Browser直接打上<http://www.mydomain.com/WebService/ClientCallBack.asmx>試試,但竟沒有問題,再看看jQuery部份,兩者實在沒有微調空間,
jQuery最重要的兩行我都有了。
contentType: "application/json; charset=utf-8",
dataType: "json",

試了很多方法都不行,最後唯有Google再Google,找到這篇文章
問題大概是會出現在當IIS7的Application Pool設定Managed pipeline mode成<Integrated>才發生。
而解決方法是在web.config的system.web段中插入下面的設定就搞定。
<system.web>
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
</system.web>

但事情還未解決...之後又出現新的錯誤:
System.InvalidOperationException: Request format is invalid: application/json; charset=utf-8.
at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

而解決方法則在這裡找到
在web.config加入
<system.webServer>
<handlers>
<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</handlers>
</system.webServer>

就大功告成。

第一個問題成因在KB article中有解說。
<By default, in .NET Framework 1.1, HTTP GET and HTTP POST are both disabled. This is for security reasons.>
雖然文中說是.NET 1.1問題,但解決方法卻是一模一樣。

而第二個問題就是,其實在IIS7的Manager上的Handler Mappings部份已經可以見到有ScriptHandlerFactory,
但就是沒有preCondition="integratedMode"一項,所以相信為什麼在Managed pipeline mode=<Classic>沒有問題,但轉成<integrated>就會產生錯誤。

1 則留言:

  1. [...] 呼叫的程式碼裡看來看去找了好久,結果發現是 web.config 造成的, 總算在這一篇(IIS7導致WebService無效?)找到我的問題,才想到我忘了在 web.config 中加入相對應的 httpModules 及 [...]

    回覆刪除