Here is a deep discussion of how it works:
JavaScript delete property delete variable
Thoughts about software development, business, management, and life.
public class ReportsApiController : ApiController { [System.Web.Http.HttpGet] public HttpResponseMessage GetQueryResultByWebSocket() { HttpContext.Current.AcceptWebSocketRequest(new MyWebSocketHandler(this)); return Request.CreateResponse(HttpStatusCode.SwitchingProtocols); }....
}
internal class MyWebSocketHandler : WebSocketHandler
{
private static WebSocketCollection _connectedClients;
private ApiController _controller;
static MyWebSocketHandler()
{
_connectedClients = new WebSocketCollection();
}
public MyWebSocketHandler(ApiController controller)
{
this._controller = controller;
}
public override void OnOpen()
{
base.OnOpen();
_connectedClients.Add(this);
}
public override void OnClose()
{
_connectedClients.Remove(this);
base.OnClose();
}
public override void OnMessage(string message)
{
HttpContext ctx = HttpContext.Current;
var currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture;
var currentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
new Task(() =>
{
HttpContext.Current = ctx;
System.Threading.Thread.CurrentThread.CurrentCulture = currentCulture;
System.Threading.Thread.CurrentThread.CurrentUICulture = currentUICulture;
var request =
JsonConvert.DeserializeObject(message);
Debug.WriteLine("Received #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
try
{
if (request.url == "/api/ReportsApi/GetQueryResult")
{
var data = MyQueriesModel.GetQueryResult(request.queryParams);
UmiWebSocketResponse result = new UmiWebSocketResponse
{
data = data,
error = null,
id = request.id,
timeStampSent = request.timeStampSent
};
Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
this.Send(JsonConvert.SerializeObject(result));
}
else if (request.url == "/api/ReportsApi/GetQueryObjResult")
{
var jss = new JavaScriptSerializer();
jss.MaxJsonLength = int.MaxValue;
var data = jss.Serialize(UmiQueriesModel.GetQueryObj(request.queryParams));
UmiWebSocketResponse result = new UmiWebSocketResponse
{
data = data,
error = null,
id = request.id,
timeStampSent = request.timeStampSent
};
Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
this.Send(JsonConvert.SerializeObject(result));
}
else if (request.url == "/api/ReportsApi/GetResource")
{
var jss = new JavaScriptSerializer();
jss.MaxJsonLength = int.MaxValue;
var prefix = "MyLibrary.Resources.Reports.";
try
{
var fullNames = request.queryParams.QueryName.Split(',');
var data = new Dictionary();
foreach (var fullName in fullNames)
{
int idx = fullName.LastIndexOf('.');
var typeName = fullName.Substring(0, idx);
var fullTypeName = typeName;
var resourceName = fullName.Substring(idx + 1);
if (!fullTypeName.StartsWith(prefix))
fullTypeName = prefix + fullTypeName;
try
{
var rm = new ResourceManager(fullTypeName, Assembly.GetExecutingAssembly());
data.Add(typeName + "." + resourceName, rm.GetString(resourceName));
}
catch (Exception ex)
{
Debug.WriteLine("Error performing resource request: {0}",
request.queryParams == null ? "null" : request.queryParams.QueryName);
data.Add(typeName + "." + resourceName, "");
}
}
UmiWebSocketResponse result = new UmiWebSocketResponse
{
data = jss.Serialize(data),
error = null,
id = request.id,
timeStampSent = request.timeStampSent
};
Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
this.Send(jss.Serialize(result));
}
catch (Exception ex)
{
Debug.WriteLine("Error performing resource request: {0}",
request.queryParams == null ? "null" : request.queryParams.QueryName);
UmiWebSocketResponse result = new UmiWebSocketResponse
{
data = "",
error = "Error performing resource request",
id = request.id,
timeStampSent = request.timeStampSent
};
Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
this.Send(jss.Serialize(result));
}
}
else
{
var routeToSearch = request.url.Replace("/PartialViews/", "");
var methods = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.IsSubclassOf(typeof(PartialViewsController)))
.SelectMany(t => t.GetMethods())
.Where(m =>
{
if (m.Name == routeToSearch)
return true;
System.Web.Mvc.RouteAttribute attr =
m.GetCustomAttributes(typeof(System.Web.Mvc.RouteAttribute), false).FirstOrDefault() as System.Web.Mvc.RouteAttribute;
if (attr == null)
return false;
return attr.Template == routeToSearch;
})
.ToArray();
if (methods.Length > 0)
{
var controller = Activator.CreateInstance(methods[0].DeclaringType) as PartialViewsController;
string baseUrl = HttpContext.Current
.Request
.Url
.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
var routeData = new RouteData();
routeData.Values.Add("controller", controller.GetType().Name.Replace("Controller", ""));
var controllerContext = new ControllerContext(
new HttpContextWrapper(
new HttpContext(
new HttpRequest(null, baseUrl + request.url, null),
new HttpResponse(null))),
routeData, controller);
controller.ControllerContext = controllerContext;
PartialViewResult pvr;
if (methods[0].GetParameters().Length == 2)
{
pvr = methods[0].Invoke(controller, new object[] { request.queryParams, Type.Missing }) as PartialViewResult;
}
else if (methods[0].GetParameters().Length == 1)
{
pvr = methods[0].Invoke(controller, new object[] { request.queryParams }) as PartialViewResult;
}
else
{
pvr = methods[0].Invoke(controller, new object[0]) as PartialViewResult;
}
var data = pvr == null ? null : ConvertPartialViewToString(controller.ControllerContext, pvr);
UmiWebSocketResponse result = new UmiWebSocketResponse
{
data = data,
error = null,
id = request.id,
timeStampSent = request.timeStampSent
};
Debug.WriteLine("Sent #{0} @{1} t:{2}", request.id, DateTime.Now,
Thread.CurrentThread.ManagedThreadId);
this.Send(JsonConvert.SerializeObject(result));
}
}
}
catch (Exception ex)
{
UmiWebSocketResponse errorResult = new UmiWebSocketResponse
{
error = ex.Message,
data = null,
id = request.id,
timeStampSent = request.timeStampSent
};
this.Send(JsonConvert.SerializeObject(errorResult));
}
}).Start();
}
private string ConvertPartialViewToString(ControllerContext controllerContext, PartialViewResult partialView)
{
using (var sw = new StringWriter())
{
partialView.View = ViewEngines.Engines
.FindPartialView(controllerContext, partialView.ViewName).View;
var vc = new ViewContext(
controllerContext, partialView.View, partialView.ViewData, partialView.TempData, sw);
partialView.View.Render(vc, sw);
var partialViewString = sw.GetStringBuilder().ToString();
return partialViewString;
}
}
}
my.infrastructure.webSocketHandler.send({ dataType: 'html', url: "/PartialViews/MyPartialView" }, function (result) { // do something with result });
my.infrastructure.useWebSocket = true;
my.infrastructure.webSocketHandler = (function () {
var uri = (location.protocol === "https:" ? "wss://" : "ws://").concat(window.location.hostname).concat("/api/reportsApi/GetQueryResultByWebSocket");
var requests = {
};
var counter = 0;
var websocket;
if (my.infrastructure.useWebSocket) {
websocket = new WebSocket(uri);
websocket.onopen = function () {
console.log("Connected to Web Socket");
};
websocket.onerror = function (event) {
console.log("ERROR CONNECTING TO WEB SOCKET");
};
websocket.onmessage = function (event) {
var message = JSON.parse(event.data);
message.timeStampReceived = new Date();
var id = message.id;
if (requests[id]) {
var request = requests[id];
console.log(message.timeStampReceived.toISOString() + ": Web Socket response received from " + request.request.url + " (queryName: " + (request.request.queryParams ? request.request.queryParams.queryName : "undefined") + "): "
//+ JSON.stringify(message)
);
if (message.Error) {
request.onError(message.error);
} else {
var data = message.data;
request.onSuccess(data);
}
delete requests[request[id]];
}
};
}
function sendRequest(settings, onSuccess, onError) {
if (!my.infrastructure.useWebSocket) {
// do some AJAX if asked for
}
var id = counter++;
var message = {
id: id,
queryParams: settings.data,
url: settings.url,
type: settings.type,
dataType: settings.dataType,
timeStampSent: new Date()
};
var messageStr = JSON.stringify(message);
requests[id] = {
onSuccess: onSuccess, onError: onError, request: message
};
waitForSocketConnection(websocket, function () {
console.log(message.timeStampSent.toISOString() + ": Web Socket message sent to " + settings.url + " (queryName: " + (message.queryParams ? message.queryParams.queryName : "undefined") + "): "
//+ messageStr
);
websocket.send(messageStr);
});
}
function abortAll() {
requests = {
};
}
function abortQuery(queryName) {
$.each(requests, function (index, request) {
if (request && request.request.queryName === queryName) {
delete requests[request[id]];
}
});
}
function waitForSocketConnection(socket, callback) {
var retryCounter = 3000; // 5 minutes
setTimeout(
function () {
if (socket.readyState === 1) {
if (callback != null) {
callback();
}
return;
} else {
if (retryCounter-- > 0) {
console.log("Waiting for Web Socket connection...");
waitForSocketConnection(socket, callback);
}
}
}, 100);
}
return {
send: sendRequest,
abortAll: abortAll,
abortQuery: abortQuery
}
})();
npm i -g npm-check-updates
npm-check-updates -u
npm install
After reinstalling the Windows, Suite ASP.NET application does not work: 0x80070021. This configuration section cannot be used at this path
Unexpectedly help comes from Microsoft Knowledge Base:
http://support.microsoft.com/kb/942055/
See case #9
http://learn.iis.net/page.aspx/145/how-to-use-locking-in-iis-70-configuration
Editing the %windir%\system32\inetsrv\config\applicationHost.config helped.
Error message:
HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
Detailed Error Information
| Module | AnonymousAuthenticationModule |
| Notification | AuthenticateRequest |
| Handler | PageHandlerFactory-ISAPI-2.0-64 |
| Error Code | 0x80070021 |
| Config Error | This configuration section cannot be used at this path. This happens when the section is locked at a parent level. Locking is either by default (overrideModeDefault="Deny"), or set explicitly by a location tag with overrideMode="Deny" or the legacy allowOverride="false". |
| Config File | \\?\C:\Dev\531Patch00\Root\Web\Logon\web.config |
Spent the whole day trying to force my self-hosted service to respond.
Finally what has helped is two lines below to execute (port, certhash, path and user name are up to you. Not sure about appid yet :-) ):
netsh http add urlacl url=httpS://+:2202/PatientService user=DOMAIN\user
netsh http add sslcert ipport=0.0.0.0:2202 certhash=ea81a9b4c330247f966d23d7e21266171f92cd47 appid={4EF5AB95-0A11-43b1-842C-51D56687CC7A}
Now need to understand - WHY??