gpt4 book ai didi

WCF DataContractSerializer

转载 作者:行者123 更新时间:2023-12-04 22:29:43 28 4
gpt4 key购买 nike

尝试返回一个时出现以下错误向客户提出问卷调查对象。我按照建议在数据协定中添加了 KnowType[typeof(...)],但它仍然不起作用。不知道序列化程序不知道哪种类型,我只是放入了 EF 模型中的所有类。有人可以帮忙吗?谢谢。

这是服务契约(Contract)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using QuestionnaireWcfServiceApp.Models;

namespace QuestionnaireWcfService
{
[ServiceContract]
public interface IQuestionnaireService
{
[OperationContract]
QuestionnaireContract GetQuestionnaire(string questionnaireName);

[OperationContract]
QuestionChain LoadQuestion(int questionnaireID, int? questionID, int? userResponse);
}

[DataContract]
[KnownType(typeof(Questionnaire))]
[KnownType(typeof(Question))]
[KnownType(typeof(Choice))]
[KnownType(typeof(Decision))]
[KnownType(typeof(QuestionFlow))]
public class QuestionChain
{
[DataMember]
public Question Question { get; set; }

[DataMember]
public int? Decision {get;set;}
}

[DataContract]
[KnownType(typeof(Questionnaire))]
[KnownType(typeof(Question))]
[KnownType(typeof(Choice))]
[KnownType(typeof(Decision))]
[KnownType(typeof(QuestionFlow))]
public class QuestionnaireContract
{
[DataMember]
public Questionnaire Questionnaire { get; set; }
}
}

这是服务。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using QuestionnaireWcfServiceApp.Models;

namespace QuestionnaireWcfService
{
public class QuestionnaireService : IQuestionnaireService
{
QuestionnaireWcfServiceApp.Models.QuestionnaireEntities db = new QuestionnaireEntities();

public QuestionnaireContract GetQuestionnaire(string questionnaireName)
{
QuestionnaireContract questionnaireContract = new QuestionnaireContract();
if (!string.IsNullOrEmpty(questionnaireName))
{
Questionnaire thisQuestionnaire = (from q in db.Questionnaires where q.Name.Equals(questionnaireName) select q).FirstOrDefault();
if (thisQuestionnaire == null)
throw new ArgumentNullException("Questionnaire ID is not found.");
else
{
questionnaireContract.Questionnaire = thisQuestionnaire;
return questionnaireContract;
}
}
else
throw new ArgumentException("Questionnaire name is not specified.");
}

public QuestionChain LoadQuestion(int questionnaireID, int? currentQuestionID, int? userResponse)
{
QuestionChain qc = new QuestionChain();
QuestionFlow thisFlow = null;
Question nextQuestion = null;
Questionnaire thisQuestionnaire = (from q in db.Questionnaires where q.QuestionnaireId == questionnaireID select q).FirstOrDefault();

if (thisQuestionnaire == null)
throw new ArgumentNullException("Questionnaire ID is not found"); //InvalidOperationException;

if (currentQuestionID.HasValue)
{
//QuestionID should never be changed after setup. Change the QuestionText around the QuestionID
Question thisQuestion = thisQuestionnaire.Questions.Where(q => q.PKey.Equals(currentQuestionID)).FirstOrDefault();
if (thisQuestion == null)
throw new ArgumentNullException("Question ID is not found");
else
{
if (userResponse.HasValue)
{
thisFlow = thisQuestion.QuestionFlows.First(f => f.QuestionId.Equals(currentQuestionID) && f.ChoiceId.Equals(userResponse));
if (thisFlow.Question1 != null)
{
nextQuestion = thisFlow.Question1;
qc.Question = nextQuestion;
}
else
{
qc.Question = null;
qc.Decision = thisFlow.Decision.Value;
}
}
else
{
//can't happen. when reaches here, a userResponse must not be null
}
}
}
else
{
//default to question 1
nextQuestion = thisQuestionnaire.Questions.First(q => q.QuestionId.Equals(1));
if (nextQuestion == null)
throw new ArgumentNullException("Question ID");
else
qc.Question = nextQuestion;
}
return qc;
}
}
}

这是 Windows 应用程序日志中的异常。

Exception: System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://tempuri.org/:GetQuestionnaireResult. The InnerException message was 'Type System.Data.Entity.DynamicProxies.Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342' 
with data contract name 'Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342:
http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'
is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details. ---> System.Runtime.Serialization.SerializationException: Type 'System.Data.Entity.DynamicProxies.Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342' with data contract name 'Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
--- End of inner exception stack trace ---
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriterMessage.OnBodyToString(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.ToString(XmlDictionaryWriter writer)
at System.ServiceModel.Diagnostics.MessageLogTraceRecord.WriteTo(XmlWriter writer)
at System.ServiceModel.Diagnostics.MessageLogger.LogInternal(MessageLogTraceRecord record)
at System.ServiceModel.Diagnostics.MessageLogger.LogMessageImpl(Message& message, XmlReader reader, MessageLoggingSource source)
at System.ServiceModel.Diagnostics.MessageLogger.LogMessage(Message& message, XmlReader reader, MessageLoggingSource source)
Process Name: WebDev.WebServer40
Process ID: 11620

Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="System.ServiceModel 4.0.0.0" />
<EventID Qualifiers="49154">5</EventID>
<Level>2</Level>
<Task>7</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2012-10-18T07:32:11.000000000Z" />
<EventRecordID>36499</EventRecordID>
<Channel>Application</Channel>
<Computer>Jon-PC</Computer>
<Security UserID="S-1-5-21-334737869-2079735299-2176000493-1000" />
</System>
<EventData>
<Data>System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://tempuri.org/:GetQuestionnaireResult. The InnerException message was 'Type 'System.Data.Entity.DynamicProxies.Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342' with data contract name 'Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details. ---&gt; System.Runtime.Serialization.SerializationException: Type 'System.Data.Entity.DynamicProxies.Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342' with data contract name 'Questionnaire_EF00247BEFB9F733C947A4C3E57FD12709E91510AC0DA534D137ED75FCCAC342:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
--- End of inner exception stack trace ---
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriterMessage.OnBodyToString(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.ToString(XmlDictionaryWriter writer)
at System.ServiceModel.Diagnostics.MessageLogTraceRecord.WriteTo(XmlWriter writer)
at System.ServiceModel.Diagnostics.MessageLogger.LogInternal(MessageLogTraceRecord record)
at System.ServiceModel.Diagnostics.MessageLogger.LogMessageImpl(Message&amp; message, XmlReader reader, MessageLoggingSource source)
at System.ServiceModel.Diagnostics.MessageLogger.LogMessage(Message&amp; message, XmlReader reader, MessageLoggingSource source)</Data>
<Data>WebDev.WebServer40</Data>
<Data>11620</Data>
</EventData>
</Event>

最佳答案

与 WCF 一起使用的所有类型都必须是数据协定或标记为 [Serializable]。这包括已经在 WCF 数据协定中的任何对象。如果您有能力,则必须将 [Serializable] 标记添加到类中,或者将 WCF 特定标记添加到它们中。这不是开玩笑,这意味着即使您将类型添加到 KnownTypes,也不意味着 WCF 会知道它是可序列化的。

如果这些选项都不可用,我建议创建“代理”对象,它可以包含您要传递的值,并让这些值与您的目标对象相互转换。听起来很疯狂,但事情就是这样......

添加示例:

WCF 使用 System.Runtime.Serialization 中包含的序列化程序命名空间将数据序列化和反序列化为不同的格式(XML、SOAP、JSON、二进制)。为了使其工作,将要序列化的对象必须是某种类型的可序列化类型(用属性标记)。数据对象的内置 WCF 属性如下所示:

//This is marked with the DataContract attribute, which is WCF specific
[DataContract]
public class Foo
{
//The DataMember attribute is also WCF specific and specifies what data
// is included in the serialization. Any properties (or variables) must be
// accessable, as in not read only.
[DataMember]
public string Property1{get;set;}

//This variable will be serialized as well, even though it is private. This
// works great if you have a readonly property but still need to pass the data
[DataMember]
private int Id = 0;


//This does not have a DataMember attribute and will not be serialized
private string var1;
}

WCF 还可以利用标记为 Serializable 的类(例如 DataTable 和 DataSet) .

//This is marked with the Serializable attribute.  All public and private
// fields are automatically serialized (unless there is a containing object
// that is not serializable then you get a SerializationException
[Serializable]
public class Bar
{
//gets serialized
public string Property1{get;set;}

//gets serialized
private string var1;
}

创建“代理”对象的想法与添加服务引用时 Visual Studio 生成的想法相同,只是相反。假设您有不可序列化的类“Foo2”,并且具有某些属性。

public class Foo2
{
public string Property1{get;set;}

public string Property2{get;set;}

public int Property3{get;set;}
}

您可以创建一个代理类(几乎以您想要的任何方式),它允许您在服务之间来回传递属性。

[DataContract]
public class Foo2Proxy
{
[DataMember]
public string Property1{get;set;}

[DataMember]
public string Property2{get;set;}

[DataMember]
public int Property3{get;set;}

public Foo2Proxy()
{
}

public Foo2Proxy(Foo2 foo)
{
this.Property1 = foo.Property1;
this.Property2 = foo.Property2;
this.Property3 = foo.Property3;
}

public static Foo2 Create(Foo2Proxy fProxy)
{
var foo = new Foo2();
foo.Property1 = fProxy.Property1;
foo.Property2 = fProxy.Property2;
foo.Property3 = fProxy.Property3;
return foo;
}
}

我敢肯定,关于如何做到这一点可能有 100,000 种不同的方法和意见,但这只是当时对我有用的可能性的一个例子。如果你看一下this article on CodeProject你可以在这里看到我拍摄的内容。

在您的特定情况下,您可能需要为由 EF 创建的问题和决策类型创建“代理”对象(或包装对象,无论您想要怎样称​​呼它),因为它们似乎不是固有可序列化的,除非您可以进入为这些对象生成的代码并按上述方式添加属性。另一个考虑因素是,如果它们派生自另一个类(或抽象类),则该基类还必须标记为可序列化或 DataContract!

关于WCF DataContractSerializer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12950145/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com