XmlSerializer memberikan FileNotFoundException di konstruktor

347

Aplikasi yang saya gunakan tidak berfungsi ketika saya mencoba membuat serial.

Pernyataan seperti

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

menghasilkan:

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)

Saya tidak mendefinisikan serializers khusus untuk kelas saya.

Bagaimana saya bisa memperbaiki masalah ini?

Irwin
sumber
5
OK, jadi pertanyaan ini hanyalah versi C # saya dari pertanyaan VB yang sudah diajukan: stackoverflow.com/questions/294659/… Terima kasih semuanya.
Irwin
1
Enam tahun kemudian, jawaban @VladV adalah solusi paling sederhana dan paling tidak merugikan. Cukup ubah Generate serialization assemblytarik-turun ke "Aktif", alih-alih "Otomatis".
Heliac
@Heliac: Saya tidak setuju. Itu tidak selalu berhasil. Silakan lihat komentar Benoit Blanchon untuk jawaban Vlad. Jawaban paling sederhana bagi saya adalah tidak menggunakan String.Collection dalam file konfigurasi. Sebagai gantinya saya menggunakan: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison

Jawaban:

388

Percaya atau tidak, ini adalah perilaku normal. Pengecualian dilemparkan tetapi ditangani oleh XmlSerializer, jadi jika Anda abaikan saja semuanya akan berlanjut dengan baik.

Saya telah menemukan ini sangat menjengkelkan, dan ada banyak keluhan tentang ini jika Anda mencari di sekitar sedikit, tetapi dari apa yang saya baca Microsoft tidak berencana melakukan apa pun tentang hal itu.

Anda dapat menghindari popup Pengecualian setiap saat saat debugging jika Anda mematikan pengecualian kesempatan pertama untuk pengecualian khusus itu. Di Visual Studio, buka Debug -> Pengecualian (atau tekan Ctrl+ Alt+ E), Pengecualian Waktu Bersama Bahasa Umum -> System.IO -> System.IO.FileNotFoundException .

Anda dapat menemukan informasi tentang cara lain di sekitarnya dalam posting blog C # XmlSerializer FileNotFound pengecualian (yang membahas alat Chris Sells ' XmlSerializerPreCompiler ).

Martin Sherburn
sumber
162
Salah satu cara yang mungkin untuk menghilangkan masalah ini adalah centang opsi "Hanya kode saya" di Alat -> Opsi -> Debugging -> Opsi umum.
Frederic
26
@Frederic: Komentar ini luar biasa! Aku duduk di sini dengan "WTF !?" ekspresi di wajah saya, mencoba untuk memburu pengecualian palsu ini, dan saya menemukan pertanyaan ini, dengan jawaban (Ini kesalahan Microsoft, apa lagi yang baru?), tapi saya tidak ingin menonaktifkan penanganan pengecualian, karena saya mungkin membutuhkannya untuk kode saya. A +!
Kumba
27
Saya pikir saran Hans di bawah ini lebih berharga - gunakan pemanggilan metode yang berbeda yang tidak menghasilkan pengecualian ini sama sekali: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
cerah
3
Masalahnya adalah ini gagal dalam pengujian saya, jadi saya tidak bisa "mengabaikan" pengecualian
Csaba Toth
16
Maaf, tapi ini saran yang buruk. FileNotFoundException adalah salah satu yang lebih umum, dalam pengalaman saya, dan menonaktifkan pelaporan pengecualian ini hanya meminta masalah suatu hari nanti di masa depan. Lebih baik mengaktifkan 'Just My Code' atau mengaktifkan pembuatan rakitan serialisasi yang dijelaskan di bawah ini.
Quarkly
104

Seperti kata Martin Sherburn, ini adalah perilaku normal. Konstruktor XmlSerializer pertama kali mencoba menemukan rakitan yang bernama [YourAssembly] .XmlSerializers.dll yang harus berisi kelas yang dihasilkan untuk serialisasi tipe Anda. Karena DLL tersebut belum dihasilkan (mereka tidak secara default), FileNotFoundException dilemparkan. Ketika itu terjadi, konstruktor XmlSerializer menangkap pengecualian itu, dan DLL dihasilkan secara otomatis saat runtime oleh konstruktor XmlSerializer (ini dilakukan dengan membuat file sumber C # dalam direktori% temp% komputer Anda, kemudian mengompilasinya menggunakan kompiler C #). Konstruksi tambahan XmlSerializer untuk tipe yang sama hanya akan menggunakan DLL yang sudah dibuat.

UPDATE: Mulai dari .NET 4.5, XmlSerializertidak lagi melakukan pembuatan kode dan juga tidak melakukan kompilasi dengan kompiler C # untuk membuat perakitan serializer saat runtime, kecuali secara eksplisit dipaksa dengan menetapkan pengaturan file konfigurasi ( useLegacySerializerGeneration ). Perubahan ini menghilangkan ketergantungan pada csc.exedan meningkatkan kinerja startup. Sumber: .NET Framework 4.5 Readme , bagian 1.3.8.1.

Pengecualian ditangani oleh konstruktor XmlSerializer. Tidak perlu melakukan apa pun sendiri, Anda cukup mengklik 'Lanjutkan' (F5) untuk melanjutkan menjalankan program Anda dan semuanya akan baik-baik saja. Jika Anda terganggu oleh pengecualian menghentikan eksekusi program Anda dan muncul pembantu pembantu, Anda baik 'Just My Code' dimatikan, atau Anda memiliki FileNotFoundException diatur untuk menghentikan eksekusi ketika dilempar, bukan ketika 'Pengguna- tidak tertangani '.

Untuk mengaktifkan 'Just My Code', buka Tools >> Options >> Debugging >> General >> Enable Just My Code. Untuk mematikan penghentian eksekusi ketika FileNotFound dilempar, buka Debug >> Pengecualian >> Temukan >> masukkan 'FileNotFoundException' >> hapus centang kotak centang 'Dilempar' dari System.IO.FileNotFoundException.

Allon Guralnek
sumber
+1 untuk pembaruan: ini menjelaskan perilaku yang berbeda saat men-debug kasus uji
mbx
3
Pembaruan Anda menunjukkan bahwa pengecualian ini tidak boleh terjadi di .NET 4.5, tapi saya masih melihatnya.
Timbo
@ Timo: Saya tidak melihat mengapa Anda tidak akan mendapatkan pengecualian itu dengan .NET 4.5. Masih mencari file, dan jika file tersebut hilang, FileNotFoundExceptionakan dilempar. Perbedaannya bukan pada bagaimana keberadaan majelis diperiksa, tetapi bagaimana menghasilkannya begitu ditentukan bahwa itu hilang. Sebelumnya, digunakan generasi kode C # tekstual dengan panggilan ke kompiler C # untuk membuat IL. Dimulai dengan .NET 4.5, ia memancarkan IL secara langsung, tanpa menggunakan kompiler.
Allon Guralnek
1
Saya hanya berharap MS akan mengimplementasikan ini seolah-olah (File.Exists (...)) {Load} else {Fallback} alih-alih mencoba {Load} catch {Fallback}. Kontrol aliran berbasis pengecualian bau tidak enak dan membuat pengalaman debug saya lebih sulit dan rapuh dari yang diperlukan.
Timbo
1
@ Timo: Sederhana File.Exists()mungkin tidak cukup. Mencari lokasi bukan urusan sederhana, runtime terlihat di beberapa lokasi dan saya yakin perilaku berubah sesuai dengan lingkungan (aplikasi konsol vs di-host di IIS, dll). Saya kira apa yang seharusnya diimplementasikan adalah TryLoadAssembly()atau sesuatu yang serupa.
Allon Guralnek
63

Dalam properti proyek Visual Studio ("Build" halaman, jika saya ingat benar) ada opsi yang mengatakan "menghasilkan perakitan serialisasi". Coba nyalakan untuk proyek yang menghasilkan [Containing Assembly of MyType] .

VladV
sumber
4
Juga lihat stackoverflow.com/a/8798289/1164966 jika perakitan serialisasi masih belum dihasilkan oleh Visual Studio.
Benoit Blanchon
Jawaban terbaik, paling jelas, ringkas! Saya berharap saya bisa memilih lagi juga!
John Zabroski
59

Ada solusi untuk itu. Jika Anda menggunakan

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

harus menghindari pengecualian itu. Ini berhasil untuk saya.

PERINGATAN: Jangan gunakan beberapa kali, atau Anda akan memiliki kebocoran memori

Anda akan membocorkan memori seperti orang gila jika Anda menggunakan metode ini untuk membuat instance XmlSerializeruntuk jenis yang sama lebih dari sekali!

Ini karena metode ini mem-bypass caching bawaan yang disediakan XmlSerializer(type)dan XmlSerializer(type, defaultNameSpace)konstruktor (semua konstruktor lain juga memotong cache).

Jika Anda menggunakan metode apa pun untuk membuat XmlSerializer yang tidak melalui dua konstruktor ini, Anda harus menerapkan caching Anda sendiri atau Anda akan kehabisan memori.

quadfinity
sumber
44
PERINGATAN: Anda akan membocorkan memori seperti orang gila jika Anda menggunakan metode ini untuk membuat instance XmlSerializeruntuk jenis yang sama lebih dari sekali! Ini karena metode ini mem-bypass caching bawaan yang disediakan XmlSerializer(type)dan XmlSerializer(type, defaultNameSpace)konstruktor (semua konstruktor lain juga memotong cache). Jika Anda menggunakan metode apa pun untuk membuat XmlSerializeryang tidak melalui dua konstruktor ini, Anda harus menerapkan caching Anda sendiri atau Anda akan mengalami pendarahan memori.
Allon Guralnek
4
@ AllonGuralnek Yah aku akan terkutuk ... Anda benar-benar benar; penggalian lebih lanjut melalui Reflector menunjukkan bahwa meskipun ia memeriksa cache, ia melakukannya setelah menghasilkan perakitan serialisasi! Wtf?!?
JerKimball
4
Ternyata ini adalah bug yang dikenal: weblogs.asp.net/cschittko/archive/2005/01/14/353435.aspx
JerKimball
3
@ Jerkimball: Halaman itu sebenarnya tidak bohong. Ketika Anda menemukan, FromTypestampaknya mengisi cache. Jadi itu harus menjadi cara yang valid untuk menghangatkan XmlSerializercache kosong dalam satu pernyataan (seperti artikel menyarankan), tetapi cara yang sangat buruk untuk mengambil sesuatu dari itu (hanya boleh dilakukan melalui konstruktor paling sederhana). Bagaimanapun, saya tidak tahu itu bug, saya selalu berpikir apa pun yang bocor seharusnya bocor (seperti XmlSerializerkonstruktor yang lebih maju ). Saya bahkan tidak akan mempertimbangkan untuk menggunakan FromTypes()karena Anda bisa melakukannya types.Select(t => new XmlSerializer(t)).
Allon Guralnek
2
@ AllonGuralnek Aspek non-probing dari penggunaan FromTypesmemang memiliki daya tariknya - bahkan jika pengecualian yang dilemparkan semuanya tertangkap, ini adalah operasi yang murni; pendekatan 'tembolok cara Anda sendiri' tampaknya menjadi satu-satunya solusi, karena satu-satunya perbaikan yang didukung secara resmi terlihat dalam perakitan berbasis web yang tidak jelas. (sunting: terus terang, saya siap untuk mengirim semuanya ke kontrak data :))
JerKimball
22

Saya mengalami masalah ini dan tidak bisa mengatasinya dengan solusi yang disebutkan.

Lalu akhirnya saya menemukan solusinya. Tampaknya serializer tidak hanya membutuhkan tipe, tetapi tipe bersarang juga. Mengubah ini:

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

Untuk ini:

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

Memperbaiki masalah untuk saya. Tidak ada lagi pengecualian atau apapun.

Frosty
sumber
8
Ini berhasil untuk saya. Menggunakan .Net4.0 formatnya adalahvar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729
1
Ini juga bekerja untuk saya. Tapi sepertinya hanya diperlukan saat membuat serial, bukan saat deserialisasi. Mungkin itu masuk akal, mungkin juga tidak.
SteveCinq
2
Ini juga menghasilkan kebocoran memori, jika dijalankan berkali-kali.
Volodymyr Kotylo
9

Solusi saya adalah langsung ke refleksi untuk membuat serializer. Ini memotong pemuatan file aneh yang menyebabkan pengecualian. Saya mengemas ini dalam fungsi pembantu yang juga menangani caching serializer.

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;
    }
}
d - b
sumber
2 masalah di sini - pertama kode Anda tidak aman-thread, dan kedua (yang lebih penting) Anda mencoba untuk meniru apa yang sudah dilakukan .net runtime (berdasarkan ctor yang Anda gunakan). yaitu tidak perlu untuk kode ini
Dave Black
@ DaveBlack: Ya, jawaban quadfinity dengan caching ke ConcurrentDictionary akan lebih baik
d - b
@db Poin kedua saya adalah bahwa caching bahkan tidak diperlukan - selama Anda menggunakan salah satu dari 2 ctors yang di-cache kerangka kerja (OP menggunakan yang pertama). Dari MSDN: Untuk meningkatkan kinerja, infrastruktur serialisasi XML secara dinamis menghasilkan rakitan untuk membuat serial dan membatalkan deserialisasi jenis tertentu. Kerangka kerja menemukan dan menggunakan kembali majelis itu. Perilaku ini hanya terjadi ketika menggunakan ctors berikut: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) Referensi: msdn.microsoft.com/en-us/library/…
Dave Black
@ DaveBlack: Ya, tetapi konstruktor ini melempar dan menangkap pengecualian secara internal bahkan ketika penggunaannya benar-benar valid. Ini buruk, dan inilah alasan mengapa OP mengajukan pertanyaan sejak awal.
d - b
@ db Benar, tetapi apa yang ingin saya katakan (tetapi tidak jelas - permintaan maaf saya) adalah bahwa satu-satunya baris dari perusahaan Anda yang diperlukan adalah 3 baris pertama dalam kondisi yang lain.
Dave Black
8

Untuk menghindari pengecualian, Anda perlu melakukan dua hal:

  1. Tambahkan atribut ke kelas serial (saya harap Anda memiliki akses)
  2. Hasilkan file serialisasi dengan sgen.exe

Tambahkan atribut System.Xml.Serialization.XmlSerializerAssembly ke kelas Anda. Ganti 'MyAssembly' dengan nama majelis tempat MyClass berada.

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

}

Hasilkan file serialisasi menggunakan utilitas sgen.exe dan menyebarkannya dengan perakitan kelas.

'sgen.exe MyAssembly.dll' akan menghasilkan file MyAssembly.XmlSerializers.dll

Dua perubahan ini akan menyebabkan .net untuk menemukan perakitan secara langsung. Saya memeriksanya dan bekerja pada .NET framework 3.5 dengan Visual Studio 2008

Ami Bar
sumber
Oke, dan apakah itu gagal tanpa perubahan ini, dan jika demikian, mengapa?
John Saunders
1
Saya tidak dapat menemukan alasan mengapa proyek saya, 4.0 di VS2012, tiba-tiba mulai gagal. "Mengabaikan" kesalahan itu bukan pilihan, karena itu terjadi setiap kali saya mencoba mengakses Direktori Aktif; dengan demikian mengabaikan berarti tidak mengotentikasi. Saya masih sangat frustrasi bahwa VS2012 tidak akan secara otomatis menghasilkan serialisasi DLL dengan benar. Namun, langkah-langkah ini memberikan solusi yang sempurna.
sfuqua
6

Pengecualian ini juga dapat dijebak oleh asisten debugging terkelola (MDA) yang disebut BindingFailure.

MDA ini berguna jika aplikasi Anda dirancang untuk dikirimkan dengan rakitan serialisasi pra-bangun. Kami melakukan ini untuk meningkatkan kinerja aplikasi kami. Hal ini memungkinkan kami untuk memastikan bahwa rakitan serialisasi pra-dibangun sedang dibangun dengan benar oleh proses pembuatan kami, dan dimuat oleh aplikasi tanpa dibangun kembali dengan cepat.

Ini benar-benar tidak berguna kecuali dalam skenario ini, karena seperti yang dikatakan poster lainnya, ketika kesalahan pengikatan terperangkap oleh konstruktor Serializer, perakitan serialisasi dibangun kembali saat runtime. Jadi biasanya Anda bisa mematikannya.

HiredMind
sumber
6

Fungsi XmlSerializer.FromTypes tidak melempar pengecualian, tetapi bocor memori. Itulah mengapa Anda perlu men-cache serializer tersebut untuk setiap jenis untuk menghindari kebocoran memori untuk setiap instance yang dibuat.

Buat pabrik XmlSerializer Anda sendiri dan gunakan hanya:

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

Pabriknya terlihat seperti:

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;
    }       
}

Versi yang lebih rumit tanpa kemungkinan kebocoran memori (tolong seseorang tinjau kodenya):

    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;
    }       
}
Tomas Kubes
sumber
Anda harus menggunakan ConcurrentDictionary sebagai gantinya. Kode ini bisa menemui jalan buntu.
Behrooz
Bagaimana bisa jalan buntu jika semua manajemen dengan kamus ada di bagian kunci?
Tomas Kubes
Maaf, kata-kata saya membingungkan. Yang saya maksud adalah bisa memasukkan item lebih dari satu kali. karena ada kesenjangan antara saat memeriksa keberadaan dan ketika memasukkan. kamus serentak menggunakan semacam penguncian dua fase (tas [0] dan kemudian tas [hash]]) dan menyimpan referensi ke tas yang harus memasukkan / berisi item yang sedang Anda kerjakan. Lebih cepat, lebih aman dan bersih.
Behrooz
Iya dan tidak. Anda benar bahwa dapat terjadi bahwa dalam waktu yang bersamaan satu serializer dengan tipe yang sama akan dibuat pada dua utas secara paralel dan kemudian ditambahkan ke kamus dua kali. Dalam kasus seperti itu, insert kedua hanya akan menggantikan yang pertama, tetapi bagian kunci menjamin keamanan thread dan kerugian keseluruhannya adalah kebocoran memori yang kecil. Ini adalah pengoptimalan kinerja, karena Anda tidak ingin utas satu dengan Serializer tipe A menunggu diblokir oleh utas dua dengan serializer tipe B dalam skenario nyata.
Tomas Kubes
Saya bisa membayangkan solusinya mungkin lebih baik (tanpa kebocoran memori teoritis), tetapi lebih rumit.
Tomas Kubes
3

Pemecahan masalah kesalahan kompilasi di sisi lain sangat rumit. Masalah-masalah ini memanifestasikan dirinya dalam FileNotFoundException dengan pesan:

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() 

Anda mungkin bertanya-tanya apa hubungan file yang tidak ditemukan dengan instantiating objek serializer, tetapi ingat: konstruktor menulis file C # dan mencoba untuk mengompilasinya. Tumpukan panggilan pengecualian ini memberikan beberapa informasi yang baik untuk mendukung kecurigaan itu. Pengecualian terjadi ketika XmlSerializer berusaha memuat rakitan yang dihasilkan oleh CodeDOM yang memanggil metode System.Reflection.Assembly.Load. Pengecualian tidak memberikan penjelasan mengapa perakitan yang seharusnya dibuat oleh XmlSerializer tidak ada. Secara umum, rakitan tidak hadir karena kompilasi gagal, yang mungkin terjadi karena, dalam keadaan langka, atribut serialisasi menghasilkan kode yang gagal dikompilasi oleh kompiler C #.

Catatan Kesalahan ini juga terjadi ketika XmlSerializer berjalan di bawah akun atau lingkungan keamanan yang tidak dapat mengakses direktori temp.

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

Zyphrax
sumber
dia tidak menentukan bahwa ini terjadi saat runtime. Hal lain yang dapat saya pikirkan adalah bahwa Anda mungkin memiliki konflik namespace / kelas. Apa nama lengkap MyType Anda?
Zyphrax
Ya, saya memeriksa tautan Anda, info tentang konstruktor, meskipun membantu, bukan yang saya butuhkan.
Irwin
5
@SpaceghostAl Anda dapat mengkompilasi saat runtime. Dan itulah yang dilakukan XmlSerializer. Itu secara dinamis membangun saat runtime perakitan yang (de) membuat serialisasi XML untuk jenis tertentu. Untuk alasan apa pun proses ini gagal untuk OP. Mungkin karena masalah izin misalnya pada direktori temp. (Bisa konyol seperti keluar dari ruang disk bahkan.)
No
Apa kau yakin tentang ini? Saya cukup yakin bahwa hal-hal serialisasi akan dikompilasi menjadi sebuah perakitan dengan nama YourAssemblyName.XmlSerializers.dll selama pembuatan , tidak dikompilasi pada saat runtime. Ini bisa gagal karena segala macam alasan, apalagi dari semua izin NTFS di folder penempatan.
tomfanning
1
Saya berharap saya dapat memperbaiki ini beberapa kali. Catatan Anda tentang akun yang tidak dapat mengakses folder temp memicu jawaban untuk saya. Setelah saya menambahkan akun layanan saya ke grup admin di server, itu hanya berfungsi. Terima kasih!
Bob Horn
2

Dalam properti proyek Visual Studio ada opsi yang mengatakan "menghasilkan perakitan serialisasi". Coba nyalakan untuk proyek yang menghasilkan [Containing Assembly of MyType].

Pascal
sumber
1

Kelas khusus untuk membuat serial:

[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;
    }
}

Saya telah melampirkan cuplikan kode. Mungkin ini bisa membantu Anda.

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();
}
Shahjapan
sumber
2
-1 untuk tidak menggunakan blok untuk mencegah kebocoran sumber daya, dan untuk menggunakan XmlTextWriter.
John Saunders
ok setuju, tapi saya masih menggunakan XmlSerializer xmlSerializer = XmlSerializer baru (typeof (TestClass)); tapi saya tidak mendapatkan Pengecualian tersebut.
shahjapan
1

Saya mengalami masalah yang sama, dan mengabaikan pengecualian tidak berhasil untuk saya. Kode saya memanggil konfigurasi NServiceBusConfigure.With(...).XmlSerializer()...

Apa yang diperbaiki bagi saya adalah mengubah platform untuk proyek saya.

  1. Pergi ke Build \ Configuration Manager ...
  2. Temukan proyek Anda dan ubah Platform (dalam kasus saya dari x86 ke CPU Apa Pun)
kkelley
sumber
1

Sama seperti referensi. Mengambil dari jawaban dan komentar DB, saya datang dengan solusi yang dekat dengan solusi DB. Ini berfungsi dengan baik dalam semua kasus saya dan aman utasnya. Saya tidak berpikir bahwa menggunakan ConcurrentDictionary akan ok.

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;
            }
        }
    }
}

Pemakaian:

        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);
                }
            }
        }
Eric Ouellet
sumber
0

Jenis Anda dapat mereferensikan majelis lain yang tidak dapat ditemukan di GAC maupun di folder bin lokal Anda ==> ...

"atau salah satu dependensinya. Sistem tidak dapat menemukan file yang ditentukan"

Bisakah Anda memberikan contoh tipe yang ingin Anda serialkan?

Catatan: Pastikan jenis Anda mengimplementasikan Serializable.

Henrik
sumber
0

Saya mendapatkan kesalahan yang sama, dan itu karena jenis saya mencoba deserialize tidak memiliki konstruktor tanpa parameter default . Saya menambahkan konstruktor, dan mulai bekerja.

kay.one
sumber
0

Saya memiliki masalah yang sama sampai saya menggunakan alat Pihak ke-3 untuk menghasilkan Kelas dari XSD dan itu berhasil! Saya menemukan bahwa alat itu menambahkan beberapa kode tambahan di bagian atas kelas saya. Ketika saya menambahkan kode yang sama ini ke bagian atas kelas asli saya itu berhasil. Inilah yang saya tambahkan ...

#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
  {
  ...
TheJonz
sumber
0

Terlihat banyak rekomendasi untuk menggunakan ConcurrentDictionary, tetapi tidak ada contoh yang solid tentang itu, jadi saya akan melemparkan topi saya ke ras solusi ini. Saya bukan pengembang thread-aman, jadi jika kode ini tidak solid, silakan berbicara demi mereka yang mengikuti.

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);
        });
    }
}

Saya telah melihat posting lain yang melibatkan ConcurrentDictionarydan Lazymemuat nilainya. Saya tidak yakin apakah itu relevan di sini atau tidak, tapi ini kode untuk itu:

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;
}
Airn5475
sumber