控制器返回后修改JSON对象

时间:2018-03-26 18:41:30

标签: c# json asp.net-mvc asp.net-mvc-4

我正在使用C#和MVC并尝试在控制器返回之后但在它到达客户端之前将数据添加到JSON消息。

我可以使用C#框架/工具吗?

示例

控制器返回特定订单的订单数据,其中包括Unix时间的日期(int表示秒数)。

在返回给调用者之前拦截该消息。

从Unix时间转换的格里高利日期/时间的另一个字段将附加到JSON消息。

这可能吗?

3 个答案:

答案 0 :(得分:0)

从控制器返回后,您无法对C#中的数据执行任何操作。它现在转向客户端。你要么必须在格里高利时将一个字段添加到你的类中并在返回之前初始化它,要么在客户端处理它。在Javascript中向对象添加字段非常简单。请考虑以下对象:

var obj = {
   foo: "hello"
}

现在,让我们添加到这个对象。我们有两个选择:

obj.bar = "world" //Dot Notation

OR

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

答案 1 :(得分:0)

要实现这一点,您可以执行以下操作(添加额外的属性来表示公历日期/时间):

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; } }

答案 2 :(得分:0)

有两个解决方案,但没有建议!!! 都需要使用反射和递归来解析和注入结果值。

主要问题,你怎么知道一个数字是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
  

选项1:WebApi Action过滤器

它可以方便地指出可以使用的女巫动作。

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"
    }
  ]
}
  

选项2:DelegatingHandler

女巫是最糟糕的解决方案!更多细节以及如何 DelegatingHandler for response in WebApi

其余的shebang,重复使用它来自选项1的代码片段,用于日期时间注入(注入方法)。

祝你好运,明智地选择了。