WCF传输System.IO.FileInfo时CreationTime被重置为1600年的简便解决方法咨询
我太懂你这种觉得写包装类有点冗余甚至“蠢”的感受了!其实你遇到的问题核心很明确:System.IO.FileInfo本身的设计就不是为WCF的数据契约序列化而生的。
它虽然标记了[Serializable]属性,但WCF默认采用的是数据契约序列化(Data Contract Serializer),而FileInfo里的很多属性(比如CreationTime)是延迟加载的——也就是说,在服务器端序列化的时候,这些属性并没有真正去读取文件系统的真实值,只是保存了一个“待加载”的状态;当客户端反序列化时,因为没有服务器端的文件上下文,根本加载不到真实的时间数据,就会默认填充成DateTime类型的最小值附近(也就是你看到的1600年左右的异常时间)。
你提到的[Serializable]其实是给.NET旧式的二进制序列化用的,WCF默认不会优先使用它。如果强行让WCF切换到二进制序列化,虽然能解决部分问题,但会带来更多麻烦:比如客户端和服务器必须严格使用相同版本的.NET框架,跨平台兼容性几乎为零,反而不如包装类靠谱。
给你几个更实用的方案:
方案一:优化你的包装类(其实没那么冗余!)
你可以把包装类写得更通用、更易用,比如扩展它的属性覆盖常用场景,再配合扩展方法实现一键转换,这样代码复用性拉满,也不会显得繁琐:[DataContract] public class dcFileInfo { [DataMember] public string Name { get; set; } [DataMember] public DateTime CreationTime { get; set; } [DataMember] public DateTime LastWriteTime { get; set; } [DataMember] public long Length { get; set; } [DataMember] public string FullName { get; set; } // 空构造函数是WCF序列化的强制要求 public dcFileInfo() {} public dcFileInfo(FileInfo fi) { Name = fi.Name; CreationTime = fi.CreationTime; LastWriteTime = fi.LastWriteTime; Length = fi.Length; FullName = fi.FullName; } } // 写个扩展方法,转换一行搞定 public static class FileInfoExtensions { public static dcFileInfo ToDcFileInfo(this FileInfo fi) { return new dcFileInfo(fi); } }之后你只需要在服务端写
fileInfo.ToDcFileInfo()就能完成转换,客户端拿到的就是纯粹的、没有依赖的数据对象,完全不会有时间重置的问题。方案二:强行启用NetDataContractSerializer(不推荐)
如果你实在不想写包装类,可以让WCF使用支持[Serializable]的NetDataContractSerializer,但要做好兼容性牺牲:
在你的服务契约接口上添加特性:[ServiceContract] public interface IYourFileService { [OperationContract] [SerializerFormat(Serializer = SerializerType.NetDataContractSerializer)] FileInfo GetFileInfo(string filePath); }但要注意:这种方式要求客户端必须和服务器使用完全一致的.NET环境,而且客户端反序列化后得到的FileInfo对象在本地是“无效”的——因为它指向的是服务器上的文件路径,客户端本地根本没有这个文件,后续操作大概率会报错。
最后想说一句:其实包装类真的是最稳妥的选择!WCF的设计理念就是传输纯数据契约对象,而不是像FileInfo这种和系统资源强绑定的复杂对象。包装类虽然多写了几行代码,但能让你的数据传输逻辑更清晰、更可控,完全避免序列化的隐藏坑。
内容来源于stack exchange

