Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从XML反序列化对象时出现间歇性错误_C#_.net_.net 3.5_Xml Serialization - Fatal编程技术网

C# 从XML反序列化对象时出现间歇性错误

C# 从XML反序列化对象时出现间歇性错误,c#,.net,.net-3.5,xml-serialization,C#,.net,.net 3.5,Xml Serialization,我有一个程序,它将对象作为XML存储在数据库(基本上是一个消息队列)中并反序列化它们。我会间歇性地出现以下错误之一: System.Runtime.InteropServices.ExternalException: Cannot execute a program. The command being executed was "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe" /noconfig /fullpaths @"C:\Do

我有一个程序,它将对象作为XML存储在数据库(基本上是一个消息队列)中并反序列化它们。我会间歇性地出现以下错误之一:

System.Runtime.InteropServices.ExternalException: Cannot execute a program. The command being executed was "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe" /noconfig /fullpaths @"C:\Documents and Settings\useraccount\Local Settings\Temp\lh21vp3m.cmdline".
   at System.CodeDom.Compiler.Executor.ExecWaitWithCaptureUnimpersonated(SafeUserTokenHandle userToken, String cmd, String currentDir, TempFileCollection tempFiles, String& outputName, String& errorName, String trueCmdLine)
   at System.CodeDom.Compiler.Executor.ExecWaitWithCapture(SafeUserTokenHandle userToken, String cmd, String currentDir, TempFileCollection tempFiles, String& outputName, String& errorName, String trueCmdLine)
   at Microsoft.CSharp.CSharpCodeGenerator.Compile(CompilerParameters options, String compilerDirectory, String compilerExe, String arguments, String& outputFile, Int32& nativeReturnValue, String trueArgs)
   at Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
   at Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources)
   at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, String[] sources)
   at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource(CompilerParameters options, String[] sources)
   at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
   at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
   at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
   at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type)
   .....
或者我要这个:

System.InvalidOperationException: Unable to generate a temporary class (result=1).
error CS0016: Could not write to output file 'c:\Documents and Settings\useraccount\Local Settings\Temp\nciktsd7.dll' -- 'Could not execute CVTRES.EXE.'

   at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
   at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
   at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
   at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type)
   ....
这个程序一天成功地处理数千条消息,但我一天只收到2到3次这些错误。它们似乎与任何特定类型的信息都没有关联,只是完全随机的

知道是什么导致了这些错误以及如何修复它吗

ETA-以下是导致错误的代码,以防有帮助:

public class MessageContextBuilder<T> where T : MessageContextBase 
{
    private static IDictionary<string, XmlSerializer> SerializerCache { get; set; }
    public ILog Logger { get; set; }


    public MessageContextBuilder() {
        if (SerializerCache == null) SerializerCache = new Dictionary<string, XmlSerializer>();
        Logger = LogContextManager.Context.GetLogger<MessageContextBuilder<T>>();
    }

    public T BuildContextFromMessage(IEmailQueueMessage msg) {
        XmlSerializer serializer = GetSerializer(typeof(T));
        XmlReader r = XmlReader.Create(new StringReader(msg.MessageDetails));
        if (serializer.CanDeserialize(r)) {
            T rval = (T)serializer.Deserialize(r);
            rval.EmailAddress = msg.EmailAddress;
            rval.LocaleID = msg.LocaleID;
            rval.StoreID = msg.StoreID;
            rval.MessageID = msg.UniqueKey;
            return rval;
        } else {
            throw new ArgumentException("Cannot deserialize XML in message details for message #" + msg.UniqueKey);
        }
    }

    public XmlSerializer GetSerializer(Type t) {
        if (!SerializerCache.ContainsKey(t.FullName)) {
            SerializerCache.Add(t.FullName, new XmlSerializer(t)); // Error occurs here, in XmlSerializer constructor, intermittently
        }
        return SerializerCache[t.FullName];
    }
}
公共类MessageContextBuilder,其中T:MessageContextBase
{
私有静态IDictionary SerializerCache{get;set;}
公共ILog记录器{get;set;}
public MessageContextBuilder(){
如果(SerializerCache==null)SerializerCache=new Dictionary();
Logger=LogContextManager.Context.GetLogger();
}
公共T BuildContextFromMessage(IEmailQueueMessage消息){
XmlSerializer serializer=GetSerializer(typeof(T));
XmlReader r=XmlReader.Create(新的StringReader(msg.MessageDetails));
if(序列化程序CanDeserialize(r)){
T rval=(T)序列化程序。反序列化(r);
rval.EmailAddress=msg.EmailAddress;
rval.LocaleID=msg.LocaleID;
rval.StoreID=msg.StoreID;
rval.MessageID=msg.UniqueKey;
返回rval;
}否则{
抛出新ArgumentException(“无法反序列化消息#的消息详细信息中的XML”+msg.UniqueKey);
}
}
公共XmlSerializer GetSerializer(类型t){
如果(!SerializerCache.ContainsKey(t.FullName)){
SerializerCache.Add(t.FullName,新的XmlSerializer(t));//此处在XmlSerializer构造函数中间歇性发生错误
}
返回SerializerCache[t.FullName];
}
}

这是一个迹象,表明您没有缓存一点都不好的序列化程序=>这会导致内存泄漏,我怀疑您会遇到这种情况

请记住,每次创建序列化程序时,.NET都会生成代码并将其编译成程序集

始终创建序列化服务器,然后缓存它们

以下是一个示例:

public class SerialiserCache
{

    private static readonly SerialiserCache _current = new SerialiserCache();
    private Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();

    private SerialiserCache()
    {

    }

    public static SerialiserCache Current
    {
        get { return _current; }
    }

    public XmlSerializer this[Type t]
    {
        get
        {
            LoadIfNecessary(t);
            return _cache[t];
        }
    }

    private void LoadIfNecessary(Type t)
    {

        // double if to prevent race conditions 
        if (!_cache.ContainsKey(t))
        {
            lock (_cache)
            {
                if (!_cache.ContainsKey(t))
                {
                    _cache[t] = new XmlSerializer(typeof(T));
                }
            }
        }
    }

}
公共类序列化缓存
{
私有静态只读SerialiserCache _current=new SerialiserCache();
私有字典_cache=新字典();
私有SerialiserCache()
{
}
当前公共静态序列化缓存
{
获取{return\u current;}
}
公共XmlSerializer此[类型t]
{
得到
{
如有需要(t);
返回_缓存[t];
}
}
专用空心荷载(如有必要)(t型)
{
//加倍if以防止比赛条件
if(!\u cache.ContainsKey(t))
{
锁(_缓存)
{
if(!\u cache.ContainsKey(t))
{
_cache[t]=新的XmlSerializer(typeof(t));
}
}
}
}
}

XmlSerializer被认为是线程安全的

即使是这种情况,您也可以注意到,在这两种情况下,您得到的行为都在以下位置失败:
XmlSerializer..ctor(Type)

考虑到这一点,试图创建序列化程序看起来很像是多线程限制

我建议您使用以下代码:

public XmlSerializer GetSerializer(Type t) {
        if (!SerializerCache.ContainsKey(t.FullName)) {
            SerializerCache.Add(t.FullName, new XmlSerializer(t)); // Error occurs here, intermittently
        }
        return SerializerCache[t.FullName];
    }
并在Add上实现一个锁。这样,一次只能创建一个序列化程序。如果你没有处理成吨的不同类型,那么影响很小

请注意,无论如何都需要锁,因为如果同时添加两个类型,可能会出现重复的异常

static object serializerCacheLock = new object();
public XmlSerializer GetSerializer(Type t) {
        if (!SerializerCache.ContainsKey(t.FullName))
        lock(serializerCacheLock)
        if (!SerializerCache.ContainsKey(t.FullName)) {
            SerializerCache.Add(t.FullName, new XmlSerializer(t));
        }
        return SerializerCache[t.FullName];
    }
如果以上仍然不够,我会尝试对序列化器构造函数使用读/写锁,而不是序列化器使用。我们的思路是,多线程问题可能比同时运行两个CTOR更有价值

static object serializerCacheLock = new object();
public XmlSerializer GetSerializer(Type t) {
        if (!SerializerCache.ContainsKey(t.FullName))
        lock(serializerCacheLock)
        if (!SerializerCache.ContainsKey(t.FullName)) {
            SerializerCache.Add(t.FullName, new XmlSerializer(t));
        }
        return SerializerCache[t.FullName];
    }

所有这些都是一个巨大的猜测,但如果是我,我肯定不会这样做。

你可以预先创建序列化程序:试试看。这类问题的下一个典型候选对象是您的病毒扫描程序。创建序列化程序时,工具正在写入光盘。我见过病毒扫描程序在这种情况下产生各种奇怪的错误。

对于第一个错误(无法执行程序),您可能遇到了与我们遇到的相同的错误。当Directory.CurrentDirectory设置为不再存在的文件夹时,XmlSerlializer会引发该异常

我们的具体情况与你们的不同,但我会给出细节,以防它有助于了解可能发生的事情,或者它有助于其他人。在我们的案例中,少数客户在直接从安装程序启动WinForms应用程序后会出现该错误,即他们在安装或升级后选择了“立即运行”选项。(不清楚为什么会发生在某些人身上,但其他人却没有)。我们怀疑的是,我们的安装程序(InstallAware)偶尔启动应用程序时,将当前目录设置为不再存在或即将删除的文件夹。为了验证这一理论,我编写了一个测试应用程序,模拟从安装程序启动:

    string dir = @"C:\Users\me\Documents\Temp\WillBeDeleted";
    Directory.CreateDirectory(dir);
    Directory.SetCurrentDirectory(dir);

    Process.Start(@"C:\Program Files (x86)\...\our.exe");

    Directory.SetCurrentDirectory(@"C:\");  // otherwise, won't be able to delete
    Directory.Delete(dir);

果然,一旦启动的应用程序创建了XmlSerializer的新实例,就会抛出异常。我放入跟踪语句以显示GetCurrentDirectory()的结果,实际上它被设置为WillBeDeleted文件夹。修复方法是在应用程序初始化期间,在进行任何序列化之前,将CurrentDirectory设置到一个有效位置。

这是一个很好的技巧,我将对此进行介绍,但这与该程序的设置方式无关。基本上,它每隔几分钟作为作业运行一次,处理几条消息,然后退出。因此,缓存序列化程序的好处微乎其微。如果在同一个ruun中多次创建序列化程序,则可能会有好处