使用WCF和通用应用程序创建/使用REST Web服务

时间:2014-09-02 19:55:46

标签: c# web-services wcf rest windows-store-apps

我想创建一个IIS托管的Web服务,我将使用通用Windows存储aoo(windows phone / windows 8.1 / windows RT)来使用它。

据我所知,通用应用程序不支持使用“添加服务引用”的代理类生成和SOAP调用,因此我需要创建一个RESTful Web服务并在通用应用程序中手动使用它。

我在整个网络中尝试过几十种教程和方法,但我从未设法将数据实际发布到网络服务。

我需要将在共享库中定义的自定义类的对象发送到Web服务。我知道我需要序列化Object并将其包含在POST请求中,但无论我尝试什么,我最终会遇到不同的问题 - 例如HTTP 400错误请求:传入消息具有意外的消息格式'Raw ”。该操作的预期消息格式是'Xml'; '的Json'。

我已经看到了几种手动设置内容类型标头的方法,但我找到的方法在通用应用程序中不可用。

有人可以提供适合我的方案的信息或示例(通过通用应用程序发布)吗?

更新1:有关进一步说明:我知道WCF如何工作,我已经能够完成this post中描述的基本GET请求。但是,我无法将其扩展为也可以使用POST请求。

我试过的一些代码:

public async static void SendStartup(CustomClass customObject)
{
    var httpClient = new HttpClient();
    var serialized = JsonConvert.SerializeObject(customObject);
    var response = await httpClient.PostAsync("http://localhost:49452/Metrics.svc/LogStartup", new StringContent(serialized));
    string content = await response.Content.ReadAsStringAsync();
}

Web服务接口:

[OperationContract]
[WebInvoke(UriTemplate = "LogStartup", Method="POST", BodyStyle=WebMessageBodyStyle.Wrapped)]
string LogStartup(CustomClass obj);

实现:

public void LogStartup(CustomClass obj)
{
    // nothing
}

这例如在运行时因上述错误而失效

3 个答案:

答案 0 :(得分:6)

您的代码存在两个问题。

1)您在提出请求时必须发送Content-Type标题

var content = new StringContent(serialized,Encoding.UTF8,"application/json");

2)您必须使用BodyStyle = WebMessageBodyStyle.Bare

WebMessageBodyStyle.Bare可以在您的示例中使用一个参数,但如果您想发布更多参数,那么您必须使用WebMessageBodyStyle.Wrapped但是,您发布的对象应该修改为

var serialized = JsonConvert.SerializeObject(new { obj = customObject });

以下是可以使用自托管WCF服务进行测试的工作代码

async void TestRestService()
{
    var ready = new TaskCompletionSource<object>();
    Task.Factory.StartNew(() =>
    {
        var uri = new Uri("http://0.0.0.0:49452/Metrics.svc/");
        var type = typeof(Metrics);
        WebServiceHost host = new WebServiceHost(type, uri);
        host.Open();
        ready.SetResult(null);
    },TaskCreationOptions.LongRunning);

    await ready.Task;

    var customObject = new CustomClass() { Name = "John", Id = 333 };
    var serialized = JsonConvert.SerializeObject(new { obj = customObject });

    var httpClient = new HttpClient();
    var request = new StringContent(serialized,Encoding.UTF8,"application/json");
    var response = await httpClient.PostAsync("http://localhost:49452/Metrics.svc/LogStartup", request);
    string content = await response.Content.ReadAsStringAsync();
}

[ServiceContract]
public class Metrics
{
    [OperationContract]
    [WebInvoke(Method = "POST",  BodyStyle = WebMessageBodyStyle.Wrapped)]
    public string LogStartup(CustomClass obj)
    {
        return obj.Name + "=>" + obj.Id;
    }
}

public class CustomClass
{
    public string Name { set; get; }
    public int Id { set; get; }
}

PS:如果你想返回一个json响应,那么你可以使用ResponseFormat=WebMessageFormat.Json。然后,您应该将WebInvoke属性更改为

[WebInvoke(Method = "POST",  BodyStyle = WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]

BTW:您仍然可以通过设置AutomaticFormatSelectionEnabled来动态选择返回的内容类型(xml或json)。

答案 1 :(得分:2)

你看过这篇文章吗?

How to use HttpClient to post JSON data

基本上您似乎需要向StringContent()构造函数添加更多参数,如下所示:

new StringContent(serialized, System.Text.Encoding.UTF8, "application/json");

答案 2 :(得分:1)

您需要了解的有关 Windows Communication Foundation 的一件事是 ABC的

  • A:地址
  • B:绑定
  • C:合同

所以这个理论非常简单,虽然在你编码的时候,却很奇怪。可以找到一个简单的教程herehere。在Code Project中可以找到其他几个教程来实现这种精确的方法。

了解多态性可能有助于理解 Windows Communication Foundation ,因为它非常依赖它。

[ServiceContract]
public interface IContent
{
     [OperationContract]
     void DoSomething(SomeModel model);
}

所以你在这里做的是定义你的服务,定义你的方法。正如我上面提到的,我们明确地声明了我们的合同,但我们还没有实现我们的方法。我们还打算通过SomeModel这将是我们的数据合同

我们将建立我们的模型:

[DataContract]
public class SomeModel
{
     [DataMember]
     public string Name { get; set; }
}

模型可以像上面那样非常简单,或者非常复杂。这取决于使用情况。

现在我们想实现我们的方法:

public class Content : IContent
{
     public void DoSomething(SomeModel model)
     {
          // Implementation
     }
}

现在在客户端上,您只需使用您的服务。一旦理解了基础知识以及它如何序列化和反序列化,就可以将它用于REST。还有哪些教程。