Reputation: 51
I have a problem to make my WCF websocket service working. Until now I cannot find how to establish a connection. Both client and server side are really simple. So I think I miss something obvious here.
I currently have one WCF service running properly in my solution. The web services are hosted under IIS, the connection is properly handled using https and using basic authentication.
Here is my web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms" />
</system.web>
<system.serviceModel>
<!--webHttpBinding allows exposing service methods in a RESTful manner-->
<services>
<service behaviorConfiguration="secureRESTBehavior" name="MyApp.Services.MyService">
<endpoint address="" behaviorConfiguration="RESTfulBehavior" binding="webHttpBinding" bindingConfiguration="webHttpTransportSecurity" contract="MyApp.Services.IMyService" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<!--WCF Service Behavior Configurations-->
<behaviors>
<endpointBehaviors>
<behavior name="RESTfulBehavior">
<webHttp defaultBodyStyle="WrappedRequest" defaultOutgoingResponseFormat="Json" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="secureRESTBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="MyApp.Security.CustomAuthorizationManager, MyApp">
<authorizationPolicies>
<add policyType=" MyApp.Security.AuthorizationPolicy, MyApp" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
<!--WCF Service Binding Configurations-->
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" transferMode="Streamed" sendTimeout="00:05:00">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="CORSModule" type="Security.CORSModule" />
</modules>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true" />
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://myapp.com" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
<add name="Access-Control-Allow-Methods" value="GET, DELETE, POST, PUT, OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Now I'm trying use WebSocketHost to host a WebSocket server as a WCF service.
Here is my factory:
public class TRWebSocketServiceFactory: ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
try
{
WebSocketHost host = new WebSocketHost(serviceType, baseAddresses);
host.AddWebSocketEndpoint();
return host;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
}
}
Here is the service:
public class EchoWSService : WebSocketService
{
public override void OnOpen()
{
this.Send("Welcome!");
}
public override void OnMessage(string message)
{
string msgBack = string.Format(
"You have sent {0} at {1}", message, DateTime.Now.ToLongTimeString());
this.Send(msgBack);
}
protected override void OnClose()
{
base.OnClose();
}
protected override void OnError()
{
base.OnError();
}
}
Here is my Global.asax file:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add(new ServiceRoute(
"Echo", new TRWebSocketServiceFactory(), typeof(EchoWSService)));
}
}
Here is the client side who try to establish a connection:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>WebSocket Chat</title>
<script type="text/javascript" src="Scripts/jquery-2.0.2.js"></script>
<script type="text/javascript">
var ws;
$().ready(function () {
$("#btnConnect").click(function () {
$("#spanStatus").text("connecting");
ws = new WebSocket("wss://MyServer/Echo");
ws.onopen = function () {
$("#spanStatus").text("connected");
};
ws.onmessage = function (evt) {
$("#spanStatus").text(evt.data);
};
ws.onerror = function (evt) {
$("#spanStatus").text(evt.message);
};
ws.onclose = function () {
$("#spanStatus").text("disconnected");
};
});
$("#btnSend").click(function () {
if (ws.readyState == WebSocket.OPEN) {
ws.send($("#textInput").val());
}
else {
$("#spanStatus").text("Connection is closed");
}
});
$("#btnDisconnect").click(function () {
ws.close();
});
});
</script>
</head>
<body>
<input type="button" value="Connect" id="btnConnect" /><input type="button" value="Disconnect" id="btnDisconnect" /><br />
<input type="text" id="textInput" />
<input type="button" value="Send" id="btnSend" /><br />
<span id="spanStatus">(display)</span>
</body>
</html>
On the line:
host.AddWebSocketEndpoint();
I always got the error:
Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].
I'm a bit confused about the following points:
Thanks!
Upvotes: 2
Views: 430
Reputation: 51
I was missing:
Binding binding = WebSocketHost.CreateWebSocketBinding(true);
before:
host.AddWebSocketEndpoint();
Now the endpoint is correct.
Upvotes: 1