ASP.NET WebService로 .asmx 서비스를 하나 만들면 기본적으로 SOAP 호출을 받는 서비스가 된다.
그런데 여기에 AjaxControlToolkit을 설치하거나 Ajax를 통해 JSON 호출도 받는 서비스를 만들려면
[ScriptService] 라는 속성 선언을 더해주고 web.config에도 아래 부분을 추가해야 한다.
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="5000000" />
</webServices>
</scripting>
</system.web.extensions>
숫자는 적당히.
>> 참조: http://msdn.microsoft.com/ko-kr/library/bb398998(v=vs.90).aspx
그러면 AjaxControlToolkit뿐만 아니라 jQuery의 $.ajax() 명령을 이용해서 JSON 개체를 사용할 수 있다.
>> 참조: http://www.codeproject.com/Articles/521723/Web-Service-and-Script-Service
그런데, 문제는 이런 것들을 쓰려면 뭔가를 설치하거나 참조 또는 스크립트 링크를 넣어야 한다는 점이다.
제 아무리 minifier 등을 써서 줄여도 최소 수십 KB 이상이 추가되기 때문에 웹 페이지가 갑작스레 무거워진다는 점이 영 별로다. 정작 실제로 사용하는 건 겨우 함수 한두 개, 길어야 코드 수십 줄 뿐인데 말이다.
그래서 이것저것 다 빼고 Javascript로 직접 XmlHttpRequest 코딩을 하려고 할 때가 있다, 오직 가벼움을 위해.
JSON도 아니고 SOAP도 아닌 그냥 HttpPost 방식으로.
예를 들면 이런 거.
[Service.asmx.cs]
[ScriptService]
public class Service : WebService
{
[WebMethod]
public string GetString(bool isOk)
{
return isOK ? "OK" : "NO";
}
}
이런 간단한 웹 서비스를 하나 만들고 Javascript에서 호출하려고 하면,
[test.js]
function getXmlHttpRequest() {
if (!window.XMLHttpRequest) {
window.XMLHttpRequest = function window$XMLHttpRequest() {
var progIDs = ['Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP'];
for (var i = 0, l = progIDs.length; i < l; i++) {
try {
return new ActiveXObject(progIDs[i]);
} catch (ex) {
}
}
return null;
};
}
return new XMLHttpRequest();
}
xhr.open("POST", "/Service.asmx/GetString", false);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
xhr.send("isOK=true");
if (xhr.readyState == 4 && xhr.status == 200) {
console.log("서버 호출 결과: " + xhr.responseText);
var doc = xhr.responseXML;
var xmldoc;
if (doc && doc.documentElement) // Chrome, IE 최신 버전 등...
xmldoc = doc;
else { // IE 낮은 버전
doc = xhr.responseText;
if (window.DOMParser) {
var parser = new DOMParser();
xmldoc = parser.parseFromString(doc, "text/xml");
} else if (window.ActiveXObject || "ActiveXObject" in window) { // Internet Explorer
xmldoc = new ActiveXObject("Microsoft.XMLDOM");
xmldoc.async = false;
xmldoc.loadXML(doc);
}
}
if (xmldoc != null && xmldoc.documentElement != null && xmldoc.documentElement.firstChild != null) {
var val = xmldoc.documentElement.firstChild.nodeValue;
}
...
}
뭐 이런 식의 코드가 만들어져야 한다. (녹색 부분은 크로스 브라우저 호환 코드라 괜히 길어졌다.)
호출은 Form POST 방식(x-www-form-urlencoded)으로 "이름=값&이름=값" 이런 식으로 단순하게 들어가지만, 결과는 안타깝게도 XML로 리턴되므로 위와 같이 XML 파싱 부분이 들어가야 하는데, 코드 길이나 참조 링크 등 여러 측면에서 JSON 파싱보다는 낫다고 생각한다. (무한 단순 반복 연산이나 과부하 상태일 때는 JSON이 더 나은 성능을 보인다는 얘기도 있는데, 그런 건 난 잘 모르겠다. 난 XML 파싱이 더 좋다. 보기에도 좋고 쓰기에도 좋고.)
그런데, 문제가 있다!
코드를 잘 완성해서 로컬 PC나 서버 로컬에서 테스트해보면 매우 정상 작동하다가도
클라이언트-서버 분리된 환경으로 테스트를 해 보면 에러가 발생하고 제대로 호출이 되지 않는 상황이 생긴다.
그 때 서버 이벤트를 보면,
Event code: 3005
Event message: 처리되지 않은 예외가 발생했습니다.
Event time: 2014-0x-xx 오후 x:xx:xx
Event time (UTC): 2014-0x-xx 오전 x:xx:xx
Event ID: 08ee8dbd5a334c16876c30272c2549c5
Event sequence: 2506
Event occurrence: 196
Event detail code: 0
Application information:
Application domain: /LM/W3SVC/1/ROOT-6-130416651036127238
Trust level: Full
Application Virtual Path: /
Application Path: D:\TestWeb\
Machine name: TESTCOMPUTER
Process information:
Process ID: 5792
Process name: w3wp.exe
Account name: IIS APPPOOL\TestWeb
Exception information:
Exception type: InvalidOperationException
Exception message: URL이 예기치 않게 '/GetString'(으)로 끝나 요청 형식을 인식할 수 없습니다.
위치: 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.Script.Services.ScriptHandlerFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated)
위치: System.Web.HttpApplication.MaterializeHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
위치: System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
이런 오류를 기록하고 있다.
요청 형식을 인식할 수 없다고?
(영어로는 "Request format is unrecognized for URL unexpectedly ending in '/GetString'" 쯤 되겠다.)
이게 왜 이러는 걸까? 엄연히 존재하는 URL이 맞고 정상적으로 요청한 것도 맞는데?
개발 컴퓨터 로컬컴퓨터에서 하면 잘만 되는데?
이건 뭔가 다른 문제가 있다는 거다. 예를 들면 호출 방식이나 서버의 설정 같은 문제가...
좀 더 확인해 보니,
JSON이나 SOAP으로는 아주 잘 되는데, Form POST 방식(x-www-form-urlencoded)일 때만 안되는 거였다.
즉, HttpPost 방식이 안되는 거였다.
왜 HttpPost 방식만 안되는 걸까?
그 답은,
기본적으로 ASP.NET에서 ScriptService는 HttpGet과 HttpPost가 disabled 되어 있어서 그런 것이란다.
이걸 허용해 주면 된다.
<system.web>
<webServices>
<protocols>
<add name="HttpPost" />
</protocols>
</webServices>
</system.web>
그러면 다 잘 된다.
'Tech: > .NET·C#' 카테고리의 다른 글
한 눈에 보는 OS별 .NET Framework 기본 버전 (0) | 2014.06.05 |
---|---|
PushSharp APNS "SSPI를 호출하지 못했습니다" 오류 (1) | 2014.04.23 |
C# 4.5 버전과 C# 4.5.1 버전의 차이 (0) | 2014.04.04 |
SEED 활용 - 전자서명 (6) | 2014.03.26 |
SEED C# 소스 (33) | 2014.03.25 |