생성자에서 FileNotFoundException을 제공하는 XmlSerializer


347

유형을 직렬화하려고 할 때 작업했던 응용 프로그램이 실패합니다.

다음과 같은 진술

XmlSerializer lizer = new XmlSerializer(typeof(MyType));

생산 :

System.IO.FileNotFoundException occurred
  Message="Could not load file or assembly '[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
  Source="mscorlib"
  FileName="[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  FusionLog=""
  StackTrace:
       at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

클래스에 대한 특수 직렬 변환기를 정의하지 않습니다.

이 문제를 어떻게 해결할 수 있습니까?


5
좋아, 그래서이 질문은 이미 요청한 VB 질문의 내 C # 버전입니다. stackoverflow.com/questions/294659/… 감사합니다.
Irwin

1
6 년 동안 @VladV의 답변은 가장 단순하고 부작용이 적은 솔루션입니다. Generate serialization assembly드롭 다운을 "자동"대신 "켜기"로 변경하십시오 .
Heliac

@Heliac : 동의하지 않습니다. 항상 작동하지는 않습니다. Vlad의 답변에 대한 Benoit Blanchon의 의견을 참조하십시오. 가장 간단한 대답은 구성 파일에서 String.Collection을 사용하지 않는 것입니다. 대신 다음을 사용합니다. string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison

답변:


388

믿거 나 말거나, 이것은 정상적인 행동입니다. 예외는 발생하지만 XmlSerializer에서 처리되므로 예외를 무시하면 모든 것이 잘 진행됩니다.

나는 이것이 매우 성가신 것을 발견했으며 조금 둘러 보면 이것에 대해 많은 불만이 있었지만, 내가 읽은 것에서 그것에 대해 아무것도 할 계획이 없습니다.

특정 예외에 대한 첫 번째 예외를 해제하면 디버깅하는 동안 항상 예외 팝업이 표시되는 것을 피할 수 있습니다. Visual Studio에서 디버그 -> 예외 (또는 Ctrl+ Alt+ E), 공용 언어 런타임 예외 -> System.IO- > System.IO.FileNotFoundException으로 이동하십시오 .

블로그 게시물 C # XmlSerializer FileNotFound 예외 (Chris Sells의 도구 XmlSerializerPreCompiler 설명) 에서 다른 방법에 대한 정보를 찾을 수 있습니다 .


162
이 문제를 제거하는 가능한 방법 중 하나는 도구-> 옵션-> 디버깅-> 일반 옵션에서 "내 코드 만"옵션을 선택하는 것입니다.
Frederic

26
@ Frederic :이 의견은 굉장합니다! 나는 "WTF와 함께 여기 앉아있다!?" 내 얼굴에 표현을 하고이 가짜 예외를 찾아 내려고 노력 하면서이 질문에 대한 답을 얻었습니다 (Microsoft의 결함, 새로운 것이 무엇입니까?).하지만 예외 처리를 비활성화하고 싶지 않았습니다. 내 코드. A +!
Kumba

27
아래 Hans의 제안이 더 가치 있다고 생각합니다.이 예외를 전혀 발생시키지 않는 다른 메소드 호출을 사용하십시오. XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
밝은

3
문제는 이것이 테스트에 실패했기 때문에 예외를 "무시"할 수 없다는 것입니다
Csaba Toth

16
미안하지만 이것은 끔찍한 제안입니다. FileNotFoundException은 내 경험상 가장 일반적인 것 중 하나이며이 예외보고를 비활성화하면 나중에 언젠가 문제가 발생합니다. 'Just My Code'를 켜거나 아래 설명 된 직렬화 어셈블리를 생성하는 것이 좋습니다.
Quarkly

104

Martin Sherburn이 말했듯이 이것은 정상적인 동작입니다. XmlSerializer의 생성자는 먼저 형식의 직렬화를 위해 생성 된 클래스를 포함해야하는 [YourAssembly] .XmlSerializers.dll이라는 어셈블리를 찾으려고합니다. 이러한 DLL은 아직 생성되지 않았으므로 (기본적으로는 아님) FileNotFoundException이 발생합니다. 이 경우 XmlSerializer의 생성자는 해당 예외를 포착하고 DLL은 XmlSerializer의 생성자에 의해 런타임에 자동으로 생성됩니다 (이는 컴퓨터의 % temp % 디렉토리에 C # 소스 파일을 생성 한 다음 C # 컴파일러를 사용하여 컴파일하여 수행됨). 동일한 유형의 XmlSerializer를 추가로 구성하면 이미 생성 된 DLL 만 사용됩니다.

업데이트 : .NET 4.5부터는 XmlSerializer구성 파일 설정 ( useLegacySerializerGeneration ) 을 설정하여 명시 적으로 강제하지 않는 한 런타임에 직렬 변환기 어셈블리를 만들기 위해 더 이상 코드 생성을 수행하거나 C # 컴파일러로 컴파일을 수행하지 않습니다 . 이 변경으로 인해 종속성이 제거되고 csc.exe시작 성능이 향상됩니다. 출처 : .NET Framework 4.5 추가 정보 , 섹션 1.3.8.1.

XmlSerializer의 생성자가 예외를 처리합니다. 아무것도 할 필요가 없습니다. '계속'(F5)을 클릭하여 프로그램을 계속 실행하면 모든 것이 정상입니다. 프로그램 실행을 중지하고 예외 도우미를 팝업으로 표시하는 예외로 인해 방해를 받으면 '사용자 정의'가 해제되었거나 'User- 처리되지 않은 '.

'내 코드 만'을 활성화하려면 도구 >> 옵션 >> 디버깅 >> 일반 >> 내 코드 만 활성화로 이동하십시오. FileNotFound가 발생할 때 실행 중단을 끄려면 디버그 >> 예외 >> 찾기 >>로 이동하여 'FileNotFoundException'을 입력하고 >> System.IO.FileNotFoundException에서 'Thrown'확인란을 선택 취소하십시오.


업데이트에 대한 +1 : 테스트 케이스를 디버깅 할 때이 서로 다른 동작을 설명
MBX

3
귀하의 업데이트에 따르면 .NET 4.5에서는이 예외가 발생하지 않아야하지만 여전히 그렇습니다.
Timbo

@ Timbo : .NET 4.5에서 왜 예외가 발생하지 않는지 모르겠습니다. 여전히 파일을 찾고 파일이 없으면 a FileNotFoundException가 발생합니다. 차이점은 어셈블리의 존재 여부를 확인하는 방법이 아니라 누락 된 것으로 확인되면 생성하는 방법입니다. 이전에는 C # 컴파일러를 호출하여 텍스트 C # 코드 생성을 사용하여 IL을 만들었습니다. .NET 4.5부터는 컴파일러를 사용하지 않고 직접 IL을 방출합니다.
Allon Guralnek

1
MS가 {Load} catch {Fallback}을 시도하는 대신 (File.Exists (...)) {Load} else {Fallback}로 구현하기를 바랍니다. 예외 기반의 흐름 제어는 악취가 나고 디버깅 경험이 필요 이상으로 어렵고 부서지기 쉽습니다.
Timbo

1
@Timbo : 단순 File.Exists()하지 않을 수 있습니다. 어셈블리를 찾는 것은 간단한 일이 아니며 런타임은 여러 위치를 살펴보고 환경에 따라 동작이 변경된다고 생각합니다 (콘솔 응용 프로그램 대 IIS에서 호스팅되는 등). 구현해야 할 TryLoadAssembly()것이 비슷한 것 같았습니다.
Allon Guralnek

63

Visual Studio 프로젝트 속성 ( "빌드"페이지, 올바르게 기억하면)에는 "직렬화 어셈블리 생성"이라는 옵션이 있습니다. [MyType의 어셈블리 포함] 을 생성하는 프로젝트의 경우 켜십시오 .


4
직렬화 어셈블리가 여전히 Visual Studio에서 생성되지 않은 경우 stackoverflow.com/a/8798289/1164966을 참조하십시오 .
Benoit Blanchon

가장 명확하고 간결한 답변! 다시 투표 할 수 있으면 좋겠다.
John Zabroski

59

이에 대한 해결 방법이 있습니다. 당신이 사용하는 경우

XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];

그 예외를 피해야합니다. 이것은 나를 위해 일했습니다.

경고 : 여러 번 사용하지 마십시오. 메모리 누수가 발생합니다

이 방법을 사용 XmlSerializer하여 같은 유형의 인스턴스를 두 번 이상 만들면 미친 것처럼 메모리가 누출됩니다 !

이는이 메소드가 XmlSerializer(type)XmlSerializer(type, defaultNameSpace)생성자를 제공 한 경우 내장 캐싱을 무시하기 때문입니다 (다른 모든 생성자도 캐시를 무시 함).

이 두 생성자를 통하지 않는 XmlSerializer를 만드는 방법을 사용하는 경우 고유 한 캐싱을 구현해야합니다. 그렇지 않으면 메모리가 출혈 될 수 있습니다.


44
경고 : 이 방법을 사용 XmlSerializer하여 같은 유형의 인스턴스를 두 번 이상 만들면 메모리가 미친 것처럼 누출됩니다 ! 이는이 메소드가 XmlSerializer(type)XmlSerializer(type, defaultNameSpace)생성자를 제공 한 경우 내장 캐싱을 무시하기 때문입니다 (다른 모든 생성자도 캐시를 무시 함). XmlSerializer이 두 생성자를 통하지 않는 방법을 사용하는 방법을 사용하는 경우 자체 캐싱을 구현해야합니다. 그렇지 않으면 메모리가 출혈 될 수 있습니다.
Allon Guralnek

4
@AllonGuralnek 글쎄, 난 망할거야 ... 당신은 절대적으로 정확합니다; Reflector를 통해 더 깊이 파고 들면 캐시를 확인하는 동안 직렬화 어셈블리를 생성 한 후에도 확인됩니다 ! WTF?!?
JerKimball


3
@JerKimball : 그 페이지는 실제로 거짓말이 아닙니다. 발견 한대로 FromTypes캐시를 채우는 것처럼 보입니다. 따라서 XmlSerializer기사에서 제안하는 것처럼 하나의 문에서 빈 캐시 를 예열하는 유효한 방법이어야 하지만 그중에서 아무것도 검색하지 못하는 가장 나쁜 방법입니다 (가장 간단한 생성자를 통해서만 수행해야 함). 어쨌든, 나는 그것이 버그라는 것을 몰랐다. 나는 항상 누출 된 것이 누출 될 것이라고 생각했다 (고급 XmlSerializer생성자 처럼 ). 당신이 FromTypes()할 수 있기 때문에 사용조차 고려하지 않았을 것 types.Select(t => new XmlSerializer(t))입니다.
Allon Guralnek

2
@AllonGuralnek 사용의 비 탐색 측면은 FromTypes호소력이있다. 예외가 모두 잡히더라도 가격이 비싼 작업이다. 공식적으로 지원되는 유일한 수정 프로그램이 모호한 웹 기반 어셈블리에있는 것처럼 보이기 때문에 '자신 만의 방식으로 캐시'접근 방식이 유일한 해결 방법 인 것 같습니다. (편집 : 솔직히, 나는 모든 것을 데이터 계약에 포팅하기 위해 모두 있습니다 :))
JerKimball

23

나는이 정확한 문제에 부딪 쳤고 언급 된 해결책으로 해결할 수 없었습니다.

그런 다음 마침내 해결책을 찾았습니다. 시리얼 라이저는 유형뿐만 아니라 중첩 유형도 필요로합니다. 이것을 변경 :

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

이에:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());

나를 위해 문제를 해결했습니다. 더 이상 예외 또는 아무것도 없습니다.


8
이것은 나를 위해 일했습니다. .Net4.0을 사용하는 형식은 다음과 같습니다.var xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729

1
이것은 나를 위해 일했다. 그러나 직렬화를 해제 할 때가 아니라 직렬화 할 때만 필요한 것 같습니다. 어쩌면 그럴 수도 있고 어쩌면 그렇지 않을 수도 있습니다.
SteveCinq

2
여러 번 실행하면 메모리 누수가 발생합니다.
Volodymyr Kotylo 2014 년

9

내 솔루션은 직렬화기를 만들기 위해 바로 반영하는 것입니다. 이는 예외를 일으키는 이상한 파일로드를 무시합니다. 직렬화기를 캐싱하는 도우미 기능으로 이것을 패키지했습니다.

private static readonly Dictionary<Type,XmlSerializer> _xmlSerializerCache = new Dictionary<Type, XmlSerializer>();

public static XmlSerializer CreateDefaultXmlSerializer(Type type) 
{
    XmlSerializer serializer;
    if (_xmlSerializerCache.TryGetValue(type, out serializer))
    {
        return serializer;
    }
    else
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(type, null, null);
        serializer = new XmlSerializer(mapping);
        return _xmlSerializerCache[type] = serializer;
    }
}

두 가지 문제-첫 번째 코드는 스레드로부터 안전하지 않으며 두 번째 (더 중요하게는) .net 런타임이 이미 수행중인 것을 복제하려고합니다 (사용중인 ctor를 기준으로). 즉,이 코드가 필요 없습니다
Dave Black

@DaveBlack : 예, ConcurrentDictionary에 캐싱하는 quadfinity의 대답이 더 좋습니다.
d--b

@db 내 두 번째 요점은 프레임 워크가 캐시하는 두 ctor 중 하나를 사용하는 한 캐싱이 필요하지 않다는 것입니다 (OP가 첫 번째 사용). MSDN에서 : 성능을 향상시키기 위해 XML 직렬화 인프라는 어셈블리를 동적으로 생성하여 지정된 유형을 직렬화 및 역 직렬화합니다. 프레임 워크는 이러한 어셈블리를 찾아 재사용합니다. 이 문제는 다음 ctor를 사용할 때만 발생합니다. XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) 참조 : msdn.microsoft.com/en-us/library/…
Dave Black

@DaveBlack : 예. 그러나 이러한 생성자는 사용법이 완전히 유효한 경우에도 내부적으로 예외를 발생시키고 포착합니다. 이것은 나쁘고 이것이 OP가 처음에 질문을 한 이유입니다.
d--b

@db True, 그러나 내가 말하고자하는 것은 (그러나 내 사과가 분명하지는 않았지만) 당신의 soln의 유일한 줄은 else 조건의 처음 3 줄이라는 것입니다.
Dave Black

8

예외를 피하려면 다음 두 가지를 수행해야합니다.

  1. 직렬화 된 클래스에 속성 추가 (액세스 권한이 있기를 바랍니다)
  2. sgen.exe를 사용하여 직렬화 파일 생성

클래스에 System.Xml.Serialization.XmlSerializerAssembly 특성을 추가하십시오. 'MyAssembly'를 MyClass가있는 어셈블리 이름으로 바꾸십시오.

[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{

}

sgen.exe 유틸리티를 사용하여 직렬화 파일을 생성하고 클래스의 어셈블리와 함께 배포하십시오.

'sgen.exe MyAssembly.dll'은 MyAssembly.XmlSerializers.dll 파일을 생성합니다

이 두 가지 변경 사항으로 인해 .net에서 어셈블리를 직접 찾을 수 있습니다. 확인하고 Visual Studio 2008의 .NET Framework 3.5에서 작동합니다.


좋아, 그리고 이러한 변화없이 실패 했습니까? 그렇다면 왜 그럴까요?
John Saunders

1
VS2012의 4.0 프로젝트가 갑자기 실패한 이유는 없습니다. "무시"오류는 옵션이 아닙니다. Active Directory에 액세스하려고 할 때마다 발생했기 때문입니다. 따라서 무시하는 것은 인증하지 않는 것을 의미합니다. VS2012가 직렬화 DLL을 올바르게 자동 생성하지 않는다는 것에 여전히 실망합니다. 그러나 이러한 단계는 완벽한 솔루션을 제공했습니다.
sfuqua

6

이 예외는 관리되는 디버깅 도우미에 의해 잡힐 수도 있습니다. BindingFailure라는 (MDA)에 .

이 MDA는 응용 프로그램이 사전 빌드 직렬화 어셈블리와 함께 제공되도록 설계된 경우 유용합니다. 애플리케이션의 성능을 향상시키기 위해이 작업을 수행합니다. 이를 통해 빌드 프로세스에서 사전 빌드 된 직렬화 어셈블리를 올바르게 빌드하고 애플리케이션을 즉시 빌드하지 않고도로드 할 수 있습니다.

다른 포스터가 말했듯이 Serializer 생성자에 의해 바인딩 오류가 발생하면 직렬화 어셈블리가 런타임에 다시 작성 되므로이 포스터를 제외하고는 실제로 유용하지 않습니다. 따라서 일반적으로 끌 수 있습니다.


6

함수 XmlSerializer.FromTypes는 예외를 throw하지 않지만 메모리가 누출됩니다. 따라서 생성 된 모든 인스턴스에서 메모리 누수가 발생하지 않도록 모든 유형에 대해 이러한 직렬 변환기를 캐시해야합니다.

자신의 XmlSerializer 팩토리를 작성하고 간단히 사용하십시오.

XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));

공장은 좋아 보인다 :

public static class XmlSerializerFactoryNoThrow
{
    public static Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();

    private static object SyncRootCache = new object();        

    /// <summary>
    /// //the constructor XmlSerializer.FromTypes does not throw exception, but it is said that it causes memory leaks
    /// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
    /// That is why I use dictionary to cache the serializers my self.
    /// </summary>
    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            //constructor XmlSerializer.FromTypes does not throw the first chance exception           
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            //serializer = XmlSerializerFactoryNoThrow.Create(type);
        }

        lock (SyncRootCache)
        {
            _cache[type] = serializer;
        }
        return serializer;
    }       
}

메모리 누수 가능성이없는보다 복잡한 버전 (누군가 코드를 검토하십시오) :

    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            lock (SyncRootCache)
            {
                if (_cache.TryGetValue(type, out serializer))
                    return serializer;
            }
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            lock (SyncRootCache)
            {
                _cache[type] = serializer;
            }
        }          
        return serializer;
    }       
}

대신 ConcurrentDictionary를 사용해야합니다. 이 코드는 교착 상태가 될 수 있습니다.
Behrooz

사전을 가진 모든 관리가 잠금 섹션에 있으면 어떻게 교착 상태가 될 수 있습니까?
Tomas Kubes

죄송합니다. 단어가 혼동되었습니다. 내가 의미하는 바는 항목을 두 번 이상 삽입 할 수 있다는 것입니다. 존재 여부와 삽입시기 사이에 간격이 있기 때문입니다. 동시 사전은 일종의 2 단계 잠금 (bag [0] 및 bag [hash]])을 사용하고 작업중인 항목을 삽입 / 포함해야하는 bag에 대한 참조를 유지합니다. 더 빠르고 안전하며 깨끗합니다.
Behrooz

예, 아니오 동시에 동일한 유형의 직렬 변환기가 두 스레드에서 병렬로 작성된 후 사전에 두 번 추가 될 수 있습니다. 이 경우 두 번째 인서트는 첫 번째 인서트를 대체하지만 잠금 섹션은 스레드 안전성을 보장하며 전반적인 단점은 작은 메모리 누수입니다. 실제 시나리오에서 A 유형의 시리얼 라이저가있는 스레드 1이 B 유형의 시리얼 라이저가있는 스레드 2에 의해 차단되는 것을 원하지 않기 때문에 이것은 성능 최적화입니다.
Tomas Kubes

솔루션이 더 좋을지 모르지만 (이론적 메모리 누수가 없음) 더 복잡 할 수 있습니다.
Tomas Kubes

3

반면에 컴파일 오류 문제 해결은 매우 복잡합니다. 이러한 문제는 FileNotFoundException 메시지와 함께 나타납니다.

File or assembly name abcdef.dll, or one of its dependencies, was not found. File name: "abcdef.dll"
   at System.Reflection.Assembly.nLoad( ... )
   at System.Reflection.Assembly.InternalLoad( ... )
   at System.Reflection.Assembly.Load(...)
   at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly() 

예외를 찾을 수없는 파일이 serializer 객체를 인스턴스화하는 것과 어떤 관련이 있는지 궁금 할 수 있지만 생성자는 C # 파일을 작성하고 컴파일하려고합니다. 이 예외의 호출 스택은 그러한 의심을 뒷받침 할 수있는 좋은 정보를 제공합니다. XmlSerializer가 System.Reflection.Assembly.Load 메서드를 호출하는 CodeDOM에 의해 생성 된 어셈블리를로드하려고 시도하는 동안 예외가 발생했습니다. XmlSerializer가 생성해야하는 어셈블리가 존재하지 않는 이유에 대한 설명은 예외로 제공되지 않습니다. 일반적으로 컴파일이 실패했기 때문에 어셈블리가 존재하지 않습니다. 드문 경우에 직렬화 속성이 C # 컴파일러가 컴파일하지 못한 코드를 생성하기 때문에 발생할 수 있습니다.

노트 오류는 XmlSerializer가 temp 디렉토리에 액세스 할 수없는 계정 또는 보안 환경에서 실행될 때도 발생합니다.

출처 : http://msdn.microsoft.com/en-us/library/aa302290.aspx


그는 이것이 런타임에 발생하도록 지정하지 않았습니다. 내가 생각할 수있는 또 다른 것은 네임 스페이스 / 클래스 충돌이있을 수 있다는 것입니다. MyType의 전체 이름은 무엇입니까?
Zyphrax

예, ur 링크를 확인했습니다. 생성자에 대한 정보는 도움이되었지만 필요한 것은 아닙니다.
Irwin

5
@SpaceghostAl 런타임에 컴파일 할 수 있습니다. 그리고 그것이 XmlSerializer가하는 일입니다. 런타임에 특정 유형에 대해 XML을 직렬화 해제하는 어셈블리를 동적으로 구성합니다. 어떤 이유로 든이 프로세스는 OP에 실패합니다. 아마도 임시 디렉토리와 같은 권한 문제 때문일 수 있습니다. (디스크 공간이
부족할

이거 확실하니? 빌드 중에 직렬화 항목이 YourAssemblyName.XmlSerializers.dll이라는 이름으로 어셈블리로 컴파일되고 런타임에는 컴파일되지 않았습니다. 배포 폴더에있는 모든 NTFS 권한 중 최소한 모든 이유로 실패 할 수 있습니다.
tomfanning

1
나는 이것을 여러 번 공표 할 수 있으면 좋겠다. 임시 폴더에 액세스 할 수없는 계정에 대한 귀하의 메모로 인해 답변이 트리거되었습니다. 서비스 계정을 서버의 관리자 그룹에 추가하면 방금 작동했습니다. 감사합니다!
밥 혼

2

Visual Studio 프로젝트 속성에는 "직렬화 어셈블리 생성"이라는 옵션이 있습니다. [MyType의 어셈블리 포함]을 생성하는 프로젝트의 경우 켜십시오.


1

직렬화 할 사용자 정의 클래스 :

[Serializable]
public class TestClass
{
    int x = 2;
    int y = 4;
    public TestClass(){}
    public TestClass(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int TestFunction()
    {
        return x + y;
    }
}

코드 스 니펫을 첨부했습니다. 아마도 이것은 당신을 도울 수 있습니다.

static void Main(string[] args)
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestClass));

    MemoryStream memoryStream = new MemoryStream();
    XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

    TestClass domain = new TestClass(10, 3);
    xmlSerializer.Serialize(xmlWriter, domain);
    memoryStream = (MemoryStream)xmlWriter.BaseStream;
    string xmlSerializedString = ConvertByteArray2Str(memoryStream.ToArray());

    TestClass xmlDomain = (TestClass)DeserializeObject(xmlSerializedString);

    Console.WriteLine(xmlDomain.TestFunction().ToString());
    Console.ReadLine();
}

2
리소스 누수를 방지하기 위해 블록을 사용하지 않고 XmlTextWriter를 사용하는 경우 -1입니다.
John Saunders

그래도 동의하지만 여전히 XmlSerializer를 사용했습니다. xmlSerializer = new XmlSerializer (typeof (TestClass)); 하지만 나는 예외를 얻지 못했습니다.
shahjapan

1

나는 비슷한 문제를 겪고 있었고 예외를 무시해도 효과가 없었습니다. 내 코드는 NServiceBus의 구성을 호출했습니다.Configure.With(...).XmlSerializer()...

나를 위해 고친 것은 내 프로젝트의 플랫폼을 변경하는 것이 었습니다.

  1. 빌드 \ 구성 관리자로 이동하십시오 ...
  2. 프로젝트를 찾고 플랫폼을 변경하십시오 (필자의 경우 x86에서 모든 CPU로)

1

참조로. DB 답변과 의견에서 DB 솔루션에 가까운이 솔루션을 제공했습니다. 그것은 모든 경우에 잘 작동하며 스레드 안전합니다. ConcurrentDictionary를 사용해도 괜찮을 것이라고 생각하지 않습니다.

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace HQ.Util.General
{
    public class XmlSerializerHelper
    {
        private static readonly Dictionary<Type, XmlSerializer> _dictTypeToSerializer = new Dictionary<Type, XmlSerializer>();

        public static XmlSerializer GetSerializer(Type type)
        {
            lock (_dictTypeToSerializer)
            {
                XmlSerializer serializer;
                if (! _dictTypeToSerializer.TryGetValue(type, out serializer))
                {
                    var importer = new XmlReflectionImporter();
                    var mapping = importer.ImportTypeMapping(type, null, null);
                    serializer = new XmlSerializer(mapping);
                    return _dictTypeToSerializer[type] = serializer;
                }

                return serializer;
            }
        }
    }
}

용법:

        if (File.Exists(Path))
        {
            using (XmlTextReader reader = new XmlTextReader(Path))
            {
                // XmlSerializer x  = new XmlSerializer(typeof(T));
                var x = XmlSerializerHelper.GetSerializer(typeof(T));

                try
                {
                    options = (OptionsBase<T>)x.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    Log.Instance.AddEntry(LogType.LogException, "Unable to open Options file: " + Path, ex);
                }
            }
        }

0

유형이 GAC 나 로컬 bin 폴더에서 찾을 수없는 다른 어셈블리를 참조 할 수 있습니다 ==> ...

"또는 해당 종속성 중 하나입니다. 시스템이 지정된 파일을 찾을 수 없습니다"

직렬화하려는 유형의 예를 제공 할 수 있습니까?

참고 : 유형이 Serializable을 구현하는지 확인하십시오.


0

동일한 오류가 발생했으며 기본 매개 변수가없는 생성자가 없는 직렬화를 해제하려고 시도한 유형 때문이었습니다 . 생성자를 추가하고 작동하기 시작했습니다.


0

XSD에서 클래스를 생성하기 위해 타사 도구를 사용할 때까지 동일한 문제가 발생했습니다. 도구가 클래스 상단에 여분의 코드를 추가하고 있음을 발견했습니다. 이 동일한 코드를 원래 클래스의 맨 위에 추가하면 효과가있었습니다. 내가 추가 한 내용은 다음과 같습니다.

#pragma warning disable
namespace MyNamespace
{
  using System;
  using System.Diagnostics;
  using System.Xml.Serialization;
  using System.Collections;
  using System.Xml.Schema;
  using System.ComponentModel;
  using System.Xml;
  using System.Collections.Generic;

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1064.2")]
  [System.SerializableAttribute()]
  [System.Diagnostics.DebuggerStepThroughAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
  public partial class MyClassName
  {
  ...

0

를 사용하는 권장 사항을 많이 ConcurrentDictionary보았지만 확실한 예는 없으므로이 솔루션 경주에 모자를 던질 것입니다. 나는 스레드 안전 개발자가 아니기 때문에이 코드가 확실하지 않은 경우 다음을 따르는 사람들을 위해 말하십시오.

public static class XmlSerializerHelper
{
    private static readonly ConcurrentDictionary<Type, XmlSerializer> TypeSerializers = new ConcurrentDictionary<Type, XmlSerializer>();

    public static XmlSerializer GetSerializer(Type type)
    {
        return TypeSerializers.GetOrAdd(type,
        t =>
        {
            var importer = new XmlReflectionImporter();
            var mapping = importer.ImportTypeMapping(t, null, null);
            return new XmlSerializer(mapping);
        });
    }
}

나는 값을 포함 ConcurrentDictionary하고 Lazy로드하는 다른 게시물을 보았습니다 . 이것이 관련이 있는지 확실하지 않지만 여기에 대한 코드가 있습니다.

private static readonly ConcurrentDictionary<Type, Lazy<XmlSerializer>> TypeSerializers = new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();

public static XmlSerializer GetSerializer(Type type)
{
    return TypeSerializers.GetOrAdd(type,
    t =>
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(t, null, null);
        var lazyResult = new Lazy<XmlSerializer>(() => new XmlSerializer(mapping), LazyThreadSafetyMode.ExecutionAndPublication);
        return lazyResult;
    }).Value;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.