The basic problem here is that FileInfo is not a data object, it is a view into the local file system that allows live querying and manipulation of a specific file. As such, after deserialization its properties return information about an identically named file on the server, not the original properties on the client - even though FileInfo is marked as [Serializable] in .NET Framework 4.8.1.[1] From the docs:
FileInfo Class
Provides properties and instance methods for the creation, copying, deletion, moving, and opening of files, and aids in the creation of FileStream objects. This class cannot be inherited.
The FileInfo class [also] provides properties that enable you to retrieve information about a file.
This explains why CreationTime resets to year 1600: when a file with the specified name does not exist on the receiving system, FileInfo returns this value to indicate an error. From the docs for the base class method FileSystemInfo.CreationTime:
FileSystemInfo.CreationTime Property
Gets or sets the creation time of the current file or directory.
If the file described in the FileSystemInfo object does not exist, this property returns 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC), adjusted to local time.
For confirmation, we can check the .NET Framework 4.8.1 reference source for streaming constructors for FileInfo and FileSystemInfo. Both populate only the name, full path and original path from the provided SerializationInfo. Other properties such as the creation time are not populated and so are retrieved from the local file system instead.
As a workaround, you will need to create a DTO for FileInfo for serialization purposes -- even though you stated in your question that "this seems to be redundant (if not looks stupid)" there doesn't seem to be any other option. To make its use a little easier, you could add an implicit operator from FileInfo to your DTO:
[DataContract(Name = "FileInfo")]
public class FileInfoDTO
{
public static implicit operator FileInfoDTO (FileInfo fileInfo) { return fileInfo == null ? null : new FileInfoDTO(fileInfo); }
public FileInfoDTO() { } // Parameterless constructor required for serialization
public FileInfoDTO(FileInfo fileInfo)
{
if (fileInfo == null)
throw new ArgumentNullException("fileInfo");
this.Attributes = fileInfo.Exists ? fileInfo.Attributes : null;
this.CreationTime = fileInfo.CreationTime;
this.CreationTimeUtc = fileInfo.CreationTimeUtc;
this.DirectoryName = fileInfo.DirectoryName;
this.Exists = fileInfo.Exists;
this.Extension = fileInfo.Extension;
this.IsReadOnly = fileInfo.IsReadOnly;
this.LastAccessTime = fileInfo.LastAccessTime;
this.LastAccessTimeUtc = fileInfo.LastAccessTimeUtc;
this.LastWriteTime = fileInfo.LastWriteTime;
this.LastWriteTimeUtc = fileInfo.LastWriteTimeUtc;
this.Length = fileInfo.Exists ? fileInfo.Length : null;
this.Name = fileInfo.Name;
}
// TODO: remove any properties you don't need to serialize
[DataMember] public string Name { get; set; }
[DataMember] public DateTime CreationTime { get; set; }
[DataMember] public DateTime CreationTimeUtc { get; set; }
[DataMember] public string DirectoryName { get; set; }
[DataMember] public bool Exists { get; set; }
[DataMember] public string Extension { get; set; }
[DataMember] public bool IsReadOnly { get; set; }
[DataMember] public DateTime LastAccessTime { get; set; }
[DataMember] public DateTime LastAccessTimeUtc { get; set; }
[DataMember] public DateTime LastWriteTime { get; set; }
[DataMember] public DateTime LastWriteTimeUtc { get; set; }
// When the file does not exist, (FileAttributes)(-1). is returned. This cannot be serialized, so make the property nullable instead.
[DataMember] public FileAttributes? Attributes { get; set; }
// When the file does not exist, FileInfo.Length throws an exception. Make the property nullable instead.
[DataMember] public long? Length { get; set; }
}
Then replace FileInfo with FileInfoDTO in your data models:
[DataContract]
public class Model
{
[DataMember]
public FileInfoDTO FileInfo { get; set; }
}
And you will be able to initialize the DTO values from your existing FileInfo values using the implicit operator:
var model = new Model() { FileInfo = new FileInfo(fileName) };
Demo fiddle here.
[1] While your question is specifically about .NET Framework, the situation is even worse in .NET Core. There FileInfo is not marked as serializable and so cannot be serialized by WCF at all. See ASP.NET Core serialized object with a FileInfo returns incomplete JSON for details, and this fiddle for a demo.