0

感谢Alex Zeitler 的文章,我的 WCF Web API 服务接受 JSONP 请求。

这对于简单的请求非常有效,但我有一个问题。

我需要能够访问的功能之一是搜索功能,该功能目前通过 http 帖子获取复杂对象。显然我不能通过 JSONP 发布,所以我试图考虑如何将其转换为获取请求。

现有功能如下所示:

[WebInvoke(UriTemplate = "", Method = "POST")]
public HttpResponseMessage<List<Models.Payload>> FindPayloads(Models.AimiRequest requestValues)
{
  // do stuff here
  return new HttpResponseMessage<List<searchResult>>(results);
}

传入的请求对象定义如下:

public class AimiRequest
{
  public MetadataQueryParameter[] Metadata { get; set; }
  public string ContentType { get; set; }
  public string RuleTypes { get; set; }
}

public class MetadataQueryParameter
{
  public string Name { get; set; }
  public string Value { get; set; }
}

棘手的部分是元数据参数的数量未知,并且名称和值事先不知道。

我尝试简单地将对象序列化为字符串并将其传递,但​​服务抛出 400 错误请求(从客户端检测到潜在危险的 Request.Path 值 (:)。)

有没有人有什么好主意?

编辑:肮脏的黑客警报!

好的,我有一个工作功能,但我不喜欢它。必须有一种方法可以实现这一点,而无需我手动将数据从查询字符串中提取出来并自己取消编码。

客户端脚本(请记住这是测试代码而不是生产代码)

function findPayload() {
  var paramName = $("#ddlMetaType option:selected").val();
  var paramValue = $("#txtValue").val();

  // build query object
  var AimiRequest = new Object();
  AimiRequest.ContentType = null;
  AimiRequest.RuleTypes = null;

  var MetadataQueryParameter = new Object();
  MetadataQueryParameter.Name = paramName;
  MetadataQueryParameter.Value = paramValue;

  AimiRequest.Metadata = new Array();
  AimiRequest.Metadata.push(MetadataQueryParameter); 
  // NB. In production there may be multiple params to push into the array.

  // send query to service
  $.ajax({
    cache: false,
    contentType: "application/json",
    data: {},
    dataType: "jsonp",
    error: function (xhr, textStatus, errorThrown) {
      switch (xhr.status) {
        case 404:
          displayNotFound();
          break;
        default:
          alert(xhr.status);
          break;
      }
    },
    success: function (response) {
      var resultsPane = $("#resultsPane");
      $(resultsPane).empty();
      $("#payloadTemplate").tmpl(response).appendTo(resultsPane);
    },
    type: "GET",
    url: "http://localhost:63908/search/json?data=" + encodeURIComponent(JSON.stringify(AimiRequest))
  });

}

以及接收它的服务器端函数:

[ServiceContract]
public class SearchResource
{
  private IPayloadService _payloadService;

  public SearchResource(IPayloadService pService)
  {
    this._payloadService = pService;
  }

  [WebGet(UriTemplate = "")]
  public HttpResponseMessage<List<Payload>> Search()
  {
    // find input in querystring
    var qString = HttpContext.Current.Request.QueryString["data"];
    // Unencode it
    var unenc = HttpUtility.UrlDecode(qString);
    // deserialise back to the object
    var jsSerialiser = new System.Web.Script.Serialization.JavaScriptSerializer();
    var myObj = jsSerialiser.Deserialize<AimiRequest>(unenc);
    // do search
    var metadataParams = new List<KeyValuePair<string, string>>();
    foreach (MetadataQueryParameter param in myObj.Metadata)
    {
      metadataParams.Add(new KeyValuePair<string, string>(param.Name, param.Value));
    }
    List<Data.Payload> data = _payloadService.FindPayloads(metadataParams, myObj.ContentType, myObj.RuleTypes);
    // Map to "viewmodel"
    var retVal = AutoMapper.Mapper.Map<List<Data.Payload>, List<Payload>>(data);
    // return results
    return new HttpResponseMessage<List<Payload>>(retVal);
  }
}
4

1 回答 1

2

1) WCF Web API 具有格式化程序的概念,用于在通过 Stream 访问的 HTTP 内容和对象之间进行转换。可以注册多个格式化程序,选择过程不仅会考虑目标对象类型,还会考虑内容的媒体类型。

2) 但是,格式化程序不用于转换 URI 和查询字符串参数。相反,此过程由不可扩展的 HttpParameterValueConverter(s) 完成。

3)总而言之,您必须自己“取消编码”数据。但是,您可以将此代码排除在操作之外。只需创建一个操作处理程序,以字符串形式接收(输入参数)查询字符串参数并返回(输出参数)强类型的“未编码”对象 ( Models.AimiRequest)。操作参数的类型应该是Models.AimiRequest

于 2011-09-01T11:45:15.570 回答