通过jQuery将数组发送到启用Ajax的WCF

时间:2011-07-21 08:33:05

标签: jquery asp.net wcf asp.net-ajax

我的js代码:

var a = ["asdfa", "asdfa", "aaa"];
var data = [];
for (var i in a) data.push({ name: 'keys', value: a[i] });
$.post('<%=ResolveUrl("~/svc/aja.svc/GetMultiple") %>', $.param(data), function(d) {
//do stuff
});

我的ajax已启用wcf

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Aja
{
    [WebInvoke(Method="POST")]
    [OperationContract]
    public IEnumerable<IdContent> GetMultiple(string[] keys)
    {
        return keys.Select(o => new IdContent { Id = o, Content = o + o });
    }

我尝试了调试,方法GetMultiple没有被击中,(我得到错误500)

如果我这样做是通过发送一个简单的字符串而不是数组,而不是它的工作

这是我在firebug中得到的消息:

  

{ “ExceptionDetail”:{ “HELPLINK”:空 “的InnerException”:空, “消息”:“的   传入消息具有意外的消息格式“原始”。预期的   操作的消息格式是'Xml'; 'Json的'。这可以   因为尚未在绑定上配置WebContentTypeMapper。   有关更多信息,请参阅WebContentTypeMapper的文档   详情。“,”StackTrace“:”at   System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.MessageRpc.Process(布尔   isOperationContextSet) “ ”类型“: ”System.InvalidOperationException“}, ”ExceptionType“: ”System.InvalidOperationException“, ”消息“:” 的   传入消息具有意外的消息格式“原始”。预期的   操作的消息格式是'Xml'; 'Json的'。这可以   因为尚未在绑定上配置WebContentTypeMapper。   有关更多信息,请参阅WebContentTypeMapper的文档   详情。“,”StackTrace“:”at   System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(消息   消息,对象[]参数)\ u000d \ u000a at   System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&安培;   rpc)\ u000d \ u000a at   System.ServiceModel.Dispatcher.MessageRpc.Process(布尔   isOperationContextSet)“}

5 个答案:

答案 0 :(得分:5)

您遇到的问题:$ .post发送以application / x-www-form-urlencoded编码的数据,WCF本身不支持此格式。这就是问题所在。

现在寻求解决方案:与WCF一样,您可以做很多事情:

1)更改客户端以发送服务可以理解的格式。 WCF理解JSON,因此您可以使用JSON字符串(即json2.js from Crockford's implementation中的JSON.stringify)。有了这个,您需要更改代码以使用$ .ajax而不是“快捷方式”$ .post:

$.ajax({
    type: "POST",
    url: '<%=ResolveUrl("~/svc/aja.svc/GetMultiple") %>',
    contentType: "application/json",
    data: JSON.stringify({ keys: a }),
    success: function (result) {
        alert(result);
    }
});

2)“教”WCF如何理解$ .params(或$ .post)调用的原生格式。有两种方法可以做到这一点:

2.1)“手动”做。这不是很微不足道,但可以做到。您需要一个IDispatchMessageFormatter,它可以从表单/编码转换为您的操作的string[]参数。然后,您需要一种行为来挂接这种新格式,以及新服务主机工厂(通过代码挂钩行为)或行为配置扩展(如果您想在配置中执行此操作)。以下链接适用于更详细解释message formattersendpoint behaviorsservice host factorybehavior config extensions的帖子。下面的代码显示了调度格式化程序的一种可能实现,它知道如何处理字符串数组。

public class AjaServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new AjaServiceHost(serviceType, baseAddresses);
    }

    public class AjaServiceHost : ServiceHost
    {
        public AjaServiceHost(Type serviceType, Uri[] baseAddresses)
            : base(serviceType, baseAddresses) { }

        protected override void OnOpening()
        {
            base.OnOpening();
            ServiceEndpoint endpoint = this.AddServiceEndpoint(typeof(Aja), new WebHttpBinding(), "");
            endpoint.Behaviors.Add(new WebScriptEnablingBehavior());
            endpoint.Behaviors.Add(new MyFormsUrlEncodedAwareBehavior());
        }
    }
}
class MyFormsUrlEncodedAwareBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        foreach (var operation in endpoint.Contract.Operations)
        {
            var dispatchOperation = endpointDispatcher.DispatchRuntime.Operations[operation.Name];
            dispatchOperation.Formatter = new MyFormsUrlEncodedAwareFormatter(operation, dispatchOperation.Formatter);
        }
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}
class MyFormsUrlEncodedAwareFormatter : IDispatchMessageFormatter
{
    private OperationDescription operationDescription;
    private IDispatchMessageFormatter originalFormatter;

    public MyFormsUrlEncodedAwareFormatter(OperationDescription operationDescription, IDispatchMessageFormatter originalFormatter)
    {
        this.operationDescription = operationDescription;
        this.originalFormatter = originalFormatter;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        if (message.Properties.ContainsKey(WebBodyFormatMessageProperty.Name))
        {
            var bodyFormat = (WebBodyFormatMessageProperty)message.Properties[WebBodyFormatMessageProperty.Name];
            if (bodyFormat.Format == WebContentFormat.Raw)
            {
                if (message.Properties.ContainsKey(HttpRequestMessageProperty.Name))
                {
                    var httpReq = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
                    if (httpReq.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded")
                    {
                        var requestBodyParts = operationDescription.Messages[0].Body.Parts;
                        if (requestBodyParts.Count == 1 && requestBodyParts[0].Type == typeof(string[]))
                        {
                            string body = GetRawMessageBodyAsString(message);
                            NameValueCollection pairs = HttpUtility.ParseQueryString(body);
                            parameters[0] = pairs.GetValues(requestBodyParts[0].Name);
                            return;
                        }
                    }
                }
            }
        }

        this.originalFormatter.DeserializeRequest(message, parameters);
    }

    private string GetRawMessageBodyAsString(Message message)
    {
        XmlDictionaryReader reader = message.GetReaderAtBodyContents();
        reader.ReadStartElement("Binary");
        byte[] bytes = reader.ReadContentAsBase64();
        return Encoding.UTF8.GetString(bytes);
    }

    public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
    {
        return this.originalFormatter.SerializeReply(messageVersion, parameters, result);
    }
}

2.2 )使用http://wcf.codeplex.com上发布的新“jCF支持WCF”。这些是一些行为/格式化程序,它们增加了对表单/ urlencoded请求的支持。但是您需要更改操作以无类型方式接收数据(即,作为JsonArray),并且在代码中您自己枚举项目。

答案 1 :(得分:1)

我认为你应该使用你试图作为参数传递给wcf应用程序的数组创建一个JSON字符串。请尝试以下代码

Javascript部分,

 var list = ["a", "b", "c", "d"];
 var jsonText = JSON.stringify({ list: list });

$.ajax({
  type: "POST",
  url: "WebService1.svc/methodName",
  data: jsonText,
  contentType: "application/json; charset=utf-8",
  dataType: "json",
 success: function() { alert("it worked"); },
 failure: function() { alert("Uh oh"); }

});

希望这会有所帮助......

答案 2 :(得分:1)

这是不可能的。

您无法将值数组从URL映射到参数。

如果要传递数组,请使用HTTP POST


编辑:

为你演示〜

使用mvc2~

成功的关键是traditional

traditional参数设置为true

$(function(){
    var a = [1, 2];
    $.ajax({
       type: "POST",
       url: "<%= ResolveUrl("~/Home/PostArray/") %>",
       data: {orderedIds: a},
       dataType: "json",
       traditional: true,
       success: function(msg){alert(msg)}
    });
})

由于jquery 1.4存在此参数,因为将对象序列化为查询参数的机制已更改。

并且行动是〜

    [HttpPost]
    public ActionResult PostArray(int[] orderedIds)
    {
        return Content(orderedIds.Length.ToString());
    }

希望有帮助~`

答案 3 :(得分:1)

尝试保持服务器端代码相同,并将客户端代码更改为:

$(function(){
    var a = ["asdfa", "asdfa", "aaa"];
var data = [];
for (var i in a) data.push({ name: 'keys', value: a[i] });
    $.ajax({
       url: "echo/json/",
       data: data,
       dataType: "json",
       traditional: true,
       success: function(msg){alert(msg)}
    });
})

我认为您的问题可能是使用$.post方法时未正确指定内容类型。

答案 4 :(得分:0)

您也可以尝试

var objSearch = [

        { "Key": "Key_Name1", "Value": "asdfa"},
        { "Key": "Key_Name2", "Value": "asdfa"},
         { "Key": "Key_Name3", "Value": "aaa"},
    ];

此处Key_Name表示您加入了wcf Lke(键=>“ Keyname1”,Value =>“ asdfa”)

$.ajax({

        type: "POST",
        url: svcCertificateUrl + '/Fetch',
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        async: false,
        data: JSON.stringify({"objSearch": JSON.stringify(objSearch) }),
        success: function (data) {});