카테고리

분류 전체보기 (510)
문학 (128)
찬양 콘티(Continuity) (80)
Business as heritage (6)
IT . Web (149)
Photo (127)
etc. (20)
Total348,470
Today59
Yesterday147
*20121219 국치가 회복될 사건이 올 때까지 블로그 양쪽은 조의를 표하는 검정색입니다.
Tistory 로고 이미지 티스토리 가입하기!









블로그 이미지

지난 번에 C# 직렬화와 관련해서
라는 포스팅을 한 적이 있었습니다. 위 글에서도 단순한 타입들만 프로퍼티로 갖고 있는 클래스들을 직렬화해서 세션에 담고, 역직렬화해서 재사용하는데 문제는 없습니다.

그런데 직접 작성해서 클래스 위에 [Serializable]을 명시한 경우나 닷넷 프레임워크 제공 클래스처럼 수정할 수 없는 dll에 포함된 클래스이면서 [Serializable]이 명시되어 있거나 ISerializable 인터페이스를 구현한 경우면 괜찮은데, 그렇지 않은 클래스 또는 그렇지 않은 클래스의 객체를 프로퍼티로 포함하는 경우 문제가 될 수 있습니다.

대표적인 예로 딕셔너리가 그렇습니다. 지난 포스팅의 방식으로 딕셔너리를 프로퍼티로 갖는 클래스의 직렬화를 시도하면 아래처럼 에러메시지를 만나게 됩니다.

You must implement a default accessor on System.Collections.Generic.SortedDictionary`2+ValueCollection[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[MyClass, App_Code.d1a_4wmy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] because it inherits from ICollection.

그렇다고.. 그래 그럼 구현[implement]하지 뭐! 하시면 안됩니다. 밑바닥부터 System.Collections.Generic.SortedDictionary를 그대로 베낀 녀석에 인덱서만 따로 추가하는 것도 좀 소모적이구요.

대신 좀 더 Raw 한 방식으로 직렬화를 할 수 있습니다. 아래의 방식을 쓰면 이러한 에러를 만나지 않습니다. 한 편으로는 좀 더 가벼울지도 모르겠네요. 어차피 웹서비스가 아니라 세션에 담는 것이 주 관심시라면 XML이 꼭 필요한 건 아니니까요. 메모리 스트림을 쓰면 굳이 파일에 쓰는 일도 피할 수 있습니다.


using System.Runtime.Serialization.Formatters.Binary;
.......
        public static Byte[] serializeObject(Object o)
        {
            MemoryStream ms = new MemoryStream(1024 * 16);
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, o);

            return ms.ToArray();
        }

        public static Object deserializeObject(Byte[] os)
        {
            MemoryStream ms = new MemoryStream(1024 * 16);

            foreach (Byte b in os)
                ms.WriteByte(b);

            ms.Position = 0;
            
            BinaryFormatter bf = new BinaryFormatter();

            return bf.Deserialize(ms);
        }

메모리 스트림의 크기는 용도에 따라 조절해서 쓰시면 되겠습니다.

악. 어제부터 헤멨는데 결국 성공은 했습니다. 구글링을 하도 했더니 눈이... 외국 개발자분들도 이 문제로 좀 헤메이신 듯.

============ 테스트 후 추가

그런데.. 이 방식은 직렬화가 가능한 대신 XML 방식과 달리 cs 파일 자동 수정 시 버전차이발생에 영향을 받는 것 같습니다. 아... 모든 것은 원점으로 돌아가는 건가요. 결국 안정수준에 이르러 왠만해선 바뀌지 않으면서 세션에 담기는 클래스들은 그냥 dll로 만들어서 관리하는 편이 좋은 걸까요. 그럼 조금 헛고생 한 건데ㅠㅜ; 직렬화코드를 별도로 안만들어도 무방했을 뻔ㅋㅋㅋ

XML 방식은 버전차이에 따른 영향은 안받지만 Dictionary 등을 직렬화하지 못해서 문제, 기본 방식은 버전차이에 영향을 받아서 문제.~

============ 일보 전진
Binder Property 를 쓰면 App_Code 아래 .cs 파일의 자동생성 .dll 버전이 바뀌는 것을 극복할 수 있습니다.

위 코드에 Binder 프로퍼티를 설정해줍니다.

BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new AllwaysBrandnewDeserializationBinder();

return bf.Deserialize(ms);

.....
    
using System.Reflection;
    
using System.Runtime.Serialization;
    
using System.Runtime.Serialization.Formatters.Binary;
    sealed class AllwaysBrandnewDeserializationBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Type typeToDeserialize = null;

            assemblyName = Assembly.GetExecutingAssembly().FullName;
            // 이 코드 또한 App_Code 아래에 있다면 직렬화 당시의 어셈블리 버전 대신 현재 어셈블리 버전을 반환할 것이므로, 클래스 내용 자체는 같고 리빌드만 된 경우 현재 버전으로 문제 없이 역직렬화 가능
            typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
                typeName, assemblyName));

            return typeToDeserialize;
        }
    }

1. 세션에 담고 싶은 객체가 .NET Framework 내에 기본 제공되는 것이라면 그냥

Session["a"] = new HashTable();
HashTable a = (HashTable)Session["a"];

2. App_Code 아래 코드처럼 리빌드 할 때마다 클래스의 변화가 없어도 버전차이가 생긴다면

Session["a"] = serializeObject(new HashTable());
HashTable a = deserializeObject((Byte[])Session["a"]) as HashTable;

그리고 SQL Server 모드로 세션을 관리하면 App_Code 수정에도 멈추지 않고 운영되는 ASP.NET 사이트 만들기 성공.

저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by One of Remnants

댓글을 달아 주세요

  1. 2010.04.23 13:19 신고 One of Remnants  댓글주소  수정/삭제  댓글쓰기

    이유는 정확히 모르겠지만, 이 방식으로 역직렬화할 때 System.Collections.Generic.Dictionary 콜렉션을 속성으로 포함하고 있는 사용자 정의 클래스의 경우에는 Website를 Restart하면 외부 세션 저장소의 Byte Array를 다시 가져올 때 Dictionary에 포함된 Value 객체를 역직렬화하는데 실패합니다.(새 세션은 잘 동작)
    - Object of type 'Kr.A.YourClass' cannot be converted to type 'Kr.A.YourClass'.

    하지만 System.Collections.Generic.SortedDictionary 로 바꿔주면 이런 문제가 발생하지 않습니다.

  2. 2010.10.12 01:46 신고 별찌  댓글주소  수정/삭제  댓글쓰기

    지민냥 덕분에 어려움을 잘~ 풀었습니다. 감사합니다.^^

달력

« » 2017.08
    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    

최근에 받은 트랙백

글 보관함

티스토리 툴바