2010-09-26 16 views
6

Mam problem z deserializacji XML, który mnie zaskakuje.Dlaczego XmlSerializer.Deserialize rzuca wyjątek System.IO.FileLoadException?

Buduję aplikację, która obsługuje lokalne dostosowywanie różnych usług, z których korzysta. Zaimplementowałem abstrakcyjną klasę ServiceLocator, której metody zwracają różne obiekty. Każda niestandardowa instalacja jest odpowiedzialna za wdrożenie podklasy tego i dostarczenie implementacji tych metod. Mięso tej klasy wygląda następująco:

public abstract class ServiceLocator 
{ 
    public static void Initialize(string customFeaturesPath) 
    { 
     Assembly a = Assembly.LoadFrom(customFeaturesPath); 
     Type t = a.GetExportedTypes() 
      .AsEnumerable() 
      .Where(x => x.IsSubclassOf(typeof (ServiceLocator))) 
      .First(); 
     Default = (ServiceLocator)a.CreateInstance(t.FullName); 
    } 

    public static ServiceLocator Default { get; private set; } 

    public abstract DefaultValuesContainer CreateDefaultValuesContainer(); 
} 

Działa to dobrze: otrzymuję ścieżka zwyczaju dysponuje zespół z pliku konfiguracyjnego aplikacji, program nazywa Initialize, a następnie aplikacja może wywołać różne metody na ServiceLocator.Default i zwracają odpowiednie niestandardowe implementacje usług.

Jedną z tych usług jest DefaultValuesContainer. Jest to prosty obiekt, który eksponuje właściwości, których wartości należy utrwalić w pliku ustawień użytkownika. Chodzi o to, że mogę przekształcić ten obiekt do postaci pojedynczego użytkownika typu string. Tworzy plik ustawień użytkownika, którego nie chcesz edytować ręcznie, ale jestem z tym fajny.

Oto konkretna realizacja ServiceLocator.CreateDefaultValuesContainer:

protected override DefaultValuesContainer CreateDefaultValuesContainer(string serializedXml) 
{ 
    DefaultValuesContainer c = new ClientDefaultValuesContainer(); 

    if (string.IsNullOrEmpty(serializedXml)) 
    { 
     return c; 
    } 
    XmlSerializer x = new XmlSerializer(c.GetType()); 
    return (DefaultValuesContainer) x.Deserialize(new StringReader(serializedXml)); 
} 

Teraz tutaj jest rzeczą.

Zbudowałem testy jednostkowe dla tego przy użyciu NUnit. Kiedy przeprowadzam testy w klasie testowej, która obsługuje niestandardowe funkcje klienta, działają. Kiedy uruchomić cały zestaw testów, ostatni wiersz powyższego sposobu rzuca ten wyjątek:

System.InvalidOperationException : There is an error in XML document (0, 0). 
    ----> System.IO.FileLoadException : Could not load file or assembly 'ClientCustomFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER)) 
    ----> System.ArgumentNullException : Value cannot be null. 
Parameter name: path1 

mam niby zaskoczony, dlaczego. Metoda SetUp nadal działa, a ServiceLocator.Default nadal zwraca obiekt typu ClientServiceLocator, co oznacza, że ​​załadował on zestaw ClientCustomFeatures. Rzeczywiście, sama metoda, która rzuca wyjątek, jest w zespole, o którym mówiono, że nie można go załadować.

Co to jest próbowanie zrobić tutaj XmlSerializer? Dlaczego próbuje załadować zestaw, który jest już załadowany? Co u licha oznacza "Nieprawidłowy wskaźnik"? A nade wszystko jak mam debugować coś takiego?

+2

Nie znam tego konkretnego błędu, ale zauważ, że XmlSerializer używa generowania kodu i kompilacji dynamicznej, więc próbuje utworzyć * nowy * zestaw, który odwołuje się do tych, których potrzebuje. Wygląda na to, że ten nowy (wygenerowany) zestaw nie jest zadowolony z odniesienia. Czy (na przykład) wszystkie niezbędne typy zawierają "publiczny"? –

+3

Jest to z pewnością problem odniesienia. Otwórz plik ClientCustomFeatures.dll w odbłyśniku i wyszukaj odniesienia, których nie masz. –

Odpowiedz

0

Miałem problemy z modułem ładującym zespołu (Fusion?), Gdy jeden zespół ładuje inny zestaw, który sam posiada odwołania (inne niż GAC). YourDLL.XmlSerializers.dll może być jednym z takich zgromadzeń. Spróbuj wyłączyć opcję Visual Studio, aby automatycznie generować zespół do serializacji XML (Opcje projektu) - spowoduje to usunięcie dodatkowego zespołu (a tym samym zależności).

0

Fusion Log Viewer

Aby pomóc zdiagnozować problemy ładowanie montaż jak te, spójrz na Fusion Log Viewer (aka fuslogvw.exe).

Fusion == składnik .NET, który lokalizuje i ładuje złoŜenia.

0

Spróbuj zamienić linię:

XmlSerializer x = new XmlSerializer(c.GetType()); 

z:

XmlSerializer x = new XmlSerializer(c.GetType(), new Type[] { typeof(DefaultValuesContainer), typeof(ClientDefaultValuesContainer) }); 
1

Jeśli niestandardowy montaż nie wie, gdzie można załadować zestawu zawierającego klasę ClientCustomFeatures będzie to zdarzyć. Dzieje się tak, gdy rozmieszczono niestandardowy zespół w lokalizacji, która nie znajduje się na ścieżce głównego zespołu, a główny zespół nie znajduje się w gac. Więc jeśli twoje niestandardowe assesje zostaną załadowane z podkatalogów twojego głównego zespołu, to powinno zniknąć. Jeśli jednak znajdują się w dowolnych miejscach, wystąpi problem, ponieważ muszą załadować główny zespół, ponieważ potrzebują dostępu do typu ClientCustomFeatures.

+0

Cóż, wszystkie zestawy są w tym samym katalogu, więc nie sądzę, że tak jest w tym przypadku. –

+1

Witaj Robert, spójrz na tę stronę: http://msdn.microsoft.com/en-us/library/aa302290.aspx Ma wiele doskonałych pomysłów na rozwiązywanie problemów, które odnoszą się do probelmu, który dostajesz i powody, dla których może się zdarzyć. Istnieje również link do narzędzia, które powinno pomóc w rozwiązaniu tego problemu. Ponieważ nie mamy dostępu do całego twojego kodu, nie możemy tego zrobić dla ciebie, ale będę bardzo ciekawy wiedzieć, jaki będzie wynik tej małej przygody :) Będziesz chciał spojrzeć na "Wyjątki w konstruktorze" "sekcja – Kell

+0

Pomyślnie o czymś: NUnit działa w tymczasowej lokalizacji pamięci podręcznej i może nie mieć odpowiednich uprawnień do ładowania wszystkich złożeń i generowania klas. Ale przeczytaj powyższy URL, ma o wiele więcej dróg dochodzenia lub Ciebie. – Kell

Powiązane problemy