0

I'm working on an interview project that has to call a simple WCF that I created. I've never used those before, so I'm a little lost. I spent several hours last night trying to get this to work, and have it narrowed down now to a serialization error.

This is the WCF I'm using.

[ServiceContract(Namespace = "HighEnergy.Web")]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CustomerService {
    private const string ACCT   = "9999999999";
    private const string PHONE  = "111-111-1111";

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
    public bool Validate(OutageModel model) {
        if (!string.IsNullOrWhiteSpace(model.AccountNumber) && !string.IsNullOrWhiteSpace(model.PhoneNumber)) {
            if (string.IsNullOrWhiteSpace(model.AccountNumber)) {
                model.AccountNumber = ACCT;
            }
            if (string.IsNullOrWhiteSpace(model.PhoneNumber)) {
                model.PhoneNumber = PHONE;
            }

            return model.AccountNumber == ACCT &&
                   model.PhoneNumber == PHONE;
        }

        return false;
    }
}

This is the OutageModel I'm using for that call.

[Serializable]
public class OutageModel {
    [RegularExpression(Utilities.AccountNumberRegex, ErrorMessage = "Your account number is 10 digits.")]
    public string AccountNumber { get; set; }
    [Phone(ErrorMessage = "Your phone number must be in 123-456-7890 format.")]
    public string PhoneNumber   { get; set; }

    public OutageModel() {
        this.Clear();
    }

    private void Clear() {
        this.AccountNumber  = string.Empty;
        this.PhoneNumber    = string.Empty;
    }
}

Here is how I'm trying to call it from my MVC page. I don't have it wired into any button events or anything, just sitting at the bottom of the page to run as it gets parsed.

$.ajax({
        url: '/CustomerService.svc/Validate',
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: {
            "AccountNumber": "9999999999",
            "PhoneNumber": "111-111-1111"
        }
    }
    ).done(function (data) {
        alert(data);
    }).error(function (xhr, status, error) {
        console.log(xhr.responseText);
        //alert("Error\n-----\n" + xhr.status + '\n' + xhr.responseText);
    });

The relevant section of the web.config:

<system.serviceModel>
  <diagnostics>
    <messageLogging
        logEntireMessage = "true"
        logMalformedMessages ="false"
        logMessagesAtServiceLevel ="true"
        logMessagesAtTransportLevel = "false"
        maxMessagesToLog = "3000"
        maxSizeOfMessageToLog ="2000" />
  </diagnostics>
  <bindings>
    <webHttpBinding>
      <binding name="WebHttpEndpointBinding">
        <security mode="TransportCredentialOnly">
          <transport clientCredentialType="Windows"/>
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="HighEnergy.Web.CustomerServiceAspNetAjaxBehavior">
        <enableWebScript />
        <dataContractSerializer maxItemsInObjectGraph="2147483647" />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="debug">
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
      <behavior name="AjaxServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceThrottling
                     maxConcurrentCalls="4096"
                     maxConcurrentSessions="4096"
                     maxConcurrentInstances="4096"
                   />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <standardEndpoints>
    <webHttpEndpoint>
      <standardEndpoint name="" contentTypeMapper="HighEnergy.Web.WebContentTypeMapper.JsonContentTypeMapper, JsonContentTypeMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </webHttpEndpoint>
  </standardEndpoints>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
    multipleSiteBindingsEnabled="false" />
  <services>
    <service name="HighEnergy.Web.CustomerService">
      <endpoint address="http://localhost:44208/CustomerService.svc" behaviorConfiguration="HighEnergy.Web.CustomerServiceAspNetAjaxBehavior"
        binding="webHttpBinding" contract="HighEnergy.Web.CustomerService" />
    </service>
  </services>
</system.serviceModel>

Here are the basics of the Exception details being returned to the client in that AJAX call (edited for brevity):

"Type" : "System.ServiceModel.Dispatcher.NetDispatcherFaultException"},
"ExceptionType" : "System.ServiceModel.Dispatcher.NetDispatcherFaultException",
"Message" : "The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'Validate'. Encountered unexpected character 'A'."

I can provide more of those details if needed. I have checked out several other questions, but after about 6 hours have been unable to get this to work. I'd imagine it's probably something monumentally simple that I'm missing, but any help would be appreciated.

Community
  • 1
  • 1
krillgar
  • 12,596
  • 6
  • 50
  • 86
  • I'm running this in Visual Studio 2013 Ultimate on Windows 8. It is just running via localhost. I did turn on the WCF items under both .NET 3.5 and 4.5 under Windows Features. – krillgar Jan 22 '15 at 14:03
  • If you have webhttpendpoint defined then why we need standardEndpoints? I am not saying it will solve your problem but lets keep things bare minimum to narrow down issue. – Pankaj Kapare Jan 22 '15 at 14:25
  • Is one preferable over the other? – krillgar Jan 22 '15 at 14:27
  • Depends on case by case basis.Standard endpoints define an endpoint that has default values or where one or more endpoint’s properties does not change whereas with explicit endpoint configuration we can change properties way we want. – Pankaj Kapare Jan 22 '15 at 14:33
  • I would say you add in your AjaxServiceBehavior and check response in fiddler. It may give detailed exception. – Pankaj Kapare Jan 22 '15 at 14:37
  • You will also need to modify service tag to include servicebehavior like this . – Pankaj Kapare Jan 22 '15 at 14:46
  • I followed the steps you provided. This is what I have in the Text View of Fiddler: "AccountNumber=9999999999&PhoneNumber=111-111-1111". I haven't used Fiddler much, so I'm not quite sure what I'm looking at. – krillgar Jan 22 '15 at 15:45
  • Try sending input data as json string instead of object in your javascript like this. data: '{"AccountNumber": "9999999999","PhoneNumber": "111-111-1111"}' – Pankaj Kapare Jan 22 '15 at 15:54

2 Answers2

1

I believe you are missing a JSON.stringify() around the data argument. Off the top of my head I don't know what a javascript object serializes to. They should probably have assumed that most people are going to want it serialized to json and accommodated that - but they don't, so arguments to $.ajax must be stringified before POSTing.

Tom W
  • 5,108
  • 4
  • 30
  • 52
0

I think the problem is that you're mixing up two different things. On one hand, you're using webHTTPBinding on the host side with an AJAX request. That should be OK, but you're also adding AspNetCompatibilityRequirements, which is a .NET-centric, Microsoft only, requirement, which won't work well with your Java stuff.

So I'd get rid of AspNetCompatibilityRequirements and try it again.

Brian
  • 3,653
  • 1
  • 22
  • 33
  • Do you mean JavaScript stuff? – krillgar Jan 22 '15 at 13:53
  • Exactly. The javascript /ajax stuff is fine. It will work with webhttpbinding and WCF, but when you add the AspNetCompatibilityRequirements option, I think you're creating problems for yourself. Get rid of that and see what happens. – Brian Jan 22 '15 at 13:54
  • http://stackoverflow.com/questions/9690191/what-does-aspnetcompatibilityrequirements-really-mean Take a look at this. – Brian Jan 22 '15 at 13:55
  • I removed the attribute on the class, and am still getting the same error. My question about the JavaScript was because in your answer, you just said "Java", which I don't use in this solution. – krillgar Jan 22 '15 at 13:58
  • 1
    AspNetCompatibilityRequirements shouldnt cause exception in question. – Pankaj Kapare Jan 22 '15 at 14:13