从Fiddler到WCF的POST成功但传递空值

时间:2011-11-10 21:23:12

标签: wcf json fiddler

我已关注this video series on WCF并让演示正常运行。它涉及构建管理学生评估表单的WCF服务,并实现CRUD操作以对这些评估列表进行操作。我根据this guide稍微修改了我的代码,因此它会将JSON结果返回给浏览器或Fiddler请求。我的目标是通过在Fiddler中构建我自己的请求来弄清楚如何使用该服务,然后使用该格式从移动设备上的应用程序中使用该服务。

我在使用Fiddler的SubmitEval方法(保存评估)时遇到了问题。该调用有效,但Eval的所有字段均为空(或默认),但Id除外,它是在服务本身中设置的。

以下是我的Eval声明(根据this question使用属性而不是字段):

[DataContract]
public class Eval //Models an evaluation
{
    [DataMember]
    public string Id { get; set; }

    [DataMember]
    public string Submitter { get; set; }

    [DataMember]
    public string Comment { get; set; }

    [DataMember]
    public DateTime TimeSubmitted { get; set; }
}

以下是IEvalService的相关部分:

[ServiceContract]
public interface IEvalService
{
 ...
   [OperationContract]
    [WebInvoke(RequestFormat=WebMessageFormat.Json,
       ResponseFormat=WebMessageFormat.Json, UriTemplate = "eval")]
    void SubmitEval(Eval eval);
}

EvalService

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
class EvalService : IEvalService
{
...
  public void SubmitEval(Eval eval)
    {
        eval.Id = Guid.NewGuid().ToString();
        Console.WriteLine("Received eval");
        evals.Add(eval);
    }
}

在Fiddler的Request Builder中,我将Method设置为POST,将地址设置为http://localhost:49444/EvalServiceSite/Eval.svc/eval。我将标头Content-Type: application/json; charset=utf-8添加到默认标头中。请求正文是:

{"eval":{"Comment":"testComment222","Id":"doesntMatter", 
  "Submitter":"Tom","TimeSubmitted":"11/10/2011 4:00 PM"}}

我从发送该请求时获得的回复是200,但是当我查看已保存的Evals时,我刚刚添加的回复包含有效Id,但是{{1} }和Comment均为空,SubmitterTimeSubmitted

似乎WCF正在获取请求,但未正确反序列化对象。但如果是这样的话,我不知道为什么它不会引发某种例外。看起来我做得对,或者我错过了什么?

更新:这是App.config中的端点声明:

1/1/0001 12:00:00 AM

端点行为指的是:

 <endpoint binding="webHttpBinding" behaviorConfiguration="webHttp"
   contract="EvalServiceLibrary.IEvalService" />

2 个答案:

答案 0 :(得分:6)

WebInvoke属性中的默认正文样式是Bare,这意味着应该在没有包含对象名称的包装器的情况下发送对象:

{"Comment":"testComment222",
 "Id":"doesntMatter",
 "Submitter":"Tom",
 "TimeSubmitted":"11/10/2011 4:00 PM"}

或者您可以将请求正文样式设置为Wrapped,这会使输入需要包装{"eval"...}对象:

[OperationContract]
[WebInvoke(RequestFormat=WebMessageFormat.Json,
   ResponseFormat=WebMessageFormat.Json,
   UriTemplate = "eval",
   BodyStyle = WebMessageBodyStyle.WrappedRequest)] // or .Wrapped
void SubmitEval(Eval eval);

更新:您的代码中存在另一个问题,因为您正在使用DateTime,并且WCF序列化程序对JSON中的日期所期望的格式类似于\/Date(1234567890)\/ 。您可以按照MSDN Link中描述的逻辑(对基元的序列化格式进行细粒度控制)更改您的类以支持您所拥有的格式,并在下面的代码中显示。

public class StackOverflow_8086483
{
    [DataContract]
    public class Eval //Models an evaluation
    {
        [DataMember]
        public string Id { get; set; }

        [DataMember]
        public string Submitter { get; set; }

        [DataMember]
        public string Comment { get; set; }

        [DataMember(Name = "TimeSubmitted")]
        private string timeSubmitted;

        public DateTime TimeSubmitted { get; set; }

        public override string ToString()
        {
            return string.Format("Eval[Id={0},Submitter={1},Comment={2},TimeSubmitted={3}]", Id, Submitter, Comment, TimeSubmitted);
        }

        [OnSerializing]
        void OnSerializing(StreamingContext context)
        {
            this.timeSubmitted = this.TimeSubmitted.ToString("MM/dd/yyyy h:mm tt", CultureInfo.InvariantCulture);
        }

        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            DateTime value;
            if (DateTime.TryParseExact(this.timeSubmitted, "MM/dd/yyyy h:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out value))
            {
                this.TimeSubmitted = value;
            }
        }
    }

    [ServiceContract]
    public interface IEvalService
    {
        [OperationContract]
        [WebInvoke(RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json, UriTemplate = "eval",
           BodyStyle = WebMessageBodyStyle.Wrapped)]
        void SubmitEval(Eval eval);
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class EvalService : IEvalService
    {
        public void SubmitEval(Eval eval)
        {
            Console.WriteLine("Received eval: {0}", eval);
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(EvalService), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        string data = "{\"eval\":{\"Comment\":\"testComment222\",\"Id\":\"doesntMatter\", \"Submitter\":\"Tom\",\"TimeSubmitted\":\"11/10/2011 4:00 PM\"}}";
        WebClient c = new WebClient();
        c.Headers[HttpRequestHeader.ContentType] = "application/json; charset=utf-8";
        c.UploadData(baseAddress + "/eval", Encoding.UTF8.GetBytes(data));

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

答案 1 :(得分:0)

对于POST,您需要使用BodyStyle = WebMessageBodyStyle.Bare NOT
       WebMessageBodyStyle.Wrapped

    [OperationContract]
    [WebInvoke(RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json,UriTemplate = "eval",BodyStyle = WebMessageBodyStyle.Bare)]
    void SubmitEval(Eval eval);