我正在尝试反序列化xml文档:
<?xml version="1.0"?>
<games xmlns = "http://serialize">
<game>
<name>TEST1</name>
<code>TESTGAME1</code>
<ugn>1111111</ugn>
<bets>
<bet>5,00</bet>
</bets>
</game>
<game>
<name>TEST2</name>
<code>TESTGAME2</code>
<ugn>222222</ugn>
<bets>
<bet>0,30</bet>
<bet>0,90</bet>
</bets>
</game>
</games>
Run Code Online (Sandbox Code Playgroud)
.cs类:
namespace XmlParse
{
using System.Collections.Generic;
using System.Runtime.Serialization;
[DataContract(Namespace = "http://serialize")]
public class game
{
#region Public Properties
[DataMember]
public string name { get; set; }
[DataMember]
public string code { get; set; }
[DataMember]
public long ugn { get; set; }
[DataMember]
public List<decimal> bets { get; set; }
#endregion
}
[KnownType(typeof(game))]
[DataContract(Namespace = …Run Code Online (Sandbox Code Playgroud) 在C#中,如果我想序列化一个实例XmlSerializer,那么对象的类型不必用[Serializable]属性标记.但是,对于其他序列化方法,例如DataContractSerializer,需要将类标记为[Serializable]或[DataContract].
是否有关于序列化要求的标准或模式?
我有这些课程:
[DataContract]
public class ErrorBase {}
[DataContract]
public class FileMissingError: ErrorBase {}
[DataContract]
public class ResponseFileInquiry
{
[DataMember]
public List<ErrorBase> errors {get;set;};
}
Run Code Online (Sandbox Code Playgroud)
ResponseFileInquiry类的一个实例是我的服务方法返回给客户端的实例.现在,如果我用ErrorBase实例填充ResponseFileInquiry.errors,一切正常,但如果我添加一个继承类型FileMissingError的实例,我在序列化期间得到一个服务端异常:
Type 'MyNamespace.FileMissingError' with data contract name 'FileMissingError'
is not expected. 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.'
Run Code Online (Sandbox Code Playgroud)
因此序列化器变得混乱,因为它期望List包含声明的类型对象(ErrorBase),但它正在获取继承类型(FileMissingError)对象.
我有一大堆错误类型,List将包含它们的组合,那么我该怎么做才能使它工作?
我有一个返回以下数据的Web服务:
<?xml version=""1.0"" encoding=""UTF-8""?>
<RESPONSE>
<KEY>12345</KEY>
<PROPERTY>
<PROPERTY_ADDRESS>
<STREET_NUM>25</STREET_NUM>
<STREET_ADDRESS>ELM ST</STREET_ADDRESS>
<STREET_PREFIX/>
<STREET_NAME>ELM</STREET_NAME>
<STREET_TYPE>ST</STREET_TYPE>
<STREET_SUFFIX/>
</PROPERTY_ADDRESS>
</PROPERTY>
</RESPONSE>
Run Code Online (Sandbox Code Playgroud)
我有一个匹配的类结构:
[DataContract(Name="RESPONSE", Namespace="")]
public class Response
{
[DataMember(Name="KEY")]
public string Key { get; set; }
[DataMember(Name = "PROPERTY")]
public Property Property { get; set; }
}
[DataContract(Name="PROPERTY", Namespace="")]
public class Property
{
[DataMember(Name="PROPERTY_ADDRESS")]
public PropertyAddress Address { get; set; }
}
[DataContract(Name="PROPERTY_ADDRESS", Namespace="")]
public class PropertyAddress
{
[DataMember(Name="STREET_NUM")]
public string StreetNumber { get; set; }
[DataMember(Name = "STREET_ADDRESS")]
public string StreetAddress { …Run Code Online (Sandbox Code Playgroud) 我对WCF有点新意,并试图清楚地描述我想要做的事情.
我有一个使用JSON请求的WCF Web服务.我在很大程度上发送/接收JSON很好.例如,以下代码可以正常工作并且符合预期.
JSON发送:
{ "guy": {"FirstName":"Dave"} }
Run Code Online (Sandbox Code Playgroud)
WCF:
[DataContract]
public class SomeGuy
{
[DataMember]
public string FirstName { get; set; }
}
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
public string Register(SomeGuy guy)
{
return guy.FirstName;
}
Run Code Online (Sandbox Code Playgroud)
这将按预期返回带有"Dave"的JSON对象.问题是我不能总是保证我收到的JSON将与我的DataContract中的成员完全匹配.例如,JSON:
{ "guy": {"firstname":"Dave"} }
Run Code Online (Sandbox Code Playgroud)
将无法正确序列化,因为案例不匹配.guy.FirstName将为null.这种行为是有道理的,但我真的不知道如何解决这个问题.我是否必须在客户端强制使用字段名称,还是有一种方法可以在服务器端进行协调?
一个可能相关的问题:我可以接受并将通用JSON对象序列化为StringDictionary或某种简单的键值结构吗?因此,无论JSON中发送的字段名称是什么,我都可以访问已发送给我的名称和值?现在,我能够读取我收到的数据的唯一方法是它是否与预定义的DataContract完全匹配.
有没有办法改变DataContractJsonSerializer序列化日期的方式?
目前,它会将日期转换为以下内容:
{
"date": "/Date(1260597600000-0600)/"
}
Run Code Online (Sandbox Code Playgroud)
我宁愿让它序列化为自1970年以来的毫秒.这样,其他语言可以很容易地使用json数据.
精简版
我有一个使用插件基础设施的应用程序.这些插件具有可配置的属性,可帮助他们了解如何完成工作.插件被分组到配置文件中以定义如何完成任务,配置文件存储在由DataContractSerializer序列化的XML文件中.问题是在读取配置文件时,应用程序反序列化必须知道配置文件中定义的所有插件.我正在寻找一种方法来处理未知插件的解决方案.请参阅下面提出的解决方案部分,了解我实施的一些想法,但我对任何事情都持开放态度(尽管我不必重新发明应用程序).
详情
背景
我已经为我目前在C#4工作的公司开发了一种内部使用的业务流程自动化系统.它详尽地使用"插件"来定义所有内容(从要执行的任务到工作单元的定义)并且在很大程度上依赖于动态配置模型,而动态配置模型又依赖于C#4/DLR动态对象来完成工作.由于其动态特性,它在执行时有点沉重,但它能够始终如一地运行,并且能够满足我们的需求.
它包括一个WinForms配置UI,它广泛使用Reflection来确定插件的可配置属性/字段,以及定义要处理的每个工作单元的属性/字段.用户界面也建立在BPA引擎的基础之上,因此它彻底了解了(松散的)对象模型,它允许引擎完成其工作,巧合的是,这导致了一些用户体验的改进,例如,ad-hoc作业执行和用户输入的配置时验证.同样还有改进的余地,但它似乎做了它的工作.
配置UI使用DataContractSerializer来序列化/反序列化指定的设置,因此必须在配置加载之前(或在配置加载时)加载配置引用的任何插件.
结构体
BPA引擎实现为共享程序集(DLL),由BPA服务(Windows服务),配置UI(WinForms应用程序)和插件测试程序(Windows服务的控制台应用程序版本)引用.引用共享程序集的三个应用程序中的每一个仅包含执行其特定目的所需的最少代码量.此外,所有插件必须引用一个非常薄的程序集,它基本上只定义了插件必须实现的接口.
问题
由于应用程序中使用的可扩展性模型,始终要求配置UI从与服务应用程序相同的目录(在同一台PC上)运行.这样,UI总是知道服务知道的所有程序集,因此可以反序列化它们而不会遇到缺少的程序集.现在我们已经接近推出系统,为了安全起见,我们的网络管理员出现了在我们网络中的任何PC上远程允许配置UI的要求.通常,如果总是有一组已知的程序集要部署,这不会成为问题,但是,如果能够使用用户构建的程序集扩展应用程序,则必须有一种方法来解析插件所从的程序集可以实例化/使用.
建议(可能很明显)的解决方案
将WCF服务添加到服务应用程序,以允许典型的CRUD操作针对该服务实例所知道的配置,并重新配置配置UI,使其更像SSMS,具有Connect/Disconnect模型.这并没有真正解决问题所以我们还需要从Service应用程序中公开某种ServiceContract,以允许查询它知道/有权访问的程序集.这很好而且相当直接,但问题出现了,"用户应该何时了解服务所知道的程序集?" 在连接时,我们可以将所有程序集从服务发送到UI,以确保它始终知道服务所做的所有程序集,但是会因AppDomain管理(可能不必要)和程序集版本冲突而变得混乱.因此,我建议挂钩AppDomain.AssemblyResolve/AppDomain.TypeResolve事件,以便仅下载客户端尚未了解的程序集,并且仅在需要时下载.这不一定能清除AppDomain管理问题,但它肯定有助于解决版本冲突和相关问题.
题
如果你坚持我这么久我鼓掌并感谢你,但现在我终于得到了实际的问题.经过几个月的研究并最终得出结论,我想知道这里是否有人必须处理类似的问题,以及你如何处理陷阱和缺点?是否有一种标准的处理方法,我完全错过了,或者你有什么建议基于你过去如何成功处理?您是否看到提出的方法有任何问题,或者您可以提供替代方案吗?
我知道不是每个人都在我的脑海中,所以如果你需要进一步澄清/解释,请告诉我.谢谢!
更新
我给了MEF一个公平的摇晃,觉得它对我的目的来说太简单了.并不是因为它不能弯曲来处理我的应用程序的插件要求,问题是这样做太麻烦和脏,使其可行.这是一个很好的建议,它有很大的潜力,但在目前的状态,它还没有.
关于我提出的解决方案的其他想法或反馈?
更新
我不知道我遇到的问题是否过于局部化,如果我没有正确描述我想要实现的目标,或者这个问题是否太过于无理由地被完整阅读; 但是我收到的几个答案都非常有帮助,足以帮助我以不同的方式思考问题并找出我所追求的一些缺点.
简而言之,我正在尝试做的是使用三个应用程序,这些应用程序在当前状态下使用公共目录结构共享信息(配置/程序集),并尝试使这些应用程序在网络上工作,对可用性和体系结构的影响最小.
文件共享似乎是这个问题的明显答案(正如@SimonMourier在评论中提出的那样),但是当出现问题时,使用它们会转化为缺乏控制和可调试性.我认为它们是一种可行的短期解决方案,但从长远来看它们似乎并不可行.
我理解什么是属性IsReference以及它正在做什么.但我不明白为什么/当我应该不使用它.什么时候使用IsReference = true是个坏主意?
如果我的wcf服务是.net到.net,是否有充分的理由不设置IsReference = true?
有没有办法告诉WCF在返回时序列化整个类?我是否真的必须将DataMember添加到每个属性?
我在WCF调用上收到以下错误:
在对象图中可以序列化或反序列化的最大项数是'65536'
我已经阅读了大量的论坛帖子,其中许多人提到修改app.config和web.config以指定允许更大对象图的新行为.我已经做到了,这就是我在这些文件中所拥有的:
关于WPF项目的App.Config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="">
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="digiPM.Shell.LogOutPMSEMRService.PMSEMRLogOutService">
<!--<endpoint address="" binding="basicHttpBinding" contract="digiPM.Shell.LogOutPMSEMRService.IPMSEMRLogOutService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/digiPM.Shell.LogOutPMSEMRService/PMSEMRLogOutService/" />
</baseAddresses>
</host>-->
<endpoint address="" binding="netTcpBinding" name="NetTcpBindingEndpoint" contract="digiPM.Shell.LogOutPMSEMRService.IPMSEMRLogOutService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" name="MexTcpBidingEndpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8732/Design_Time_Addresses/digiPM.Shell.LogOutPMSEMRService/PMSEMRLogOutService/" />
</baseAddresses>
</host>
</service>
</services>
<!--binding info - …Run Code Online (Sandbox Code Playgroud) .net wcf datacontractserializer servicebehavior xmlserializer