Enabling Cross Origin Requests for WebSockets in Spring - spring-mvc

I have a OpenShift Wildfly server. I am building a website with the Spring MVC framework. One of my webpages also uses a WebSocket connection. On the server side, I have used the #ServerEndpoint annotation and javax.websocket.* library to create my websocket:
package com.myapp.spring.web.controller;
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.web.socket.server.standard.SpringConfigurator;
#ServerEndpoint(value="/serverendpoint", configurator = SpringConfigurator.class)
public class serverendpoint {
#OnOpen
public void handleOpen () {
System.out.println("JAVA: Client is now connected...");
}
#OnMessage
public String handleMessage (Session session, String message) throws IOException {
if (message.equals("ping")) {
// return "pong"
session.getBasicRemote().sendText("pong");
}
else if (message.equals("close")) {
handleClose();
return null;
}
System.out.println("JAVA: Received from client: "+ message);
MyClass mc = new MyClass(message);
String res = mc.action();
session.getBasicRemote().sendText(res);
return res;
}
#OnClose
public void handleClose() {
System.out.println("JAVA: Client is now disconnected...");
}
#OnError
public void handleError (Throwable t) {
t.printStackTrace();
}
}
OpenShift gives a default URL, so all of my webpages (html files) have the common (canonical) hostname. For the sake of simplicity, I am calling this URL URL A (projectname-domainname.rhclound.com). I created an alias, CNAME, of URL A, which is called URL B (say https://www.mywebsite.tech). URL B is secure, as it has the https.
I am using a JavaScript client to connect to the WebSocket at the path /serverendpoint. The URI I am using in my html webpage file, test.html, is the following:
var wsUri = "wss://" + "projectname-domainname.rhclound.com" + ":8443" + "/serverendpoint";
When I open up URL A (projectname-domainname.rhclound.com/test), the WebSocket connects and everything works fine. However, when I try to connect to the websocket using URL B (https://mywebsite.tech/test), the JavaScript client immediately connects and disconnects.
Here is the message from the console that I receive:
Here is my JavaScript code that connects to the WebSocket:
/****** BEGIN WEBSOCKET ******/
var connectedToWebSocket = false;
var responseMessage = '';
var webSocket = null;
function initWS() {
connectedToWebSocket = false;
var wsUri = "wss://" + "projectname-domainname.rhcloud.com" + ":8443" + "/serverendpoint";
webSocket = new WebSocket(wsUri); // Create a new instance of WebSocket using usUri
webSocket.onopen = function(message) {
processOpen(message);
};
webSocket.onmessage = function(message) {
responseMessage = message.data;
if (responseMessage !== "pong") { // Ping-pong messages to keep a persistent connection between server and client
processResponse(responseMessage);
}
return false;
};
webSocket.onclose = function(message) {
processClose(message);
};
webSocket.onerror = function(message) {
processError(message);
};
console.log("Exiting initWS()");
}
initWS(); //Connect to websocket
function processOpen(message) {
connectedToWebSocket = true;
console.log("JS: Server Connected..."+message);
}
function sendMessage(toServer) { // Send message to server
if (toServer != "close") {
webSocket.send(toServer);
} else {
webSocket.close();
}
}
function processClose(message) {
connectedToWebSocket = false;
console.log("JS: Client disconnected..."+message);
}
function processError(message) {
userInfo("An error occurred. Please contact for assistance", true, true);
}
setInterval(function() {
if (connectedToWebSocket) {
webSocket.send("ping");
}
}, 4000); // Send ping-pong message to server
/****** END WEBSOCKET ******/
After a lot of debugging and trying various things, I concluded that this was problem was occurring because of the Spring Framework. This is because before I introduced the Spring Framework in my project, URL B could connect to the WebSocket, but after introducing Spring, it cannot.
I read on spring's website about WebSocket Policy. I came across their same origin policy which states that an alias, URL B, cannot connect to the WebSocket because it is not the same origin as URL A is. To solve this problem I disabled the same origin policy with WebSockets as said in the documentation, so I added the following code. I thought that doing so would fix my error. Here is what I added:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
#Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
However, this did not fix the problem, so I added the following method to my ApplicationConfig which extends WebMvcConfigurerAdapter:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://www.mywebsite.com");
}
This also didn't work either. Then I tried this:
package com.myapp.spring.security.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
#Configuration
public class MyCorsFilter {
// #Bean
// public FilterRegistrationBean corsFilter() {
// System.out.println("Filchain");
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// CorsConfiguration config = new CorsConfiguration();
// config.setAllowCredentials(true);
// config.addAllowedOrigin("https://www.mymt.tech");
// config.addAllowedHeader("*");
// config.addAllowedMethod("*");
// source.registerCorsConfiguration("/**", config);
// FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
// bean.setOrder(0);
// System.out.println("Filchain");
// return bean;
// }
#Bean
public CorsFilter corsFilter() {
System.out.println("Filchain");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // you USUALLY want this
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
System.out.println("Filchain");
return new CorsFilter(source);
}
}
This also did not work.
I even changed the var wsURI in the JS code to the following:
var wsUri = "wss://" + "www.mywebsite.com" + ":8443" + "/serverendpoint";
Then var wsUri = "wss://" + "mywebsite.com" + ":8443" + "/serverendpoint";
When I did this, the Google Chrome gave me an error, saying that the handshake failed. However, when I have this URL, var wsUri = "wss://" + "projectname-domianname.rhcloud.com" + ":8443" + "/serverendpoint";, I did not get the error that the handshake didn't occur, but I get a message that the connection opened and closed immediately (as seen above).
So how can I fix this?

Have you tried implementing the WebMvcConfigurer and overriding the method addCorsMappings()? If not try this and see.
#EnableWebMvc
#Configuration
#ComponentScan
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST")
.allowedHeaders("Origin", "Accept", "Content-Type", "Authorization")
.allowCredentials(true)
.maxAge(3600);
}
}

I don't think it's a CORS issue because it's connected successully before being disconnected. If that's CORS, you can't even connect.
I think it's a communication problem between your DNS & openshift because WebSocket need a persistent connection (long-live) which keeps opening between client & server. If your DNS (e.g. CloudFlare or something like that) does not support / not configured to use WebSocket, the client would be disconnected immediately as in your issue.

Related

How to make a Blazor page update the content of one html tag with incoming data from gRPC service

So i'm testing with Blazor and gRPC and my dificulty at the moment is on how to pass the content of a variable that is on a class, specifically the gRPC GreeterService Class to the Blazor page when new information arrives. Notice that my aplication is a client and a server, and i make an initial comunication for the server and then the server starts to send to the client data(numbers) in unary mode, every time it has new data to send. I have all this working, but now i'm left it that final implementation.
This is my Blazor page
#page "/greeter"
#inject GrpcService1.GreeterService GreeterService1
#using BlazorApp1.Data
<h1>Grpc Connection</h1>
<input type="text" #bind="#myID" />
<button #onclick="#SayHello">SayHello</button>
<p>#Greetmsg</p>
<p></p>
#code {
string Name;
string Greetmsg;
async Task SayHello()
{
this.Greetmsg = await this.GreeterService1.SayHello(this.myID);
}
}
The method that later receives the communication from the server if the hello is accepted there is something like this:
public override async Task<RequestResponse> GiveNumbers(BalconyFullUpdate request, ServerCallContext context)
{
RequestResponse resp = new RequestResponse { RequestAccepted = false };
if (request.Token == publicAuthToken)
{
number = request.Number;
resp = true;
}
return await Task.FromResult(resp);
}
Every time that a new number arrives i want to show it in the UI.
Another way i could do this was, within a while condition, i could do a call to the server requesting a new number just like the SayHello request, that simply awaits for a server response, that only will come when he has a new number to send. When it comes the UI is updated. I'm just reluctant to do it this way because i'm afraid that for some reason the client request is forgotten and the client just sit's there waiting for a response that will never come. I know that i could implement a timeout on the client side to handle that, and on the server maybe i could pause the response, with a thread pause or something like that, and when the method that generates the new number has a new number, it could unpause the response to the client(no clue on how to do that). This last solution looks to me much more difficult to do than the first one.
What are your thoughts about it? And solutions..
##################### UPDATE ##########################
Now i'm trying to use a singleton, grab its instance in the Blazor page, and subcribe to a inner event of his.
This is the singleton:
public class ThreadSafeSingletonString
{
private static ThreadSafeSingletonString _instance;
private static readonly object _padlock = new object();
private ThreadSafeSingletonString()
{
}
public static ThreadSafeSingletonString Instance
{
get
{
if (_instance == null)
{
lock(_padlock)
{
if (_instance == null)
{
_instance = new ThreadSafeSingletonString();
_instance.number="";
}
}
}
return _instance;
}
set
{
_instance.number= value.number;
_instance.NotifyDataChanged();
}
}
public int number{ get; set; }
public event Action OnChange;
private void NotifyDataChanged() => OnChange?.Invoke();
And in Blazor page in code section i have:
protected override void OnInitialized()
{
threadSafeSingleton.OnChange += updateNumber();
}
public System.Action updateNumber()
{
this.fromrefresh = threadSafeSingleton.number + " que vem.";
Console.WriteLine("Passou pelo UpdateNumber");
this.StateHasChanged();
return StateHasChanged;
}
Unfortunatly the updatenumber function never gets executed...
To force a refresh of the ui you can call the StateHasChanged() method on your component:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.componentbase.statehaschanged?view=aspnetcore-3.1
Notifies the component that its state has changed. When applicable, this will cause the component to be re-rendered.
Hope this helps
Simple Request
After fully understanding that your problem is just to Update the Page not to get unsyncronous messages from the server with a bi directional connection. So jou just have to change your page like (please not there is no need to change the files generated by gRPC, I called it Number.proto so my service is named NumberService):
async Task SayHello()
{
//Request via gRPC
var channel = new Channel(Host + ":" + Port, ChannelCredentials.Insecure);
var client = new this.NumberService.NumberServiceClient(channel);
var request = new Number{
identification = "ABC"
};
var result = await client.SendNumber(request).RequestAccepted;
await channel.ShutdownAsync();
//Update page
this.Greetmsg = result;
InvokeAsync(StateHasChanged);//Required to refresh page
}
Bi Directional
For making a continious bi directional connection you need to change the proto file to use streams like:
service ChatService {
rpc chat(stream ChatMessage) returns (stream ChatMessageFromServer);
}
This Chant sample is from the https://github.com/meteatamel/grpc-samples-dotnet
The main challenge on this is do divide the task waiting for the gRPC server from the client. I found out that BackgroundService is good for this. So create a Service inherited from BackgroundService where place the while loop waiting for the server in the ExecuteAsyncmethod. Also define a Action callback to update the page (alternative you can use an event)
public class MyChatService : BackgroundService
{
Random _random = new Random();
public Action<int> Callback { get; set; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// Replace next lines with the code request and wait for server...
using (_call = _chatService.chat())
{
// Read messages from the response stream
while (await _call.ResponseStream.MoveNext(CancellationToken.None))
{
var serverMessage = _call.ResponseStream.Current;
var otherClientMessage = serverMessage.Message;
var displayMessage = string.Format("{0}:{1}{2}", otherClientMessage.From, otherClientMessage.Message, Environment.NewLine);
if (Callback != null) Callback(displayMessage);
}
// Format and display the message
}
}
}
}
On the page init and the BackgroundService and set the callback:
#page "/greeter"
#using System.Threading
<p>Current Number: #currentNumber</p>
#code {
int currentNumber = 0;
MyChatService myChatService;
protected override async Task OnInitializedAsync()
{
myChatService = new MyChatService();
myChatService.Callback = i =>
{
currentNumber = i;
InvokeAsync(StateHasChanged);
};
await myChatService.StartAsync(new CancellationToken());
}
}
More information on BackgroundService in .net core can be found here: https://gunnarpeipman.com/dotnet-core-worker-service/

How to change client TLS preferences in Java?

I'm trying to make a POST request to an endpoint in Java, and when I try to send the request, I get the following error:
Caused by: javax.net.ssl.SSLHandshakeException: The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]
This is what I have so far
Map<Object, Object> data = new HashMap<>();
data.put("username","foo");
data.put("password","bar");
String url = "https://google.com";
HttpRequest request = HttpRequest.newBuilder()
.POST(buildFormDataFromMap(data))
.uri(URI.create(url))
.build();
try{
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
} catch (Exception e){
e.printStackTrace();
}
Then when I run the code, the error gets thrown when sending the request/making the response object. My question is, if the TLS preferences are different for the server than the client, how can I change the preferences within Java so it can still make the request?
To solve this problem in jdk 11, I had to create an javax.net.ssl.SSLParameters object to enable "TLSv1", etc:
SSLParameters sslParameters = new SSLParameters();
sslParameters.setProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
Then create the HttpClient and add the sslParamters object:
HttpClient httpClient = HttpClient.newBuilder()
.sslParameters(sslParameters)
.build();
If you also want to disable hostname verification, add following code BEFORE HttpClient initialization;
final Properties props = System.getProperties();
props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());
Also you can add a new TrustManager to trust all certificates (self signed).
To do so, add following code into your Class:
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
After this, you have to create an SSLContext object and add the TrustManger object:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
And finally alter the HttpClient initialization like this:
httpClient = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(sslParameters)
.build()
Here is a complete Class example:
import java.net.http.HttpClient;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Properties;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpSSLClient {
private SSLContext sslContext;
private SSLParameters sslParameters;
private HttpClient httpClient;
public HttpSSLClient() throws KeyManagementException, NoSuchAlgorithmException {
sslParameters = new SSLParameters();
sslParameters.setProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final Properties props = System.getProperties();
props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());
httpClient = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(sslParameters)
.build();
}
public HttpClient getHttplClient() {
return httpClient;
}
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
}
You can use the getHttplClient() function while calling your HttpRequest.
I had the same issue and this solution does not work for me.
Instead I saw this answer Android Enable TLSv1.2 in OKHttp and I tried this code:
ConnectionSpec spec = new ConnectionSpec
.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2,TlsVersion.TLS_1_0,TlsVersion.TLS_1_1,TlsVersion.TLS_1_3).build();
client =client.newBuilder().connectionSpecs(Collections.singletonList(spec)).build();
And it worked for me:)
I think mmo's answer should be highlighted in bold. I had similar issue, but found out that the open-jdk jvm I was using has TLSv1 and TLSv1.1 as disabled in the jdk.tls.disabledAlgorithms line in java.security. So as soon as I removed it and restarted the JVM, I was able to connect usingthe older TLS protocols.
But please pay ATTENTION, This is not advisable in Production since it degrades the secure communication. So I'd say change it if you want at YOUR OWN RISK!!!

How to post an image to azure-blob-storage from front-end(Angular8) while passing the file to backend(C#)

I am trying to allow users to upload an image for their profile pic. I want to store it inside of my azure-blob-storage. So after doing some research and going through different theories about doing this solely within the front end, I have decided to just pass the file to the backend and make the backend post to my azure blob. However, upon doing so, I get a 500 Internal Server error while attempting to upload a selected file.
I am using Angular 8 for my frontend code and using C#/ASP.NetCore for my backend. I have been able to successfully post an image to my azure-blob-storage with just my backend by using PostMan to see if my controller works. The main issue is getting my frontend code to pass this file to my controller which will handle posting to the azure-blob-storage.
I am using a service to provide a linkage between my upload-picture-component and the backend controller.
FrontEnd(Angular8)
'upload-profile-service.ts' snippet:
import { HttpClient, HttpEvent, HttpParams, HttpRequest } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '#angular/core';
import { environment } from '#env/environment';
#Injectable({
providedIn: 'root'
})
export class UploadProfileImageService {
// dependency injection
constructor(private _httpClient: HttpClient) { }
private baseurl = environment.api + '/myupload';
// change from any to type image.
public getImages(): Observable<any> {
return this._httpClient.get(this.baseurl);
}
// Form Data as image to pass to API to be pushed to Azure Storage
public postImages(formData: FormData): Observable<any> {
const saveImageUrl = this.baseurl + '/SaveFile';
return this._httpClient.post<any>(saveImageUrl, formData);
}
'upload-profile-component.ts' snippet:
constructor(
private consultantStore: ConsultantStore,
private notification: NotificationsService,
private dialogRef: MatDialogRef<Upload-Picture-Component>,
private _uploadProfileImageService: UploadProfileImageService,
private formBuilder: FormBuilder
) { }
ngOnInit(){}
selectedFile: File = null;
imageChangedEvent: any = '';
fileChangeEvent(event: any): void {
this.imageChangedEvent = event;
this.selectedFile = <File>this.imageChangedEvent.target.files[0];
}
UploadImageToBlob(){
const formData = new FormData();
formData.append(this.selectedFile.name, this.selctedFile, this.selectedFile.name);
this._uploadProfileImageService.postImages(formData)
.subscribe(res => {
console.log(res);
})
}
BackEnd(C#)
'UploadPicController.cs' snippet
[Route("myupload")]
[ApiController]
public class FileUploadController : Controller
{
private string _conn = <my_key_to_azure_blob_storage>;
private CloudBlobClient _blobClient;
private CloudBlobContainer _container;
private CloudStorageAccount _storageAccount;
private CloudBlockBlob _blockBlob;
[HttpPost("[Action]")]
public async Task<IActionResult> SaveFile(IFormFile files)
{
_storageAccount = CloudStorageAccount.Parse(_conn);
_blobClient = _storageAccount.CreateCloudBlobClient();
_container = _blobClient.GetContainerReference("profileimages");
//Get a reference to a blob
_blockBlob = _container.GetBlockBlobReference(files.FileName);
//Create or overwrite the blob with contents of a local file
using (var fileStream = files.OpenReadStream())
{
await _blockBlob.UploadFromStreamAsync(fileStream);
}
return Json(new
{
name = _blockBlob.Name,
uri = _blockBlob.Uri,
size = _blockBlob.Properties.Length
});
}
}
I want my azure blob to be able to receive the image via httpPost when the UploadImageToBlob function is called, but instead, I receive this error...
zone.js:3372 POST http://localhost:5000/myupload/SaveFile 500 (Internal Server Error)...
core.js:5847 ERROR HttpErrorResponse {headers: HttpHeaders, status: 500, statusText: "Internal Server Error", url: "http://localhost:5000/myupload/SaveFile", ok: false, …}error: "
↵http://localhost:5000/myupload/SaveFile: 500 Internal Server Error"name: "HttpErrorResponse"ok: falsestatus: 500statusText: "Internal Server Error"url: "http://localhost:5000/myupload/SaveFile"proto: HttpResponseBase...
Here is an update on what I get in the error log in Developer Tools
'NullReferenceException: Object reference not set to an instance of an object.'
Developer Tools -> 'Preview'
Here is my HttpPost method which worked for me:
[HttpPost]
public async Task<IActionResult> UploadFileAsync([FromForm]IFormFile file)
{
CloudStorageAccount storageAccount = null;
if (CloudStorageAccount.TryParse(_configuration.GetConnectionString("StorageAccount"), out storageAccount))
{
var client = storageAccount.CreateCloudBlobClient();
var container = client.GetContainerReference("fileupload");
await container.CreateIfNotExistsAsync();
CloudBlockBlob blob = container.GetBlockBlobReference(file.FileName);
await blob.UploadFromStreamAsync(file.OpenReadStream());
return Ok(blob.Uri);
}
return StatusCode(StatusCodes.Status500InternalServerError);
}
I was also getting the same issue when i tried to use below method:
GetBlockBlobReference() or `GetBlobReferenceFromServerAsync`
Also i would suggest you to add below line after getting the container reference:
await container.CreateIfNotExistsAsync();
When I debugged the code in network tab in developer tools while i was using GetBlobReferenceFromServerAsync()
here is the reason which was causing 500:
Please try to debug it from your end and see if it helps.
Let me know if you any assistance, will share my code base.

Using Websockets with Azure Websites - Error during WebSocket handshake

I am using Azure websites. In my ASP Net MVC project I created a websocket server and client. When trying to call my server I get
WebSocket connection to 'ws://binfx.azurewebsites.net/WebSocketServer.ashx' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET
My server class is:
WebSocketServer.ashx
public class WebSocketServer : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
context.AcceptWebSocketRequest(new MicrosoftWebSockets());
}
else
{
context.Response.ContentType = "text/plain";
context.Response.Write("Not a websocket response!");
context.Response.StatusCode=400;
}
}
}
My client code is:
Index.cshtml
window.onload = function () {
var conversation = $('body');
var localHost = window.document.location.host;
var url = "ws://" + localHost + "/WebSocketServer.ashx";
if (window.WebSocket) {
var ws = new WebSocket(url);
ws.onmessage = function (response) {
conversation.append(createSpan('Response:' + response.data));
}
ws.onopen = function (response) {
ws.send('message!');
conversation.append(createSpan('Azure CONNECTED'));
}
ws.onerror = function (e) {
conversation.append(createSpan("There are connection issues"));
}
}
else {
alert("Your browser does not support instant messaging. You need to regularly refresh your browser in order to receive updates");
}
}
I have enabled using Websockets in Azure Portal
Enabling using Websockets in Azure Portal
Thanks for your ideas!

Configuring WCF Services in Code WCF 4.5

Hi, I am trying to configure wcf using code behind, below is the code:
public static void Configure(ServiceConfiguration config)
{
string configPath = ConfigurationManager.AppSettings["wcfconfigDBPath"];
// Enable “Add Service Reference” support
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
// set up support for http, https, net.tcp, net.pipe
if (isEnabled(configPath, "enablehttp"))
config.EnableProtocol(new BasicHttpBinding());
if (isEnabled(configPath, "enablenettcp"))
config.EnableProtocol(new NetTcpBinding());
if (isEnabled(configPath, "enablepipe"))
config.EnableProtocol(new NetNamedPipeBinding());
}
private static bool isEnabled(string path, string elementName)
{
try
{
string elementValue = string.Empty;
bool returnVal = false;
using (XmlTextReader reader = new XmlTextReader(path))
{
reader.ReadToFollowing(elementName);
if (reader.Read())
elementValue = reader.Value;
}
if (!string.IsNullOrEmpty(elementValue))
{
bool.TryParse(elementValue, out returnVal);
}
return returnVal;
}
catch (Exception ex)
{
return false;
}
}
The above code is not working. I am not sure when the "static void Configure" gets fired.
My question is, is there any way to enable/disable the protocol based on DB/xml configuration without bringing down the service?
New feature in .NET 4.5 which probably can be used in your case:
Note: The configure method is called by WCF before the service host is opened.
The Configure method takes a ServiceConfiguration instance that enables the developer to add endpoints and behaviors. This method is called by WCF before the service host is opened. When defined, any service configuration settings specified in an app.config or web.config file will be ignored.
The following code snippet illustrates how to define the Configure method and add a service endpoint, an endpoint behavior and service behaviors:
public class Service1 : IService1
{
public static void Configure(ServiceConfiguration config)
{
ServiceEndpoint se = new ServiceEndpoint(new ContractDescription("IService1"), new BasicHttpBinding(), new EndpointAddress("basic"));
se.Behaviors.Add(new MyEndpointBehavior());
config.AddServiceEndpoint(se);
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Refer for complete example to:https://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx

Resources