使用WCF服务进行类型和继承

时间:2014-09-24 13:48:19

标签: c# json wcf

    [DataContract]
    public abstract  class BusMessage
    {
        [DataMember(Name = "encoding")]
        public string Encoding { get; set; }

        [DataMember(Name = "type")]
        public virtual MessageType Type
        {
            get { return _type; }
            private set { _type = value; }
        }
    }

[DataContract]
public class BusTextMessage : BusMessage
{
    [DataMember(Name = "type")]
    public override MessageType Type
    {
        get { return MessageType.Text; }
    }

    [DataMember(Name = "payload")]
    public string Payload { get; set; }
}




    [ServiceContract]
    [ServiceKnownType("GetKnownTypes", typeof(Helper))]
    public interface ICommunicationService
    {
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "/SendMessage")]
        string SendMessage(BusMessage jsonMessage);
    }
}

当我使用Postman chrome发送请求时,如果我不将__type添加为“__type”:“BusTextMessage:#TransportModels.Messages”,该对象将无法正确序列化,因为它不知道如何实例化BusMessage类。我已经定义了Type属性,它定义了消息的类型。是否有可能覆盖__type行为,例如根据Type属性返回正确的实现?我不希望任何人手动将__type信息放到json中,因此在反序列化之前是否有选项可以编辑json,如果它不存在则手动将__type属性添加到json中?例如,我想做这样的事情:

public void BeforeDeserialization(string json)
{
       if(json doesnt include __type)
       {
           if(json property type(my property) is MessageType.Text)
            add to json "__type":"BusTextMessage:#TransportModels.Messages"

       ///etc
       }
}

我发现了这种方法,但似乎没有用:

 [OnDeserializing()]
        internal void OnDeserializingMethod(StreamingContext context)
        {

        }

2 个答案:

答案 0 :(得分:0)

我认为您需要将KnownType属性添加到BusMessage类。

[DataContract]
[KnownType(typeof(BusTextMessage)]
public class BusMessage
{
.
.
.
}

答案 1 :(得分:0)

这是我发现的最快的解决方案。我配置MessageInspector并处理AfterReceiveRequest。然后我检查消息格式(XML,JSON)。如果它是XML(例如从用C#编写的任何WCF客户端发送,WCF配置为使用XML发送所有内容),那么我接受该消息,因为字段__type将由WCF机制自动插入。否则我检查它是否是JSON,例如从外部客户端发送。如果它不包含属性" __ type"我检查我的属性Type并生成正确的__type值。例如,如果我的Type等于Text,我添加__type属性BusTextMessage:#TransportModels.Messages并将其插入JSON,然后重新创建消息。我无法找到更快更容易的解决方案,而且它似乎正在发挥作用。处理AfterReceiveRequest我在http://code.msdn.microsoft.com/windowsdesktop/WCF-REST-Message-Inspector-c4b6790b找到了。

  public class MessageTypeInspector : IDispatchMessageInspector
   {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext                 instanceContext)
        {
           RecreateMessage(ref request);
            return null;
        }
   }





private void RecreateMessage(ref Message message)
        {
            WebContentFormat messageFormat = this.GetMessageContentFormat(message);
            var ms = new MemoryStream();
            XmlDictionaryWriter writer = null;
            switch (messageFormat)
            {
                case WebContentFormat.Default:
                case WebContentFormat.Xml:
                    writer = XmlDictionaryWriter.CreateTextWriter(ms);
                    break;
                case WebContentFormat.Json:
                    writer = JsonReaderWriterFactory.CreateJsonWriter(ms);
                    break;
                case WebContentFormat.Raw:
                   this.ReadRawBody(ref message);
                    break;
            }

            message.WriteMessage(writer);
            writer.Flush();
            string messageBody = Encoding.UTF8.GetString(ms.ToArray());

            if (messageFormat == WebContentFormat.Json && !messageBody.Contains("__type"))
                messageBody = AddTypeField(messageBody);

            ms.Position = 0;


            ms = new MemoryStream(Encoding.UTF8.GetBytes(messageBody));

            XmlDictionaryReader reader = messageFormat == WebContentFormat.Json ?
                JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max) :
                XmlDictionaryReader.CreateTextReader(ms, XmlDictionaryReaderQuotas.Max);

            Message newMessage = Message.CreateMessage(reader, int.MaxValue, message.Version);
            newMessage.Properties.CopyProperties(message.Properties);
            message = newMessage;

        }

 private WebContentFormat GetMessageContentFormat(Message message)
        {
            WebContentFormat format = WebContentFormat.Default;
            if (message.Properties.ContainsKey(WebBodyFormatMessageProperty.Name))
            {
                WebBodyFormatMessageProperty bodyFormat;
                bodyFormat = (WebBodyFormatMessageProperty)message.Properties[WebBodyFormatMessageProperty.Name];
                format = bodyFormat.Format;
            }

            return format;
        }

private string AddTypeField(string jsonReply)
        {
            var typeRegex = new Regex("\"type\":(?<number>[0-9]*)");

            Match match = typeRegex.Match(jsonReply);
            if (match.Success)
            {
                int number = Int32.Parse(match.Groups["number"].Value);
                var type = (MessageType)number;
                var nameFormat = string.Format("Bus{0}Message", type);
                string format = string.Format("\"__type\":\"{0}:#TransportModels.Messages\"", nameFormat);
                jsonReply = "{" + string.Format("{0},{1}", format, jsonReply.Substring(1));
                return jsonReply;
            }
            else
            {
                throw new Exception("Wrong message type.");
            }
        }