Search code examples
c#jsonrestwcf-binding

Can't configure WCF Restful/json endpoints correctly


I created a restful service and was able to have it generate a JSON response when receiving XML requests, but I needed it to accept JSON requests. I tweaked the processes but had issues because I originally had the main service invoking multiple services, each with its own C# interface. It told me I had to explicitly name the endpoints and it all went to the trash heap after that. I finally gave up on calling multiple services and instead went to a single service with multiple operations contracts calling methods.

Now I just get a simple "endpoint not found" message. I really, really don't understand the ins and outs of the endpoint definitions.

Here is the code on my main service page (AgtDash.svc). We're calling up statistics for an "agent dashboard"

EDIT - updated the code to reflect the URI template reference, which made no change, and changing the service name reference in the web.config. Now the error is no longer "endpoint not found", but a 404 reference, instead.

namespace AgentDashboard
{

    public class AgtDash : dashboardInfo
    {

        public string GetAgencyInfo(agcInfoInput agcInput)
        {
            string agInfo = string.Empty;

            (RETRIEVES DATA TABLE)

            agInfo = tableToJson(agcTable);
            return agInfo;
        }

        public string GetAgencyDetails(agcInfoInput agcInput)
        {
            string agcyInfo = string.Empty;

            (RETRIEVES DATA TABLE)

            agcyInfo = tableToJson(agcTable);
            return agcyInfo;
        }

        public string GetAgencyTotals(agcInfoInput agcInput)
        {
            string agcyTot = string.Empty;

            (RETRIEVES DATA TABLE)

            agcyTot = tableToJson(agcTable);
            return agcyTot;
        }

        public string GetAgentTotals(agtInfoInput agtInput)
        {
            (RETRIEVES DATA TABLE)

                agtInfo = tableToJson(agTable);
            return agtInfo;
        }

        public string tableToJson(DataTable inpTable)
        {
            var jsString = new StringBuilder();

            (CONVERTS DATA TABLE TO JSON RESPONSE)

            return jsString.ToString();
        }
    }
}

Here is my interface:

namespace AgentDashboard
{
    [ServiceContract]
    public interface dashboardInfo
    {
        [OperationContract]
        [WebInvoke(UriTemplate="/GetAgentTotals",
            Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        string GetAgentTotals(agtInfoInput agentInput);

        [OperationContract]

        [WebInvoke(UriTemplate="/GetAgencyInfo",
            Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
               BodyStyle = WebMessageBodyStyle.Wrapped)]

        string GetAgencyInfo(agcInfoInput agencyInput);

        [OperationContract]

        [WebInvoke(UriTemplate="/GetAgencyDetails",
        Method = "POST",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Wrapped)]

        string GetAgencyDetails(agcInfoInput agencyInput);

        [OperationContract]

        [WebInvoke(UriTemplate="/GetAgentTotals",
            Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        string GetAgencyTotals(agcInfoInput agencyInput);
    }


    [DataContract]
    public class agtInfoInput
    {
        [DataMember]
        public string id { get; set; }

        [DataMember]
        public int year { get; set; }

    }

    [DataContract]
    public class agcInfoInput
    {
        [DataMember]
        public int id { get; set; }

        [DataMember]
        public int year { get; set; }

    }
}

My web config:

<system.serviceModel>
    <client>
      <endpoint binding="webHttpBinding" contract="AgentDashboard.dashboardInfo" />
    </client>
    <services>
      <service name="AgentDashboard.AgtDash">
        <endpoint address="dashboardInfo" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="AgentDashboard.dashboardInfo" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="AgtDash.svc" />
          </baseAddresses>
        </host>       
      </service>
    </services>
    <bindings>
      <webHttpBinding>
        <binding>
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>      
    </behaviors>
  </system.serviceModel>

I'm sure that web.config is a random mess. When do I need to define the service, with endpoint details? When do I use the client configuration? When do I use both? It seemed to be working locally okay when I originally had multiple client endpoints, but when it told me I had to define the service, I went that route.

Sorry if there are answers out there, but they are all very different in the solutions and don't offer me much insight into the whys. Ultimately, this is going to reside in its own web application/directory, being served by IIS, and needs to receive and send JSON. The generation of the JSON response seems to be working, it's getting the endpoints identified correctly that is stopping me from fully testing this because I can't correctly identify the target, so to speak.

If anything about the web.config jumps out at you, let me know. Thanks in advance.

CURRENT ERROR:

404ErrorCapture


Solution

  • There is no need to define extra service endpoints. Based on your configuration, the operation/methods should be in the following form.

    Http://host:portnumber/AgtDash.svc/dashboardInfo/GetAgentTotals
    Http://host:portnumber/AgtDash.svc/dashboardInfo/GetAgentInfo
    Http://host:portnumber/AgtDash.svc/dashboardInfo/GetAgencyDetails   
    Http://host:portnumber/AgtDash.svc/dashboardInfo/GetAgencyTotals.  
    

    When being called, we should attach parameter in the Body section, with Post Http verb. The service base configured in the Webconfig could be ignored. It is determined by the IIS site binding.
    Feel free to let me know if there is anything I can help with.
    Updated.
    replace <service name="AgentDashboard.AgentDashInfo"> with <service name=”AgentDashboard.AgtDash”>. Here the implemented class with namespace should be configured.