在控制器 Returns 之后修改 JSON 对象
Modify JSON Object After Controller Returns
我将 C# 与 MVC 一起使用,并尝试在控制器 returns 之后但在到达客户端之前将数据添加到 JSON 消息中。
有没有我可以用的 C# framework/tool?
例子
控制器returns 特定订单的订单数据,其中包括 Unix 时间日期(int 表示秒)。
消息在返回给调用者之前被拦截。
JSON 消息中附加了另一个从 Unix 时间转换为公历 date/time 的字段。
这可能吗?
从控制器返回数据后,您不能对 C# 中的数据执行任何操作。现在要交给客户了。您必须在公历时间的 class 中添加一个字段并在返回之前对其进行初始化,或者在 client-side 上处理该字段。向 Javascript 中的对象添加字段非常简单。考虑以下对象:
var obj = {
foo: "hello"
}
现在,让我们添加到这个对象。我们有两个选择:
obj.bar = "world" //Dot Notation
或
obj["bar"] = "world" //Square Bracket Notation
对于您的情况,使用点符号最有意义,因为您的变量名称不会动态声明。至于在Javascript中计算公历时间,我推荐一个有用的库,叫做moment.js,虽然用JS中的常规Date()
对象应该很简单。
话虽这么说,但通常最好避免在 JS 中执行可以在后端执行的操作。让浏览器进行您的服务器可以轻松完成的计算只会浪费客户端内存,占用加载时间,并且可能会花费您宝贵的流量 运行.
要根据 Unix 时间戳计算 UTC 时间,如果您使用的是 .Net 4.6,这将非常容易。假设你的 unix 时间戳存储在一个名为 'myTimestamp':
的变量中
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(myTimestamp); //Offset from Unix epoch
DateTime dateTime = dateTimeOffset.UtcDateTime; //Gregorian
为此,您可以执行如下操作(添加额外的 属性 来表示公历 date/time):
public class MyModel
{
public long UnixDateTime { get; set; }
public DateTime GregorianDateTime { get { return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(UnixDateTime); } }
}
如@Brandon 所述,您可以对 .NET 4.6 或更高版本使用以下代码块:
public DateTime GregorianDateTime { get { return DateTimeOffset.FromUnixTimeSeconds(UnixDateTime).DateTime; } }
有两种解决方案,但推荐none!!!两者都需要使用反射和递归来解析并在结果上注入值。
主要问题,你怎么知道一个数字是unix时间跨度而不是一个数字!在我的例子中,我比较结果日期是否在 2000 年和当年之间。
一个简单的匹配是使用 Unix 时间垃圾邮件的命名约定,例如:
public int UnixSaleDate {get; set;}
如果存在命名约定,请更改以下代码片段:
if (value.Type == JTokenType.Integer && IsValidDateTime(value)) // <= Change it
if (value.Type == JTokenType.Integer && name.Contains("Unix")) // <= With these
Option 1: WebApi Action filter
可以在动作上指定使用,方便。
public class ActionInjectDateTimeFromUnixActionWebApiFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
//var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
var injection = RecursiveInjectUnixToDateTime(JObject.FromObject(value)); // recursively inject value
objectContent.Value = injection;
// Overwrite return value
actionExecutedContext.Response.Content = objectContent;
}
}
/// <summary>
/// Recursive DateTime Injection
/// </summary>
/// <param name="obj">'obj' need to be a JObject</param>
/// <returns></returns>
private dynamic RecursiveInjectUnixToDateTime(JToken obj)
{
var expObj = new ExpandoObject() as IDictionary<string, Object>;
foreach (JProperty p in obj)
{
string name = p.Name;
JToken value = p.Value;
switch (value.Type)
{
case JTokenType.Integer:
{
// Make sure your int is a date time after, after all isn't sure you are returning an int or a UNIX date time
if (value.Type == JTokenType.Integer && IsValidDateTime(value))
{
expObj.Add(name + "_DateTime", UnixToDateTime((long) value));
}
else
{
expObj.Add(name, value);
}
}
break;
case JTokenType.Object:
{
// Go deep
// expObj[name] = RecursiveInjectUnixToDateTime(p.Value);
expObj.Add(name, RecursiveInjectUnixToDateTime(p.Value));
}
break;
case JTokenType.Array:
{
// Go deep
var arr = new List<dynamic>();
foreach (var val in value.ToArray())
{
arr.Add(RecursiveInjectUnixToDateTime(val));
}
// expObj[name] = arr;
expObj.Add(name, arr);
}
break;
default:
{
// expObj[name] = value;
expObj.Add(name, value);
}
break;
}
}
return expObj;
}
/// <summary>
/// Validate if long value is a valid date time between 2000 and current year
/// </summary>
/// <param name="longUnix"></param>
/// <returns></returns>
private bool IsValidDateTime(JToken longUnix)
{
long unixDateTime = (long)longUnix;
if (unixDateTime > 0)
{
try
{
var date = UnixToDateTime(unixDateTime);
return date.Year >= 2000 && date.Year <= DateTime.UtcNow.Year;
}
catch (Exception ex)
{
return false;
}
}
return false;
}
private DateTime UnixToDateTime(long unixTimestamp)
{
DateTime unixYear0 = new DateTime(1970, 1, 1);
long unixTimeStampInTicks = unixTimestamp * TimeSpan.TicksPerSecond;
DateTime dtUnix = new DateTime(unixYear0.Ticks + unixTimeStampInTicks);
return dtUnix;
}
}
}
在控制器中:
[HttpGet]
[ActionInjectDateTimeFromUnixActionWebApiFilter]
[Route("something1")]
public IHttpActionResult GetSomething1()
{
return
Ok(
new
{
unix = 1267480860,
some_int = 2,
obj = new
{
description = "Yah Right"
},
items = new List<object> {
new {
id = 1,
name = "dude",
unix2 = 1403473486
}
}
});
}
[HttpGet]
[ActionInjectDateTimeFromUnixActionWebApiFilter]
[Route("something2")]
public Object GetSomething2()
{
return new
{
unix = 1267480860,
some_int = 2,
obj = new
{
description = "Yah Right"
},
items = new List<object> {
new {
id = 1,
name = "dude",
unix2 = 1403473486
}
}
};
}
对两个控制器操作的响应:
{
"unix_DateTime": "2010-03-01T22:01:00",
"some_int": 2,
"obj": {
"description": "Yah Right"
},
"items": [
{
"id": 1,
"name": "dude",
"unix2_DateTime": "2014-06-22T21:44:46"
}
]
}
Option 2: DelegatingHandler
是最糟糕的解决方案!!!更多详细信息以及如何
DelegatingHandler for response in WebApi
shebang 的其余部分,reuse-it 来自用于日期时间注入(注入方法)的选项 1 代码片段。
祝你好运,选择明智。
我将 C# 与 MVC 一起使用,并尝试在控制器 returns 之后但在到达客户端之前将数据添加到 JSON 消息中。
有没有我可以用的 C# framework/tool?
例子
控制器returns 特定订单的订单数据,其中包括 Unix 时间日期(int 表示秒)。
消息在返回给调用者之前被拦截。
JSON 消息中附加了另一个从 Unix 时间转换为公历 date/time 的字段。
这可能吗?
从控制器返回数据后,您不能对 C# 中的数据执行任何操作。现在要交给客户了。您必须在公历时间的 class 中添加一个字段并在返回之前对其进行初始化,或者在 client-side 上处理该字段。向 Javascript 中的对象添加字段非常简单。考虑以下对象:
var obj = {
foo: "hello"
}
现在,让我们添加到这个对象。我们有两个选择:
obj.bar = "world" //Dot Notation
或
obj["bar"] = "world" //Square Bracket Notation
对于您的情况,使用点符号最有意义,因为您的变量名称不会动态声明。至于在Javascript中计算公历时间,我推荐一个有用的库,叫做moment.js,虽然用JS中的常规Date()
对象应该很简单。
话虽这么说,但通常最好避免在 JS 中执行可以在后端执行的操作。让浏览器进行您的服务器可以轻松完成的计算只会浪费客户端内存,占用加载时间,并且可能会花费您宝贵的流量 运行.
要根据 Unix 时间戳计算 UTC 时间,如果您使用的是 .Net 4.6,这将非常容易。假设你的 unix 时间戳存储在一个名为 'myTimestamp':
的变量中DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(myTimestamp); //Offset from Unix epoch
DateTime dateTime = dateTimeOffset.UtcDateTime; //Gregorian
为此,您可以执行如下操作(添加额外的 属性 来表示公历 date/time):
public class MyModel
{
public long UnixDateTime { get; set; }
public DateTime GregorianDateTime { get { return new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(UnixDateTime); } }
}
如@Brandon 所述,您可以对 .NET 4.6 或更高版本使用以下代码块:
public DateTime GregorianDateTime { get { return DateTimeOffset.FromUnixTimeSeconds(UnixDateTime).DateTime; } }
有两种解决方案,但推荐none!!!两者都需要使用反射和递归来解析并在结果上注入值。
主要问题,你怎么知道一个数字是unix时间跨度而不是一个数字!在我的例子中,我比较结果日期是否在 2000 年和当年之间。 一个简单的匹配是使用 Unix 时间垃圾邮件的命名约定,例如:
public int UnixSaleDate {get; set;}
如果存在命名约定,请更改以下代码片段:
if (value.Type == JTokenType.Integer && IsValidDateTime(value)) // <= Change it
if (value.Type == JTokenType.Integer && name.Contains("Unix")) // <= With these
Option 1: WebApi Action filter
可以在动作上指定使用,方便。
public class ActionInjectDateTimeFromUnixActionWebApiFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
//var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
var injection = RecursiveInjectUnixToDateTime(JObject.FromObject(value)); // recursively inject value
objectContent.Value = injection;
// Overwrite return value
actionExecutedContext.Response.Content = objectContent;
}
}
/// <summary>
/// Recursive DateTime Injection
/// </summary>
/// <param name="obj">'obj' need to be a JObject</param>
/// <returns></returns>
private dynamic RecursiveInjectUnixToDateTime(JToken obj)
{
var expObj = new ExpandoObject() as IDictionary<string, Object>;
foreach (JProperty p in obj)
{
string name = p.Name;
JToken value = p.Value;
switch (value.Type)
{
case JTokenType.Integer:
{
// Make sure your int is a date time after, after all isn't sure you are returning an int or a UNIX date time
if (value.Type == JTokenType.Integer && IsValidDateTime(value))
{
expObj.Add(name + "_DateTime", UnixToDateTime((long) value));
}
else
{
expObj.Add(name, value);
}
}
break;
case JTokenType.Object:
{
// Go deep
// expObj[name] = RecursiveInjectUnixToDateTime(p.Value);
expObj.Add(name, RecursiveInjectUnixToDateTime(p.Value));
}
break;
case JTokenType.Array:
{
// Go deep
var arr = new List<dynamic>();
foreach (var val in value.ToArray())
{
arr.Add(RecursiveInjectUnixToDateTime(val));
}
// expObj[name] = arr;
expObj.Add(name, arr);
}
break;
default:
{
// expObj[name] = value;
expObj.Add(name, value);
}
break;
}
}
return expObj;
}
/// <summary>
/// Validate if long value is a valid date time between 2000 and current year
/// </summary>
/// <param name="longUnix"></param>
/// <returns></returns>
private bool IsValidDateTime(JToken longUnix)
{
long unixDateTime = (long)longUnix;
if (unixDateTime > 0)
{
try
{
var date = UnixToDateTime(unixDateTime);
return date.Year >= 2000 && date.Year <= DateTime.UtcNow.Year;
}
catch (Exception ex)
{
return false;
}
}
return false;
}
private DateTime UnixToDateTime(long unixTimestamp)
{
DateTime unixYear0 = new DateTime(1970, 1, 1);
long unixTimeStampInTicks = unixTimestamp * TimeSpan.TicksPerSecond;
DateTime dtUnix = new DateTime(unixYear0.Ticks + unixTimeStampInTicks);
return dtUnix;
}
}
}
在控制器中:
[HttpGet]
[ActionInjectDateTimeFromUnixActionWebApiFilter]
[Route("something1")]
public IHttpActionResult GetSomething1()
{
return
Ok(
new
{
unix = 1267480860,
some_int = 2,
obj = new
{
description = "Yah Right"
},
items = new List<object> {
new {
id = 1,
name = "dude",
unix2 = 1403473486
}
}
});
}
[HttpGet]
[ActionInjectDateTimeFromUnixActionWebApiFilter]
[Route("something2")]
public Object GetSomething2()
{
return new
{
unix = 1267480860,
some_int = 2,
obj = new
{
description = "Yah Right"
},
items = new List<object> {
new {
id = 1,
name = "dude",
unix2 = 1403473486
}
}
};
}
对两个控制器操作的响应:
{
"unix_DateTime": "2010-03-01T22:01:00",
"some_int": 2,
"obj": {
"description": "Yah Right"
},
"items": [
{
"id": 1,
"name": "dude",
"unix2_DateTime": "2014-06-22T21:44:46"
}
]
}
Option 2: DelegatingHandler
是最糟糕的解决方案!!!更多详细信息以及如何 DelegatingHandler for response in WebApi
shebang 的其余部分,reuse-it 来自用于日期时间注入(注入方法)的选项 1 代码片段。
祝你好运,选择明智。