user2156275
user2156275

Reputation: 23

Access WCF hosted in Windows Service

I have a problem when I try to access the WCF service hosted in a Windows service directly from a web application and I can't understand what I am doing wrong.

I try all suggestion which I found and didn't help anything. I use AngularJs, but that is not important, I accept all suggestions.

There is my project: https://github.com/djromix/Portal.WorckFlow

Portal.Services is the Windows service.

This is my windows service configuration:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>
</system.webServer>
<system.serviceModel>
    <behaviors>
          <serviceBehaviors>
            <behavior name="">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service name="Portal.Services.ServiceContract.PortalContract">
            <endpoint 
                address="" 
                binding="basicHttpBinding" 
                contract="Portal.Services.ServiceContract.IPortalContract">
                <identity>
                    <dns value="localhost" />
                </identity>
            </endpoint>
            <endpoint 
                address="mex" 
                binding="mexHttpBinding" 
                contract="IMetadataExchange" />
            <host>
                <baseAddresses>
                    <add baseAddress="http://localhost:8000/Portal" />
                </baseAddresses>
            </host>
        </service>
    </services>
</system.serviceModel>


Service Code:

 namespace Portal.Services.ServiceContract
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IPortalContract" in both code and config file together.
        [ServiceContract(Namespace = "")]
        public interface IPortalContract
        {
            [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
            double Ping();

            [OperationContract]
            object CashInResult(string key);
        }
    }

namespace Portal.Services.ServiceContract
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class PortalContract : IPortalContract
    {
        public double Ping()
        {
            return -1;
        }

        [WebGet]
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
        public object CashInResult(string key)
        {
            return new {Value = "Some Data"};
        }
    }
}

I just want simple access the url and get the json result
http://localhost:8000/Portal/CashInResult?key=secretkey

Now i get the error [Failed to load resource: the server responded with a status of 400 (Bad Request)]

From web application i get the error

 XMLHttpRequest cannot load /Portal/CashInResult?key=1. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '???' is therefore not allowed access. The response had HTTP status code 400.

Upvotes: 2

Views: 1565

Answers (2)

user2156275
user2156275

Reputation: 23

After many tries i found the solution.


     namespace Portal.Services.ServiceContract
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IPortalContract" in both code and config file together.
    [ServiceContract(Namespace = "")]
    public interface IPortalContract
    {
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
        double Ping();

        [OperationContract]
        string CashInResult(string key);
    }
}


namespace Portal.Services.ServiceContract
        {
            [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
            public class PortalContract : IPortalContract
            {
                readonly Logger _nLog = LogManager.GetCurrentClassLogger();
                public double Ping()
                {
                    using (var tMeter = new TimeMeterLog(_nLog, "Ping"))
                    {
                        tMeter.Info("-1");
                        return -1;
                    }
                }

                [WebGet(UriTemplate = "/CashInResult/{key}", ResponseFormat = WebMessageFormat.Json)]
                public string CashInResult(string key)
                {
                    using (var tMeter = new TimeMeterLog(_nLog, "CashInResult"))
                    {
                        var result = JsonConvert.SerializeObject(new { Value = "Some Data" });
                        tMeter.Info(result);
                        return result;
                    }
                }
            }
        }


Call service from browser:

http://localhost:8000/rest/Ping


Result:{"PingResult":-1}

There is source code. https://github.com/djromix/Portal.WorckFlow

Upvotes: 0

user844705
user844705

Reputation:

To get your GET request to work you could add the header (Access-Control-Allow-Origin) to the request yourself in the browser but only GET requests will work.

If you are running WCF in a windows service then system.webServer is not being used as there is no IIS.

This link show how to achieve fully CORS in WCF outside of IIS..

https://code.msdn.microsoft.com/windowsdesktop/Implementing-CORS-support-c1f9cd4b

but its a bit long to explain in an SO post but this is why its not working for you at the moment....

There are two types of requests in the CORS world, “normal” requests and "preflight" requests.

A normal, or safe (HTTP GET) request involves the browser sending an ORIGIN header with the request, and the server accepting/rejecting based on that.

A preflight, or unsafe (such as POST, PUT or DELETE) request involves the browser sending an HTTP OPTIONS request asking for permission to send the actual request to the server.

IIS looks after all this for you when you enable the settings in the system.webServer section. Hosting WCF as a windows service takes IIS out the picture, so in WCF you need to implement the CORS stuff yourself.

I think you should reconsider though and use IIS if the service's purpose is to serve HTTP requests.

Upvotes: 1

Related Questions