«Тип * не ожидался. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые статически не известны». - PullRequest
0 голосов
/ 03 октября 2018

В моем приложении WPF у меня есть DataGrid, который извлекает значения из базы данных, эти значения используются в качестве параметров конфигурации для роботизированных компонентов машины.

Я пытаюсь добавить функцию для импорта / экспорта значений в сетке в / из XML-документа с использованием XML-сериализации (которую я никогда раньше не использовал), и я сталкиваюсь с несколькими проблемами, которые яне могу понять для жизни меня.

У меня есть метод Export(), который должен позаботиться об экспорте значений в XML-документ:

public void Export()
    {
        XmlSerializer serialiser = new XmlSerializer(MasterDataGrid.ItemsSource.GetType());

        using (TextWriter writer = new StreamWriter("output.txt"))
        {
            serialiser.Serialize(writer, MasterDataGrid.ItemsSource);
            writer.Close();
        }


    }

А вот класс, который определяет содержимое MasterDataGrid:

[Serializable]
[XmlRoot]
public class CmcdConfigurationParameter : INotifyPropertyChanged, IDisposable
{
    [XmlElement(ElementName = "Configuration Parameter ID")]
    [Key] public Guid ConfigurationParameterID { get; set; }

    [XmlElement(ElementName = "Owning Device")]
    [ForeignKey("OwningDevice")] public Guid DeviceDefinitionID { get; set; }
    [XmlElement]
    public virtual CmcdDeviceDefinition OwningDevice { get; set; }

    [XmlElement(ElementName = "Name")]
    public string Name { get; set; }

    [XmlElement(ElementName = "Type Assembly Qualified Name")]
    public string TypeAssemblyQualifiedName { get; set; }

    private string _storedValue;
    [XmlElement(ElementName = "Stored Value")]
    public string StoredValue
    {
        get { return _storedValue;}
        set
        {
            _storedValue = value;
        }
    }

    [NotMapped]
    [XmlElement(ElementName = "Value")]
    public string Value
    {
        get { return StoredValue; }
        set { SetValue(value); }
    }


    private string _temporaryValueFromUser;
    [NotMapped]
    [XmlElement(ElementName = "Temporary Value")]
    public string TemporaryValueFromUser
    {
        get { return _temporaryValueFromUser; }
        set { _temporaryValueFromUser = value; }
    }

    public string Minimum { get; set; }
    public string Maximum { get; set; }
    public string Units { get; set; }
    public string DefaultValue { get; set; }
    public string Description { get; set; }
    public string DisplayName { get; set; }

    public EmcdConfigurationParameterType ConfigurationParameterType { get; set; }

    public virtual List<CmcdConfigurationParameterChangeLog>
         ChangeLogs
    {
        get;
        set;
    } //Need to confirm what is required to set up this relationship, is foreign key relationship needed?

    public CmcdConfigurationParameter(string strName)
    {
        ConfigurationParameterID = Guid.NewGuid();
        Name = strName;
    }

    public CmcdConfigurationParameter()
    {
    }

    private void ConfirmValueAboveMin<T>(T objNewValue)
    {
        if (Minimum != null)
        {
            var min = Convert.ChangeType(Minimum, Type.GetType(TypeAssemblyQualifiedName));

            var iCompareAgainstMinimumResult = ((IComparable) objNewValue).CompareTo((IComparable) min);

            if (iCompareAgainstMinimumResult < 0)
                throw new ArgumentException(
                    "CmcdConfigurationParameter.SetValue() failed because argument was below the minimum allowed.");
        }
    }

    private void ConfirmValueBelowMax(IComparable objNewValue)
    {
        if (Maximum != null)
        {
            var max = Convert.ChangeType(Maximum, Type.GetType(TypeAssemblyQualifiedName));

            var iCompareAgainstMaximumResult = objNewValue.CompareTo((IComparable) max);

            if (iCompareAgainstMaximumResult > 0)
                throw new ArgumentException(
                    "CmcdConfigurationParameter.SetValue() failed because argument was above the maximum allowed.");
        }
    }

    private bool IsValueSameAsExisting(string objNewValue)
    {
        if (Value != null)
        {
            var iCompareAgainstCurrentValue = ((IComparable) objNewValue).CompareTo(Value);

            if (iCompareAgainstCurrentValue == 0)
                return true;
        }

        return false;
    }

    public void SetValue(string objNewValueAsString, string changedBy = "unknown")
    {
        if (!IsValueSameAsExisting(objNewValueAsString))
        {

            if (TypeAssemblyQualifiedName == null)
            {
                StoredValue = objNewValueAsString;
                return;
            }

            try
            {
                var objNewValue = Convert.ChangeType(objNewValueAsString, Type.GetType(TypeAssemblyQualifiedName));
            }
            catch
            {
                throw new ArgumentException(string.Format(
                    "CmcdConfigurationParameter.SetValue was unable to convert the string value to its actual type. Expected type was {0}.",
                    TypeAssemblyQualifiedName));
            }

            ConfirmValueAboveMin(objNewValueAsString);
            ConfirmValueBelowMax(objNewValueAsString);


            try
            {
                if (ChangeLogs == null)
                    ChangeLogs = new List<CmcdConfigurationParameterChangeLog>();
            }
            catch (ObjectDisposedException e)
            {
                Console.WriteLine(e);
            }


            ChangeLogs?.Add(new CmcdConfigurationParameterChangeLog
            {
                ConfigurationParameterChangeLogID = Guid.NewGuid(),
                DateChanged = DateTime.Now,
                OwningConfigParameter = this,
                OldValue = Value,
                NewValue = objNewValueAsString,
                ChangedBy = changedBy
            });
            //TemporaryValueFromUser = Convert.ToString(objNewValueAsString);
            //ORIGINAL
            StoredValue = Convert.ToString(objNewValueAsString);
        }
    }

    public dynamic GetValue<T>()
    {
        if (Type.GetType(TypeAssemblyQualifiedName).IsEnum)
            return Enum.Parse(Type.GetType(TypeAssemblyQualifiedName), Value);
        return Convert.ChangeType(Value, Type.GetType(TypeAssemblyQualifiedName));
    }

    public override string ToString()
    {
        return Name;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string property = "")
    {
        var handler = PropertyChanged;
        handler?.Invoke(this, new PropertyChangedEventArgs(property));
    }

    public void Dispose()
    {

    }

    //This is required for Entity Framework to map the private property StoredValue (by default EF will not map non-public properties)
    public static readonly Expression<Func<CmcdConfigurationParameter, string>> StoredValueExpression =
        p => p.StoredValue;
}

Извините, что включил весь класс.Я знаю, что это много, но я абсолютно не знаю, как пометить класс для сериализации, поэтому я решил опубликовать все это, чтобы случайно не пропустить что-то важное.Я новичок в сериализации и атрибутах в целом, поэтому я думаю, что класс может быть корнем проблемы.

Таким образом, при вызове метода Export() я получаю следующую ошибку:

"Тип System.Data.Entity.DynamicProxies.CmcdConfigurationPar_66DFCBBA0ADF57C8F10B1E857261CD31C86C9556A2FF6566C2A02006 не указанАтрибут SoapInclude для указания типов, которые не известны статически. "

И я не могу понять, что это значит.Я подумал, что, может быть, длинная строка буквенно-цифровых символов является ключом для одного из параметров в моей базе данных, но я ничего не смог найти.Я подумал, что, возможно, сериализатору нужно было работать с отдельными элементами, а не со списком, но я получил ту же ошибку при попытке сериализации определенного элемента таблицы данных.

Я невероятно потерян здесь, поэтому любые указания будут с благодарностью.

РЕДАКТИРОВАТЬ

Я думаю, что я отключил Динамические прокси / Ленивая загрузка, и теперь ошибка другая.

"Тип« CmcdPickerDefinition »не ожидался. Используйте атрибут XmlInclude или SoapInclude для указания типов, которые не известны статически."

Не могу показатьполный путь этого класса, но это один из моих классов.Я не добавил никаких атрибутов в этот класс, но я не думал, что он является частью элемента управления, над которым я работаю.

...