簡體   English   中英

如何在JSON中的ServiceStack中返回帶有TimeZoneInfo屬性的DTO

[英]How to return a DTO with a TimeZoneInfo property in ServiceStack in JSON

我有這個小ServiceStack消息:

[Route("/server/time", "GET")]
public class ServerTime : IReturn<ServerTime>
{
    public DateTimeOffset DateTime { get; set; }
    public TimeZoneInfo TimeZone { get; set; }
}

其各自的服務處理程序如下:

public object Get(ServerTime request)
{
    return new ServerTime
    {
        DateTime = DateTimeOffset.Now,
        TimeZone = TimeZoneInfo.Local,
    };
}

客戶端測試代碼如下所示:

var client = new JsonServiceClient("http://localhost:54146/");
var response = client.Get<ServerTime>(new ServerTime());

但是response.TimeZoneInfo總是空的......

此外,服務的元數據(JSON)不會顯示它:

(JSON元數據頁面中的示例請求)

POST /json/reply/ServerTime HTTP/1.1 
Host: localhost 
Content-Type: application/json
Content-Length: length

{"DateTime":"\/Date(-62135596800000)\/"}

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: length

{"DateTime":"\/Date(-62135596800000)\/"}

另一方面,XML和CSV格式似乎正確處理它:

POST /xml/reply/ServerTime HTTP/1.1 
Host: localhost 
Content-Type: application/xml
Content-Length: length

<ServerTime xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/PtsSampleService.ServiceModel">
  <DateTime xmlns:d2p1="http://schemas.datacontract.org/2004/07/System">
    <d2p1:DateTime>0001-01-01T00:00:00Z</d2p1:DateTime>
    <d2p1:OffsetMinutes>0</d2p1:OffsetMinutes>
  </DateTime>
  <TimeZone xmlns:d2p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
</ServerTime>

HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: length

<ServerTime xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/PtsSampleService.ServiceModel">
  <DateTime xmlns:d2p1="http://schemas.datacontract.org/2004/07/System">
    <d2p1:DateTime>0001-01-01T00:00:00Z</d2p1:DateTime>
    <d2p1:OffsetMinutes>0</d2p1:OffsetMinutes>
  </DateTime>
  <TimeZone xmlns:d2p1="http://schemas.datacontract.org/2004/07/System" i:nil="true" />
</ServerTime>

為什么我要問這個而不是使用“XML客戶端”?

這完全是為了一致性。 如果API在所有可能的客戶端上不一致,那么就不能依賴它! 我要么必須刪除JSON格式化程序(我不能這樣做,因為我想在JavaScript中使用它)或者我必須單獨拆分許多TimeZoneInfo字段...或者找到一種方法來使JSON序列化器成為處理它!

事實上,XML也不起作用。 XmlServiceClient給了我這個錯誤:

{“第1行中的錯誤位置290.元素':AdjustmentRules'包含映射到名稱' http://schemas.datacontract.org/2004/07/System:ArrayOfTimeZoneInfo.AdjustmentRule '的類型的數據。反序列化器沒有任何映射到此名稱的類型的知識。考慮使用DataContractResolver或將與“ArrayOfTimeZoneInfo.AdjustmentRule”對應的類型添加到已知類型列表中 - 例如,通過使用KnownTypeAttribute屬性或將其添加到已知類型列表中傳遞給DataContractSerializer。“}

有誰知道為什么它沒有默認處理?

TimeZoneInfo序列化為XML存在一個已知問題:請參閱此問題,關於在WCF中序列化對象以及使用變通方法鏈接的MSDN討論 不確定解決方法是否適合ServiceStack。

但我建議完全避免這個問題,只需要發送時區的Id或其他簡單標識符。

似乎沒有一種優雅的方式將TimeZoneInfo傳遞給客戶端,所以我只是創建了一個DTO,毫不奇怪地命名為TimeZoneInformation

[Serializable]
public class TimeZoneInformation
{
    public string Id { get; set; }
    public TimeSpan BaseUtcOffset { get; set; }
    public string DisplayName { get; set; }
    public string DaylightName { get; set; }
    public string StandardName { get; set; }
    public bool SupportsDST { get; set; }
    public static implicit operator TimeZoneInformation(TimeZoneInfo source)
    {
        return new TimeZoneInformation
        {
            Id = source.Id,
            DisplayName = source.DisplayName,
            BaseUtcOffset = source.BaseUtcOffset,
            DaylightName = source.DaylightName,
            StandardName = source.StandardName,
            SupportsDST = source.SupportsDaylightSavingTime,
        };
    }
    public static implicit operator TimeZoneInfo(TimeZoneInformation source)
    {
        return TimeZoneInfo.FindSystemTimeZoneById(source.Id);
    }
}

我的服務方法看起來不像這樣:

public object Get(ServerTime request)
{
    return new ServerTime
    {
        DateTime = DateTimeOffset.Now,
        TimeZoneInfo = TimeZoneInfo.Local,
    };
}

並且呼叫的元數據是:

POST /json/reply/ServerTime HTTP/1.1 
Host: localhost 
Content-Type: application/json
Content-Length: length

{"DateTime":"\/Date(-62135596800000)\/","TimeZoneInfo":{"Id":"String","BaseUtcOffset":"PT0S","DisplayName":"String","DaylightName":"String","StandardName":"String","SupportsDST":false}}

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: length

{"DateTime":"\/Date(-62135596800000)\/","TimeZoneInfo":{"Id":"String","BaseUtcOffset":"PT0S","DisplayName":"String","DaylightName":"String","StandardName":"String","SupportsDST":false}}

對該方法的實際調用返回此JSON:

{"DateTime":"\/Date(1371925432883-0300)\/","TimeZoneInfo":{"Id":"E. South America Standard Time","BaseUtcOffset":"-PT3H","DisplayName":"(UTC-03:00) Brasília","DaylightName":"Horário brasileiro de verão","StandardName":"Hora oficial do Brasil","SupportsDST":true}}

和XML:

<ServerTime><DateTime><d2p1:DateTime>2013-06-22T21:24:22.2741641Z</d2p1:DateTime><d2p1:OffsetMinutes>-180</d2p1:OffsetMinutes></DateTime><TimeZoneInfo><_x003C_BaseUtcOffset_x003E_k__BackingField>-PT3H</_x003C_BaseUtcOffset_x003E_k__BackingField><_x003C_DaylightName_x003E_k__BackingField>Horário brasileiro de verão</_x003C_DaylightName_x003E_k__BackingField><_x003C_DisplayName_x003E_k__BackingField>(UTC-03:00) Brasília</_x003C_DisplayName_x003E_k__BackingField><_x003C_Id_x003E_k__BackingField>E. South America Standard Time</_x003C_Id_x003E_k__BackingField><_x003C_StandardName_x003E_k__BackingField>Hora oficial do Brasil</_x003C_StandardName_x003E_k__BackingField><_x003C_SupportsDST_x003E_k__BackingField>true</_x003C_SupportsDST_x003E_k__BackingField></TimeZoneInfo></ServerTime>

所有類型的客戶端都完美地反序列化它。

我不是100%幸福,但盡可能快樂...

有些人可能會問我為什么不發送ID。 時區ID特定於Windows。 由於我必須與不同的客戶交談,我無法發送ID,希望他們可以相應地重建服務器的時區數據。 我已經將DateTimeOffset上的OFFSET發送回客戶端,但是在某些情況下還不夠,因為單獨的偏移量不足以確定時區或夏令時是否生效。 因此,發送客戶端正確解釋服務器日期和時間所需的所有內容是此特定應用程序的最佳解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM