来自 WCF 的 JSON 响应转义名称值

标签 json wcf serialization

我正在尝试从 WCF REST 服务返回字典作为 JSON 对象。我希望格式是 {“核心值(value)”} 所以我按照here所述创建了自己的类和 here .

服务方法在某种程度上是有效的。问题是键名被转义了。例如,如果我的字典包含“Hello world”:100,我得到 {“Hello_x0020_world”:100}。它还会转义其他字符,例如 % 等。

有什么方法可以告诉序列化不要那样转义名称吗?这几乎就像它使用的 xml 规则(不一定)适用于 JSON。

我的可序列化类:

[Serializable]
public class JsonDictionary : ISerializable
{
    private Dictionary<string, object> _Dictionary;
    public JsonDictionary()
    {
        _Dictionary = new Dictionary<string, object>();
    }
    public JsonDictionary(SerializationInfo info, StreamingContext context)
    {
        _Dictionary = new Dictionary<string, object>();
        SerializationInfoEnumerator enumerator = info.GetEnumerator();
        while (enumerator.MoveNext())
        {
            _Dictionary.Add(enumerator.Name, enumerator.Value);
        }
    }
    public object this[string key]
    {
        get { return _Dictionary[key]; }
        set { _Dictionary[key] = value; }
    }
    public void Add(string key, object value)
    {
        _Dictionary.Add(key, value);
    }
    public bool ContainsKey(string key)
    {
        return _Dictionary.ContainsKey(key);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        foreach (string key in _Dictionary.Keys)
            info.AddValue(key, _Dictionary[key], _Dictionary[key] == null ? typeof(object) : _Dictionary[key].GetType());  
    }
}

我的服务函数定义:

[WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]
    public JsonDictionary GetCollection()
    {
        JsonDictionary dict = new JsonDictionary();

        dict.Add("Hello world", 100);
        return dict;
    }

最佳答案

WCF 中默认使用的 DataContractJsonSerializer 使用 XML 到 JSON 的映射,这会导致一些问题,例如您在 ISerializable 类型中看到的问题。但是,您可以使用自定义格式化程序来更改响应的序列化方式。在下面的示例中,我使用 JSON.NET 来“正确”处理 ISerializable 对象。

public class StackOverflow_16674152
{
    [Serializable]
    public class JsonDictionary : ISerializable
    {
        private Dictionary<string, object> _Dictionary;
        public JsonDictionary()
        {
            _Dictionary = new Dictionary<string, object>();
        }
        public JsonDictionary(SerializationInfo info, StreamingContext context)
        {
            _Dictionary = new Dictionary<string, object>();
            SerializationInfoEnumerator enumerator = info.GetEnumerator();
            while (enumerator.MoveNext())
            {
                _Dictionary.Add(enumerator.Name, enumerator.Value);
            }
        }
        public object this[string key]
        {
            get { return _Dictionary[key]; }
            set { _Dictionary[key] = value; }
        }
        public void Add(string key, object value)
        {
            _Dictionary.Add(key, value);
        }
        public bool ContainsKey(string key)
        {
            return _Dictionary.ContainsKey(key);
        }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            foreach (string key in _Dictionary.Keys)
                info.AddValue(key, _Dictionary[key], _Dictionary[key] == null ? typeof(object) : _Dictionary[key].GetType());
        }
    }
    [ServiceContract]
    public class Service
    {
        [WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]
        [MyISerializableResponseJsonBehavior]
        public JsonDictionary GetCollection()
        {
            JsonDictionary dict = new JsonDictionary();

            dict.Add("Hello world", 100);
            return dict;
        }
    }
    public class MyFormatter : IDispatchMessageFormatter
    {
        IDispatchMessageFormatter original;
        string replyAction;
        public MyFormatter(IDispatchMessageFormatter original, string replyAction)
        {
            this.original = original;
            this.replyAction = replyAction;
        }

        public void DeserializeRequest(Message message, object[] parameters)
        {
            this.original.DeserializeRequest(message, parameters);
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            ISerializable serializable = result as ISerializable;
            if (serializable != null)
            {
                string json = JsonConvert.SerializeObject(serializable);
                byte[] bytes = Encoding.UTF8.GetBytes(json);
                var writer = new MyRawWriter(bytes);
                Message reply = Message.CreateMessage(messageVersion, replyAction, writer);
                reply.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
                return reply;
            }
            else
            {
                return this.original.SerializeReply(messageVersion, parameters, result);
            }
        }

        class MyRawWriter : BodyWriter
        {
            byte[] data;
            public MyRawWriter(byte[] data)
                : base(true)
            {
                this.data = data;
            }

            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                writer.WriteStartElement("Binary");
                writer.WriteBase64(data, 0, data.Length);
                writer.WriteEndElement();
            }
        }
    }
    public class MyISerializableResponseJsonBehaviorAttribute : Attribute, IOperationBehavior
    {
        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            if (operationDescription.Messages.Count > 1)
            {
                dispatchOperation.Formatter = new MyFormatter(dispatchOperation.Formatter, operationDescription.Messages[1].Action);
            }
        }

        public void Validate(OperationDescription operationDescription)
        {
            if (operationDescription.Messages.Count > 1)
            {
                var respMessage = operationDescription.Messages[1];
                if (respMessage.Body.Parts.Count > 0)
                {
                    throw new InvalidOperationException("Cannot be used with out/ref parameters");
                }
            }

            var wga = operationDescription.Behaviors.Find<WebGetAttribute>();
            var wia = operationDescription.Behaviors.Find<WebInvokeAttribute>();
            WebMessageBodyStyle bodyStyle = WebMessageBodyStyle.Bare; // default
            if (wga != null && wga.IsBodyStyleSetExplicitly) {
                bodyStyle = wga.BodyStyle;
            }

            if (wia != null && wia.IsBodyStyleSetExplicitly) {
                bodyStyle = wia.BodyStyle;
            }

            if (bodyStyle == WebMessageBodyStyle.Wrapped || bodyStyle == WebMessageBodyStyle.WrappedResponse)
            {
                throw new InvalidOperationException("This behavior can only be used with bare response style");
            }
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        Console.WriteLine(c.DownloadString(baseAddress + "/"));
    }
}

关于来自 WCF 的 JSON 响应转义名称值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16674152/

相关文章:

用于泛型的 Java JSON 库

WCF 自定义 Http 代理身份验证

c# - 实体太大错误

java - 使用 Groovy 将 bean 序列化和反序列化为 json

java - Java 是否具有与 C# 的 XML 属性等效的功能?

json - 在 Google Chrome DevTools 中搜索 JSON 对象

MySQL 获取 JSON 值

javascript - 在循环中使用innerHTML无法正确显示json结果集

WCF ChannelFactory 没有准确报告故障状态?

c# - 如何序列化从字典派生的类