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

Omu*_*Omu 3 asp.net wcf jquery 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
});
Run Code Online (Sandbox Code Playgroud)

我的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 });
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

{"ExceptionDetail":{"HELPLINK":空"的InnerException":空,"消息":"传入消息具有意想不到的消息格式的'原始’用于操作的期望的消息格式是'XML’;'的Json’. .这可能是因为一个WebContentTypeMapper尚未在所述结合构造,请参阅WebContentTypeMapper的文档了解更多信息""堆栈跟踪.":"在System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(消息信息,对象[]参数) \在System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest u000d\u000a(消息信息,对象[]参数)\ u000d\u000a在System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(消息信息,对象[]参数)\ u000d\u000a在System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&RPC)\ u000d\u000a在System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&RPC)\ u000d\u000a在System.ServiceModel.Dispatch 在System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)的System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&rpc)\ u000d\u000a中的er.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&rpc)\ u000d\u000a","Type" :"System.InvalidOperationException"},"ExceptionType":"System.InvalidOperationException","Message":"传入的消息具有意外的消息格式'Raw'.该操作的预期消息格式是'Xml'; 'Json的'.这可能是因为尚未在绑定上配置WebContentTypeMapper.有关更多详细信息,请参阅WebContentTypeMapper的文档.","StackTrace":"在System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(消息消息,Object []参数)\ u000d\u000a at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(消息的消息,对象[]参数)\ u000d\u000a在System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(消息信息,对象[]参数)\ u000d\u000a在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(Boolean isOperationContextSet)"}

car*_*ira 5

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

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

1)更改客户端以发送服务可以理解的格式.WCF理解JSON,因此您可以使用JSON字符串(即来自Crockford实现的 json2.js中的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);
    }
});
Run Code Online (Sandbox Code Playgroud)

2) "教" WCF如何理解为$ .params(或$ .post的)调用本机格式.有两种方法可以做到这一点:

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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