Connor Gervin
Connor Gervin

Reputation: 946

Can't connect to rest webservice through c# client

I am trying to create a c# client application to my RESTful webservice.

I've added the web reference (ServiceReference1) to the client application but I'm getting errors like endpoint configuration does not exist for 'UserService1.svc'.

I'm aware that 'add service reference' does not create all the required configurations when using a Rest Service, but I really can't see where I'm going wrong!

Here's my files

Client application

namespace WebServiceClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        UserService1Client webService;
        List<User> userList = new List<User>();

        public MainWindow()
        {
            InitializeComponent();            
            webService = new UserService1Client();
            serviceMethods();
        }

        private void serviceMethods()
        {
            string[] results = webService.GetUsersNames();
        }
    }
}

Client - web.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IUserService1" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:53215/UserService1.svc" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IUserService1" contract="ServiceReference1.IUserService1"
        name="BasicHttpBinding_IUserService1" />
    </client>

  </system.serviceModel>

</configuration>

Service - Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>    
  </configSections>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
    </compilation>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="WcfRestSample.UserService1">
        <endpoint address="" contract="WcfRestSample.IUserService1" binding="webHttpBinding" behaviorConfiguration="restBehavior"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="restBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
  <connectionStrings>
      <add name="cs4_databaseEntities" connectionString="metadata=res://*/cs4_model.csdl|res://*/cs4_model.ssdl|res://*/cs4_model.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\cs4_database.mdf;integrated security=True;user instance=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

IUserService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfRestSample
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IUserService1" in both code and config file together.
    [ServiceContract]
    public interface IUserService1
    {
        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Xml)]
        List<string> GetUsersNames();
    }
}

UserService1.svc

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace WcfRestSample
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "UserService1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select UserService1.svc or UserService1.svc.cs at the Solution Explorer and start debugging.
    public class UserService1 : IUserService1
    {
        public List<string> GetUsersNames()
        {
            using (cs4_databaseEntities entities = new cs4_databaseEntities())
            {
                return entities.Users.Select(user => user.Name).ToList();
            }
        }
    }
}

Hopefully someone can help me out here!!

Upvotes: 0

Views: 2463

Answers (1)

Charlie Ou Yang
Charlie Ou Yang

Reputation: 641

First of all for a RESTFUL service, you need to declare a webhttpbinding, and not a basichttpbinding (this is for SOAP services). In your REST service, you should have have these configurations

1) Declare your service and its endpoint

<services>
    <service name="SparqlService.SparqlService" behaviorConfiguration="ServiceBehavior">
        <endpoint binding="webHttpBinding" contract="SparqlService.ISparqlService" behaviorConfiguration="webHttp" />
    </service>
</services>

Service name will be [project name].[service name] Behavior configuration will be same name as the behavior you declare in the next step Binding must be webHttpBinding because you want it as REST. If you want SOAP, you declare as basicHttpBinding Contract is the [project name].[interface name] Behavior configuration in the endpoint will be the name you declare in next step

2) Declare the service behavior (usually default)

<behavior name="ServiceBehavior">
    <serviceMetadata httpGetEnabled="true" />
    <serviceDebug includeExceptionDetailInFaults="false" />
</behavior>

Behavior name can be anything, but it will be used to match BehaviorConfiguration you declared in step 1 Leave the rest alone

3) Delcare your endpoint behavior

<endpointBehaviors>
    <behavior name="webHttp">
        <webHttp />
    </behavior>
</endpointBehaviors>

Beavior name can be anything, but it will be used to match the behaviorConfiguration in endpoint.

In the end, this is what the web.config should look like for a simple REST service:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <services>
            <service name="SparqlService.SparqlService" behaviorConfiguration="ServiceBehavior">
                <endpoint binding="webHttpBinding" contract="SparqlService.ISparqlService" behaviorConfiguration="webHttp" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
                <behavior>
                    <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                    <serviceMetadata httpGetEnabled="true" />
                    <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
                <behavior name="webHttp">
                    <webHttp />
                </behavior>
            </endpointBehaviors>
        </behaviors>
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
</configuration>

After your web.config is done, this is a sample WCF REST Service and its respective C# Client

In order to send data through a POST or PUT, you need to construct your data correctly according to the WCF service. Here is basically what you need (Just change the POST to PUT for your application)

1) WCF Service Interface

[OperationContract]
[WebInvoke(Method = "POST",
    UriTemplate = "GetData",
    RequestFormat = WebMessageFormat.Xml,
    BodyStyle = WebMessageBodyStyle.Bare)]
string GetData(DataRequest parameter);

2) WCF Service Implementation

public string GetData(DataRequest parameter)
{
    //Do stuff
    return "your data here";
}

3) Data Contract in your WCF service (In this case it's DataRequest)

[DataContract(Namespace = "YourNamespaceHere")]
public class DataRequest
{
    [DataMember]
    public string ID{ get; set; }
    [DataMember]
    public string Data{ get; set; }
}

4) Client sending the data must have the data constructed properly! (C# console app in this case)

static void Main(string[] args)
{
    ASCIIEncoding encoding = new ASCIIEncoding();
    string SampleXml = "<DataRequest xmlns=\"YourNamespaceHere\">" +
                                    "<ID>" +
                                    yourIDVariable +
                                    "</ID>" +
                                    "<Data>" +
                                    yourDataVariable +
                                    "</Data>" +
                                "</DataRequest>";

    string postData = SampleXml.ToString();
    byte[] data = encoding.GetBytes(postData);

    string url = "http://localhost:62810/MyService.svc/GetData";

    string strResult = string.Empty;

    // declare httpwebrequet wrt url defined above
    HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
    // set method as post
    webrequest.Method = "POST";
    // set content type
    webrequest.ContentType = "application/xml";
    // set content length
    webrequest.ContentLength = data.Length;
    // get stream data out of webrequest object
    Stream newStream = webrequest.GetRequestStream();
    newStream.Write(data, 0, data.Length);
    newStream.Close();

    //Gets the response
    WebResponse response = webrequest.GetResponse();
    //Writes the Response
    Stream responseStream = response.GetResponseStream();

    StreamReader sr = new StreamReader(responseStream);
    string s = sr.ReadToEnd();

    return s;
}

Upvotes: 1

Related Questions