views:

66

answers:

2

I am working on a WCF rest interface using json. I have wrapped the service in a windows service to host the service but I am now having trouble getting the service to be callable. I am not sure exactly what is wrong.

The basic idea is that I want to host the service on a remote server so I want the service mapped to port localhost:7600 so that it can be invoked by posting data to [server_ip]:7600. The problem is most likely in the configuration file, since I am new to WCF and Rest I wasn't really sure what to type for the configuration so sorry if it's a total mess.

I removed several chunks of code and comments to make it a little easier to read. These functions should have no bearing on the service since they call only C# functions.

EDIT: I looked at the post suggested, and rewrote the code, but unfortunately, it still is not functional. Mabye I'm just using the wrong address, you would invoke this with http://localhost:7600, right?

EDIT: Thanks guys for all your help. The problem was that you cannot use ServiceHost with a property that uses UriTemplate. So if I remove that, the service at least halfway works. I still am stuck on one part though. The service needs to be callable via HTTP Requests like you can produce with Fiddler. Any ideas on how I would do that?

EDIT: NVM, that was a stupid question. Post data to http://localhost:7600/PCMiler_Connect_Imple and that returns the json data. Thanks again guys.

EDIT: So this would be more helpful to someone else having the same problem, I have added the code as it is now, with a json invoke example.

WCF Service Interface

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

namespace PCMiler_Service
{
    [ServiceContract]
    public interface IPCMiler_Connect
    {
        [WebInvoke(Method = "POST",
                   ResponseFormat = WebMessageFormat.Json,
                   RequestFormat = WebMessageFormat.Json), //code corrected
        OperationContract]
        List<string> PCMiler_Connect_Imple(ZIP_List_Container container);
    }
}

WCF Service Implementation

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

namespace PCMiler_Service
{
    [DataContract]
    public class ZIP_List_Container
    {
        [DataMember]
        public string[] ZIP_List { get; set; }
        [DataMember]
        public string Optimized { get; set; }
        [DataMember]
        public string Calc_Type { get; set; }
        [DataMember]
        public string Cross_International_Borders { get; set; }
        [DataMember]
        public string Use_Kilometers { get; set; }
        [DataMember]
        public string Hazard_Level { get; set; }
        [DataMember]
        public string OK_To_Change_Destination { get; set; }
    }

    public class PCMiler_Connect : IPCMiler_Connect
    {
        public List<string> PCMiler_Connect_Imple(ZIP_List_Container container)
        {
            return container.ZIP_List.ToList<string>();
        }
    }
}

XML Config File

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="PCMiler_Service.PCMiler_ConnectBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
          <endpointBehaviors>
            <behavior name="jsonBehavior"  >
              <enableWebScript />
            </behavior>
          </endpointBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="PCMiler_Service.PCMiler_ConnectBehavior"
                name="PCMiler_Service.PCMiler_Connect">
              <endpoint address="" behaviorConfiguration="jsonBehavior" binding="webHttpBinding"
                  contract="PCMiler_Service.IPCMiler_Connect" />
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:7600/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>
</configuration>

Service Wrapper

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace PCMiler_Service
{
    public partial class PCMiler_Service : ServiceBase
    {
        ServiceHost host;
        Thread thread;

        public PCMiler_Service()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            host = new ServiceHost(typeof(PCMiler_Connect));
            host.Open();
        }

        protected override void OnStop()
        {
            if (host != null)
            {
                host.Close();
                host = null;
            }
        }
    }
}

JSON POST Example with HTTP

POST /PCMiler_Connect_Imple HTTP/1.1
HOST: localhost:7600
Content-Type: application/json
Content-Length: 84

{
     "container": {
                    "ZIP_List":["29340","29614"]
      }
}
A: 

Probably a daft question but ... Where's your interface?

If you read this ...

http://weblogs.asp.net/ralfw/archive/2007/04/14/a-truely-simple-example-to-get-started-with-wcf.aspx

... it (like every other article on WCF) implies that an interface declaration is definately required in order to expose the service as it also defines the datacontract that is used when a client consumes the service.

This however does not look like your typical WCF service, more like a normal good old fashioned windows service which is not a WCF service (as you should see from that link), however it appears that you have ried to use some WCF component parts (like the contract attributes).

I think your problem is your missing interface declaration, I gather that WCF requires this.

Wardy
It's actually ok. You can decorate a class with the 'ServiceContract' attribute and the class becomes the interface as well as the implementation. If you use the VS project template in VS2010 it actually creates it this way. I agree it is confusing, but that's WCF for you.
Darrel Miller
A: 

I think you need to use WebServiceHost instead of ServiceHost.

Darrel Miller
Actually, this work perfectly with absolutely no complaints.
bulletshot60
@bulletshot60 I'm confused. Are you saying that my suggestion helped or that you are able to expose WCF REST endpoints without using the WCF REST service host (i.e. System.ServiceModel.Web.WebServiceHost)?
Darrel Miller
I am able to expose the endpoints without using System.ServiceModel.Web.WebServiceHost by using System.ServiceModel.ServiceHost.
bulletshot60
That is curious. Just be aware that some things don't seem to work unless you use WebServiceHost. See this question http://stackoverflow.com/questions/2903652/how-to-call-a-service-operation-at-a-rest-style-wcf-endpoint-uri
Darrel Miller