Notice
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- Mail Server
- not working
- curl
- 설치
- chart.js
- UML
- FCM
- mysql
- roundcube
- 자바스크립트
- php 취약점
- 안드로이드
- javascript
- android 효과음
- PHP
- 폼메일
- 안드로이드 푸쉬
- C#
- 안드로이드 푸시
- WebView
- Android
- soundpool
- 우분투
- xe
- php 시큐어코딩
- dovecot
- C# IO
- 자동 생성
- html5
- 안드로이드 gcm
Archives
- Today
- Total
그러냐
[WCF]데이터 보내기1 본문
반응형
[제목] 데이터를 보내보자
우선, 가장 쉽게 WCF를 이해하기 위해 간단하게 DataSet을 넘겨보자
[그림1]WCF를 실제 서비스할 어플리케이션을 간단한 Layer로 구성해 보았다
뭐 복잡한것은 없다
-데이터베이스(SQL2005) : 샘플데이타 베이스인 AdventureWorksDW이다.
-데이터 레이어 : 데이터 많은 것을 넘겨보기 위해 FactInternetSales 테이블을 이용했다
SELECT
A.ProductKey,
B.EnglishProductName,
CONVERT(CHAR(8), C.FullDateAlternateKey, 112) AS FullDate,
A.SalesOrderNumber,
A.RevisionNumber,
A.UnitPrice,
A.ExtendedAmount
FROM FactInternetSales A INNER JOIN DimProduct B ON A.ProductKey = B.ProductKey
LEFT OUTER JOIN DimTime C ON A.OrderDateKey = C.TimeKey
A.ProductKey,
B.EnglishProductName,
CONVERT(CHAR(8), C.FullDateAlternateKey, 112) AS FullDate,
A.SalesOrderNumber,
A.RevisionNumber,
A.UnitPrice,
A.ExtendedAmount
FROM FactInternetSales A INNER JOIN DimProduct B ON A.ProductKey = B.ProductKey
LEFT OUTER JOIN DimTime C ON A.OrderDateKey = C.TimeKey
60398건이다
-비지니스레이어 : 걍 DataSet을 패스한다
* ServiceProxy 를 참조하고, 인터페이스인 IFactInternetSales를 상속받아
SelectFactInternetSalesDs메소드를 구현한다.
-ServiceProxy : 이게 핵심이다
ServiceContract(인터페이스 IFactInternetSales)와 OperationContract(SelectFactInternetSalesDs)를 지정하는 부분이다
* 이 ServiceProxy는 Client Application에서도 참조하여 쓸 것이다
-ServiceFApp : 서비스 어플리케이션
이 부분은 이전 포스트에서 말했듯이 App.Config를 통해 모두 설정가능하고
이를 IIS에서 서비스 할 수있다(여기서는 단순히 코드를 익히기 위해 직접 self-hosting
방식으로 만들었다)
대부분 코드가 이전 Hellow예제와 동일 하며, 단지 DataSet을 서비스한다는 것 외예
별다른 것이 없다.
결과는 다음과 같다
[그림6]서비스 오픈
여기서, 중요 몇가지를 집고 넘어가기로 한다.
1. Max Transfer Limitted 전송 제한
- ServiceBehaviorAttribute클래스에 MaxItemsInObjectGraph 속성이 있다
의미는 직렬화 객체에 할 당 할 수있는 최대값
디폴트는 65536 이고, 최대값은 Int32.MaxValue인 2147483647 이다.
현재 예제에서는 그리별 문제가 되지 않지만, 사용자 정의 클래스를 사용한 예제예서 다시
이를 언급할 것이다(한마디로 지랄 맞다)
- 클라이언트 어플리케이션에서 binding객체 속성에 MaxReceivedMessageSize가 있다
이것이 중요하다.
binding(여기서는 BasicHttpBinding)과 함께 구성된 채널(ChannelFactory)에서 받을 수있는
최대값(제한)을 설정해주어야 한다.
디폴트는 65536 이고, 최대값은 Int32.MaxValue인 2147483647 이다.
이를 높게 잡아주지 않고 디폴트로 하면
The maximum message size quota for incoming messages (65536) has been exceeded.
To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element. 메세지가 떨어질 것이다
To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element. 메세지가 떨어질 것이다
--전체 에러메세지
Server stack trace:
위치: System.ServiceModel.Channels.HttpInput.ThrowMaxReceivedMessageSizeExceeded()
위치: System.ServiceModel.Channels.HttpInput.GetMessageBuffer()
위치: System.ServiceModel.Channels.HttpInput.ReadBufferedMessage(Stream inputStream)
위치: System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(Exception& requestException)
위치: System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
위치: System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
위치: System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
위치: System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
위치: System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
위치: System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
위치: System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
위치: System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
위치: System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
위치: ServiceProxy.IFactInternetSales.SelectFactInternetSalesDs()
위치: ClientApp.ClientApp.btnServiceCall_Click(Object sender, EventArgs e) 파일 F:\DOTNET30_CODE\WCF_DataNormal\ClientApp\ClientApp.cs:줄 63
---------------------------
---------------------------
자, 여기서 보아야 할 문제는 이젠 맘대로 데이터를 주고 받을 수없다는 것이다
직렬화한 객체 사이즈가 int최대값을 넘어간다거나
메세지를 받는 클라이언트 입장에서 채널에서 받을 메세지 크기가 int사이즈가 넘어가면
못받는 다는 것이다.
이런 젠장...
머리가 뒤지게 아파왔다. 왜이런 제약을 만들어서 골치아프게 하나...
우선, 왜 제한을 두었냐가 중요하다
겁나게 많은 데이터를 리턴하는 하나의 연결이 있다고 가정하자
클라이언트 - 웹서버 상에서 클라이언트가 무지 많은 데이터를 조회하면
어케 될까?..당근 빠따루 웹서버가 CPU와 Memory점유율이 엄청 높아지면서
웹서버가 힘들어 할 것이고 다른 요청들에게 다른 작업을 하기 위한 리소스를 할 당할 수없는
문제가 발생할 것이다.
이럴때, 익스를 죽이거나, 웹서버를 리스타트 하는 방법(튜닝 문제라 슬쩍 넘어간다)등 무식한
방법을 쓸것이다
이제, WCF는 이젠 코드 상에서 명시한 Max Size를 넘는 넘들은 Exception을 발생시켜버린다
이는, 한넘때문에 다른 연결들에게 추가 리소스를 할 당하는데 문제가 생기는 문제를 해결할 수있다
즉, 악의적(malicious)이거나, 의도되지 않았거나(unintentional), Denial of Service (DOS) attacks을 막을 수 있는 효휼적인 메카니즘이라는 것이다.
WCF Transport Quota
1. Timeouts : DOS공격을 완화시킬 수있다
2. Memory allocation limits(메모리 할당 제한) : 하나의 연결이 리소스를 고갈시켜 다른 연결들에
서비스를 거부하는(deny service)것을 막을 수있다
3. Collection size limits : 제한적인 서비스 양으로 인해 간접적으로 메모리 소진을 줄일 수있다.
자세한 제한 사항 설정에 대한 것은
ms-help://MS.MSSDK.1033/MS.NETFX30SDK.1033/WCF_con/html/3e71dd3d-f981-4d9c-9c06-ff8abb61b717.htm를 참조하세요
이러한, 장점(?)에도 불구하고 역시 불편하다는 것이다
당연히 테이블과 설계가 잘 되어있다면 많은 데이터가 전송되는 것을 피할 수있지는 모르지만
업무상 특정 업무에서는 잘 알다시피 X나게 많은 데이터를 한 화면에 페이징 없이 보여주기를
사용자들은 원한다는 것이다.
따라서, 도데체 int의 최대값이란 것이 얼마나 많은 행을 리턴할 수있는 크기인지 도데체
어떻게 알 수있다는 말인가
단지, catch에서 Exception을 통해 데이터가 너무 많아서 보여줄 수없어요 또는 서비스가 잠시
중단 되었습니다 라고 보여줄 것인가?...
아! ~~ 정말 고민이다. 앞으로 어케할 것인가....
2. DataTable 넘길 수있나?
못넘긴다.
DataSet은 MarshalByValueComponent, IListSource, IXmlSerializable, ISupportInitializeNotification, ISupportInitialize, ISerializable를 상속받는다
DataTable은 MarshalByValueComponent, IListSource, ISupportInitializeNotification, ISupportInitialize, ISerializable, IXmlSerializable를 상속받는다
따라서, DataTable은 직렬화 가능한 원격객체이다.
하지만, .NET Framework 2.0에서 웹서비스로 만들어서 DataTable넘겨 보시면
알겠지만 에러 발생합니다.
그리고 해결방법으로는 http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=0&detail=1&wid=338 참조하기 바란다
svcutil.exe를 통해 노출되는 프록시를 보면 DataSet 반환형은 DataSet이지만
DataTable은
public SelectFactInternetSalesDtResponseSelectFactInternetSalesDtResult SelectFactInternetSalesDt()
{
SelectFactInternetSalesDtRequest inValue = new SelectFactInternetSalesDtRequest();
SelectFactInternetSalesDtResponse retVal = ((IFactInternetSales)(this)).SelectFactInternetSalesDt(inValue);
return retVal.SelectFactInternetSalesDtResult;
}
{
SelectFactInternetSalesDtRequest inValue = new SelectFactInternetSalesDtRequest();
SelectFactInternetSalesDtResponse retVal = ((IFactInternetSales)(this)).SelectFactInternetSalesDt(inValue);
return retVal.SelectFactInternetSalesDtResult;
}
와 같이 반환형이 황당무계한 넘이 다라는 것이다.
유경상씨에 의하면 이를 object로 넘겨서 DataTable로 형변환 하면된다
정성태씨에 의하면 machine.config에 Serialization설정을 해주면
정상 리턴된다
이렇게 하고 있지만, WCF상에서는 전혀 안된다
에러는 DataTable은 직렬화 될 수없습니다 라는 것이다.
거짓말 장이 MS....
아무튼, 안된다
그리고, 굳이 DataSet, DataTable로 왜 넘기느냐가 Forum에 답이다.
이전에도 그랬고 앞으로도 Typed DataSet, Struct, 사용자 정의 클래스, 또는 Object배열등
이런것들로 만들어 넘겨라라는 것이다
알다시피 XML덩어리인 DataSet은 데이터 양이 많을때 직렬화를 거치는 과정에서
엄청난 메모리를 사용하며, 이를 XML로 만들어보면 어마머마 하다는 것이다
하지만, 앞으로 포스트할 사용자 정의 클래스를 보자면 더욱더 짜증날 것이다
짜증난다는 것은 문제점이 많고 어렵고 공부해야될 게 많고 해결해야 될게 많다는 것이다...
[출처] [본문스크랩] [WCF]데이터 보내기1|작성자 관절분리
반응형
'c#' 카테고리의 다른 글
Visual Studio 2005 IDE Tip / 단축키 (0) | 2016.01.27 |
---|---|
동적 배열 (0) | 2016.01.27 |
합계구한 컬럼을 DataTable에 추가하기 (0) | 2016.01.27 |
C#에서의 IO [3/3] (0) | 2016.01.27 |
C#에서의 IO [2/3] (0) | 2016.01.27 |