Использование JQGrid в сочетании с веб-службами WCF - PullRequest
4 голосов
/ 12 февраля 2009

Я пытаюсь получить данные для JQGrid из веб-службы WCF, которая работает из моего приложения ASP.NET 2.0 WebForms. Проблема заключается в том, что веб-служба WCF ожидает, что данные будут отформатированы в виде строки JSON, а JQGrid выполняет HTTP-публикацию и передает ее как Content-Type: application / x-www-form-urlencoded.

Хотя существует несколько вариантов формата данных, возвращаемых в JQGrid (он принимает JSON, XML и другие), похоже, нет способа изменить способ передачи входных данных в веб-службу.

Итак, я пытаюсь выяснить, как настроить службу WCF, чтобы она принимала

Content-Type: application/x-www-form-urlencoded

вместо

Content-Type:"application/json; charset=utf-8"

Когда я делал тест, используя JQuery для отправки Ajax-запроса с использованием URL-кодировки (показано здесь):

$.ajax({
    type: "POST",
    url: "../Services/DocLookups.svc/DoWork",
    data: 'FirstName=Howard&LastName=Pinsley',
    contentType: "Content-Type: application/x-www-form-urlencoded",
    dataType: "json",
    success: function(msg) {
        alert(msg.d);
    }
});

вызов не удался. Используя Fiddler для проверки трафика, я обнаружил ошибку, возвращаемую сервером:

{"ExceptionDetail":{"HelpLink":null,"InnerException":null,"Message":
"The incoming message has an unexpected message format 'Raw'. The expected
message formats for the operation are 'Xml', 'Json'. This can be because 
a WebContentTypeMapper has not been configured on the binding. 
See the documentation of WebContentTypeMapper for more details."...

Обратите внимание, что этот код работает из-за разницы в кодировке

$.ajax({
    type: "POST",
    url: "../Services/DocLookups.svc/DoWork",
    data: '{"FirstName":"Howard", "LastName":"Pinsley"}',
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(msg) {
        alert(msg.d);
    }
});

На сервере сервис выглядит так:

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class DocLookups {
    // Add [WebGet] attribute to use HTTP GET

    [OperationContract]
    public string DoWork(string FirstName, string LastName) {
        return "Your name is " + LastName + ", " + FirstName;
    }
}

и мой web.config содержит:

<system.serviceModel>
  <behaviors>
   <endpointBehaviors>
    <behavior name="DocLookupsAspNetAjaxBehavior">
     <enableWebScript />
    </behavior>
   </endpointBehaviors>
  </behaviors>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <services>
   <service name="DocLookups">
    <endpoint address="" behaviorConfiguration="DocLookupsAspNetAjaxBehavior"
     binding="webHttpBinding" contract="DocLookups" />
   </service>
  </services>
</system.serviceModel>

Спасибо за любую помощь!

1 Ответ

5 голосов
/ 12 февраля 2009

Если у вас нет контроля над вызовом ajax, я бы порекомендовал создать и Interceptor для переопределения заголовка типа контента.

public class ContentTypeOverrideInterceptor : RequestInterceptor
{
    public string ContentTypeOverride { get; set; }

    public ContentTypeOverrideInterceptor(string contentTypeOverride) : base(true)
    {
        this.ContentTypeOverride = contentTypeOverride;
    }

    public override void ProcessRequest(ref RequestContext requestContext)
    {
        if (requestContext == null || requestContext.RequestMessage == null)
        {
            return;
        }
        Message message = requestContext.RequestMessage;
        HttpRequestMessageProperty reqProp = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
        reqProp.Headers["Content-Type"] = ContentTypeOverride;
    }
}

Затем, если вы просмотрите ваш файл .svc, вы увидите, и класс AppServiceHostFactory изменит его, чтобы включить перехватчик

class AppServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var host = new WebServiceHost2(serviceType, true, baseAddresses);
        host.Interceptors.Add(new ContentTypeOverrideInterceptor("application/json; charset=utf-8"));
        return host;
    }
}

Это должно сделать это для вас.

Обновление

Как уже упоминалось в комментариях, вышеописанный метод предназначен для использования с стартовым набором WCF REST. Если вы используете только обычную службу WCF, вам нужно будет создать IOperationBehavior и прикрепить его к вашей службе. вот код для атрибута поведения

public class WebContentTypeAttribute : Attribute, IOperationBehavior, IDispatchMessageFormatter
{
    private IDispatchMessageFormatter innerFormatter;
    public string ContentTypeOverride { get; set; }

    public WebContentTypeAttribute(string contentTypeOverride)
    {
        this.ContentTypeOverride = contentTypeOverride;
    }


    // IOperationBehavior
    public void Validate(OperationDescription operationDescription)
    {

    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        innerFormatter = dispatchOperation.Formatter;
        dispatchOperation.Formatter = this;
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {

    }

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {

    }

    // IDispatchMessageFormatter
    public void DeserializeRequest(Message message, object[] parameters)
    {
        if (message == null)
            return;

        if (string.IsNullOrEmpty(ContentTypeOverride))
            return;

        var httpRequest = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
        httpRequest.Headers["Content-Type"] = ContentTypeOverride;
    }

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

И вам придется изменить свой контракт на обслуживание, чтобы он выглядел следующим образом

[OperationContract]
[WebContentType("application/json; charset=utf-8")]
public string DoWork(string FirstName, string LastName)
{
    return "Your name is " + LastName + ", " + FirstName;
}

Ссылки

Как вы и просили, здесь есть несколько ссылок, описывающих эти расширения WCF

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...