Quick look into SignalR

Last year, I was looking into various ways of communication between client and server for one of my project work. Evaluated SignalR too as one of the options. I found decent documentation online to put across a test app to see how it works.

Introduction

SignalR is a free and open-source software library for Microsoft ASP.NET that provides ability to server-side code push content to the connected clients in real-time.

Pushing data from the server to the client (not just browser clients) has always been a tough problem. SignalR makes it dead easy and handles all the heavy lifting for you.

https://github.com/SignalR/SignalR

Detailed documentation can be found at: https://dotnet.microsoft.com/apps/aspnet/signalr

Most of the shareout online considers it as ASP.NET/Web application solution only which is not true. As mentioned in quote above, client could be a non-browser too like a desktop application.

I gathered that behind the scenes, SignalR primarily tries to use Web Socket protocol to send data. WebSocket is a new HTML5 API (refer my detailed article on it) that enables bi-directional communication between the client and server. In case of any compatibility gap, SignalR uses other protocols like long polling.

P.S.: Since most of the code to make the test app was picked from web, all the credit to them. One specific source that I can recall: https://docs.microsoft.com/en-us/aspnet/signalr/overview/deployment/tutorial-signalr-self-host

Now, a quick peek into the SignalR test app
  • Using the SignalR Hub class to setup the server. Defined a hub that exposes a method like an end point for clients to send a message. Server can process the message and send back a response to all or few of the clients.
[HubName("TestHub")]
public class TestHub : Hub
{
    public void ProcessMessageFromClient(string message)
    {
        Console.WriteLine($"<Client sent:> {message}");

        // Do some processing with the client request and send the response back
        string newMessage = $"<Service sent>: Client message back in upper case: {message.ToUpper()}";
        Clients.All.ResponseToClientMessage(newMessage);
    }
}

  • Specify which “origins” we want to allow our application to accept. It is setup via CORS configuration. CORS is a security concept that allows end points from different domains to interact with each other.
public void Configuration(IAppBuilder app)
{
     app.UseCors(CorsOptions.AllowAll);
     app.MapSignalR();
}

  • Server is setup using OWIN (Open Web Interface for .NET). OWIN defines an abstraction between .NET web servers and web applications. This helps in self-hosting a web application in a process, outside of IIS.
static void Main(string[] args)
{
    string url = @"http://localhost:8080/";

    using (WebApp.Start<Startup>(url))
    {
        Console.WriteLine($"============ SERVER ============");
        Console.WriteLine($"Server running at {url}");
        Console.WriteLine("Wait for clients message requests for server to respond OR");
        Console.WriteLine("Type any message - it will be broadcast to all clients.");
        Console.WriteLine($"================================");

        // For server broadcast test
        // Get hub context 
        IHubContext ctx = GlobalHost.ConnectionManager.GetHubContext<TestHub>();

        string line = null;
        while ((line = Console.ReadLine()) != null)
        {
            string newMessage = $"<Server sent:> {line}";
            ctx.Clients.All.MessageFromServer(newMessage);
        }

        // pause to allow clients to receive
        Console.ReadLine();
    }
}

In above code, Using IHubContext:

  1. Server is setup to have earlier defined Hub as one of the broadcast end point.
  2. Server is also setup to broadcast any message to all clients by itself if needed be

  • Client is setup to communicate with the server (send and receive message) via hub using HubConnection & IHubProxy. Client can invoke the exposed end point in the hub to a send a message.
static void Main(string[] args)
{
    string url = @"http://localhost:8080/";

    var connection = new HubConnection(url);
    IHubProxy _hub = connection.CreateHubProxy("TestHub");
    connection.Start().Wait();

    // For server side initiation of messages
    _hub.On("MessageFromServer", x => Console.WriteLine(x));
    _hub.On("ResponseToClientMessage", x => Console.WriteLine(x));

    Console.WriteLine($"============ CLIENT ============");
    Console.WriteLine("Type any message - it will be sent as a request to server for a response.");
    Console.WriteLine($"================================");

    string line = null;
    while ((line = Console.ReadLine()) != null)
    {
        // Send message to Server
        _hub.Invoke("ProcessMessageFromClient", line).Wait();
    }

    Console.Read();
}

With above setup, we can see the communication between Client & Server realtime like below:

SignalR test

Things to consider while opting for SignalR

SignalR looks awesome. But, there are couple of things one should know while using it:

  • It’s a connected technology – each client connected through SignalR is using a persistent and dedicated connection on the Web Server. SignalR is shared as scalable but it never harms to look for any queries around connections, memory, cpu, etc with higher number of clients.
  • One would need to setup a valid host server with a PORT open on it that can be used for communication. This could depend on an organisation security protocols and approvals.

Hope this gives a quick overview about SignalR. Keep learning!

Download entire code for lookup from here: https://github.com/sandeep-mewara/SignalRTest

HTML5: Tips !!!

Long time, since I have blogged. Specifically, this particular post – had all the details and wanted to post more than a year back. I guess, better late than never!
Here are few of the HTML5 tips that might help while using it’s various features:

HTML5 WebSocket Protocol is present only from IIS 8.0

HTML5 Web Socket provides a two-way communication over one TCP connection (socket). IIS 8.0 (ships with Windows 8) is capable of accepting Web Socket communications. In order to use the new protocol, one has to enable it in IIS 8.0, using option “Turn Windows features on or off” present in the control panel. It should look like below:
WebSocketIIS8
A quick detail on how WebSocket works can be looked here in my article: http://www.codeproject.com/Articles/546960/HTML-Quick-Start-Web-Application#websocket
 

One can support new HTML5 elements in older browsers using HTML5 shiv

Older browsers that are still widely used by end users (namely IE6/7/8) do not have support for the new elements in HTML5. One great way to enable HTML5 element support in IE6/7/8 is to have the http://code.google.com/p/html5shiv/
As noted on the linked Google page, “shiv” and “shim” are interchangeable terms in this context.
In case interested, I came across a good sample example and details out here: http://www.sitepoint.com/html5-older-browsers-and-the-shiv/
 

Elements in HTML5 can easily be made draggable

The specifications defines an event-based mechanism – a JavaScript API and additional markup for declaring it. Any type of element can be marked draggable on a page. It’s a known fact that having a native browser support for a particular feature is best as they would be faster and provide a more responsive application.
A quick detail about the feature can be read here: http://www.codeproject.com/Articles/546960/HTML-Quick-Start-Web-Application#dragdrop
 

‘Type’ attribute for script and link are no more required in HTML5

Type attribute is optional and one does not need to provide it for script and link tag in HTML5.
Earlier, one used to give:

<link rel="stylesheet" href="somepath/somestylesheet.css" type="text/css" />
<script type="text/javascript" src="somepath/somescript.js" />

Now, in HTML5, same references can be provided as:

<link rel="stylesheet" href="somepath/somestylesheet.css" />
<script src="somepath/somescript.js" />

This makes things simpler as the file extension and the tag were enough to interpret the type.
 

async attribute has been added to <script> tag in HTML5

HTML5 has added a new attribute for <script> tag, which is async. With this attribute, the external script will be executed asynchronously as soon as it is available. It has no effect on inline scripts.
Inline scripts and scripts without async or defer attributes are fetched and executed immediately, before the browser continues to parse the page.
 

In HMTL5, all unknown element in all browsers are displayed inline by default

The three most commonly used values are none, block, and inline. All elements have an initial or default state for their display value.For all HTML5 elements, by default they have a computed display value of inline.
 

In HTML5, page and worker do not share the same instance

In HTML5, page and worker do not share the same instance – a duplicate is created on each pass. Data passed between the main page and workers are copied. Objects are serialized as they’re handed to the worker, and subsequently, deserialized on the other end. I read that most browsers implement this feature as structured cloning. (The structured clone algorithm is a new algorithm defined by the HTML5 specification for serializing complex JavaScript objects.)
A quick detail about the feature can be read here: http://www.codeproject.com/Articles/546960/HTML-Quick-Start-Web-Application#webworkers
 

In HMTL5 Offline, relative URLs listed in a manifest are resolved relative to the manifest file

Yes, the urls in the manifest are relative to manifest’s own url. It is not to be confused that they are relative to root. Though it might happen that the urls relative to root work good because the manifest file might be located in the application root.
A quick detail about the feature can be read here: http://www.codeproject.com/Articles/546960/HTML-Quick-Start-Web-Application#offlineapp

HTTP 500 – Internal server error

This is another common error that troubles a lot of ASP.NET users.

Problem Statement

Generally, the questions are framed like:

I receive a HTTP 500 – Internal Server Error  exception while trying to browse my hosted web application. Exception message says “This error (HTTP 500 Internal Server Error) means that the website you are visiting had a server problem which prevented the webpage from displaying”. Please help, how to resolve it?

Assessment

Any HTTP request made to web application running on IIS (or any other web server) returns the status of the response. This HTTP status code indicates about the request success or failure. If the request was unsuccessful, it might provide the reason why so.

Out of various status code, 5xx are the codes related to Server error. They indicate that the server failed to complete the request because server encountered an error.

The 500 Internal Server Error is a very general HTTP status code. It means something has gone wrong on the website and web server is unable to specify what exactly, thus failing in fulfilling the request made by the client. This is not related to client and the fault is in the webpage/website requested that resides on server. This status code can be considered as a ‘catch-all’ server error of Web server.

More details around various HTTP status code: The HTTP status code in IIS 7.0, IIS 7.5, and IIS 8.0

Possible Resolutions

Make sure that internally web server maintains some kind of internal error logs that gives more detail of what went wrong and thus help in diagnosing the issue. Generally, it is logged into Windows Event Logs on the server. Thus, first thing while troubleshooting the error is to see Windows Event Logs on the server to find what went wrong.

Other useful thing to troubleshoot it would be to disable friendly HTTP error messages to see if the raw content can provide a direction to look more. Steps:

  • Go to menu Tools/Internet Options in your IE.
  • Click on the Advanced tab & then uncheck “Show friendly HTTP error messages” option & then click Ok.
  • Now, when on accessing the same web page, much more developer meaningful error message will be shown.

Moving on, following are most common:

Option #1:
HRESULT: 0x80070035 – The page cannot be displayed because an internal server error has occurred.
This occurs because the server that is running IIS cannot access the configured root directory of the requested location.

Resolution would be to make sure that the server that is running IIS can access the configured root directory of the requested location.

Option #2:
HRESULT: 0x800700c1 – The page cannot be displayed because an internal server error has occurred.
This occurs because a script mapping is not valid.

Resolution would be to make sure that the script mapping points to the ISAPI.dll file that can process the request.
To do this, follow these steps:

  1. Click Start, click Run, type inetmgr.exe, and then click OK.
  2. In IIS Manager, expand server name, expand Web sites, and then click the Web site that you want to modify.
  3. In Features view, double-click Handler Mappings.
  4. Make sure that the script mapping points to the correct ISAPI.dll file. (e.g: .asp files should map to the %windir%\system32\inetsrv\asp.dll file)

Option #3:
HRESULT: 0x8007007f – There is a problem with the resource you are looking for, so it cannot be displayed.
This occurs because the handler mapping for the requested resource points to a .dll file that cannot process the request.

Resolution would be to edit the handler mapping for the requested resource to point to the .dll file that can process the request.
To do this, follow these steps:

  1. Click Start, click Run, type inetmgr.exe, and then click OK.
  2. In IIS Manager, expand server name, expand Web sites, and then click the Web site that you want to modify.
  3. In Features view, double-click Handler Mappings.
  4. Right-click the script mapping that you want to edit, and then click Edit.
  5. In the Edit Script Map dialog box, type the appropriate executable file in the Executable box, and then click OK.

Option #4:
One of the other possibilities could be an issue in the way web application is hosted. Some security configuration issue or conflict due to multiple config files.

Resolution would be to make sure application is hosted correctly by published the application as website and setting up the virtual directory as needed.
More details around the known issues and their resolution:
Error message when you visit a Web site that is hosted on IIS 7.0: “HTTP Error 500.0 – Internal Server Error”
Troubleshoot an “HTTP 500 – Internal Server Error” error message on IIS 4.0 or on IIS 5.0

Conclusion

This is a server error and can only be solved by website admin who has access to files and the web-server. There can be one of/or multiple reasons to get this error. One has to track down the issue and handle accordingly.

Keep learning!

Browser Back button issue after logout

I have found a lot of people asking for a resolution to handle the browser’s back button once user has logged out.

Problem description

Typically, users reports something like:

I am facing issue in my application’s logout scenario. After the user login into website, he/she uses it(website) and when done, they do a logout, which leads them back to login page. But the problem is now, from this login page, if I click the browser back button then it again takes the user back to the previous visited page as if logged in. How can I stop user from viewing the previous page once logged out?

Assessment

The browser Back button is an option to go back to previously visited pages. The back button can be considered as a pointer that is linked to the page previously visited by the user. Browser keeps a stack of the web pages visited as a doubly-linked list.

The back button works by stepping through the history of HTTP requests which is maintained by the browser itself. This history is stored in browsers cache that consists of the entire page content with resources like image and scripts. This enables browser to navigate backwards and forwards through the browser history and have each page displayed instantly from cache without the delay of having it re-transmitted over the internet from the server.

Just to handle the scenario of getting page content from server, browsers have a Refresh button transmits the request to web server and get back the fresh copy of entire page. Internally, this also replaces the copy of the page in the browser’s cache.
Thus, basic reason behind the problem in discussion is Browser’s Cache!

Possible Resolutions

On Logout, one does clear the session to make sure user related data no more exists. Now, browsers cache needs to be handled such that browser has no history (this will make back/forward button in browser grayed out disabled.)

Here are various ways of how one can do it:

Option #1: 
Set Response Cache settings in code-behind file for a page

// Code disables caching by browser.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
Response.Cache.SetNoStore();


Option #2:
Set META tag for HTTP cache settings in your ASPX page header

<META Http-Equiv="Cache-Control" Content="no-cache"/>
<META Http-Equiv="Pragma" Content="no-cache"/>
<META Http-Equiv="Expires" Content="0"/>


Option #3:
Clear browser’s history through JavaScript using script tag

<SCRIPT LANGUAGE="javascript">
//clears browser history and redirects url
function ClearHistory()
{
     var backlen = history.length;
     history.go(-backlen);
     window.location.href = loggedOutPageUrl
}
</SCRIPT>


Option #4:
Clear browser’s history through JavaScript injecting through code-behind file via Response

protected void LogOut()
{
     Session.Abandon();
     string loggedOutPageUrl = "Logout.aspx";
     Response.Write("<script language='javascript'>");
     Response.Write("function ClearHistory()");
     Response.Write("{");
     Response.Write(" var backlen=history.length;");
     Response.Write(" history.go(-backlen);");
     Response.Write(" window.location.href='" + loggedOutPageUrl + "'; ");
     Response.Write("}");
     Response.Write("</script>");
}


Option #5:
Clear browser’s history through JavaScript injecting through code-behind file via Page.ClientScript

Page.ClientScript.RegisterStartupScript(this.GetType(),"clearHistory","ClearHistory();",true);

Conclusion

Any one or combination of above can be used to handle the scenario.
Though, I would like to call out that it’s not a good thing to mess with browser’s history. One should implement it, only if they really need it and are prepared to accept that it is not a good practice. Lastly, few would not work if one disables JavaScript.

NOTE: I would not suggest to use it and mess with browser’s history as this is a bad thing. One should implement it, only if they really need it and are prepared to accept that it is not a good practice.

Keep learning!

“Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack”

This is one of the common runtime error reported by a lot of ASP.NET users.

Problem description

A successfully compiled code at runtime throws the following error during an operation:

“Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.”

Typically, this happens when the Response.EndResponse.Redirect, or Server.Transfer method is used.

Assessment

This happens because current page execution is stopped and execution is sent to the Application_EndRequest event in the application’s event pipeline.

The duty of Response.End method is to stop the page execution and raise the EndRequest event. Thus, the line of code that follows Response.End is not executed. Error occurs with Response.Redirect and Server.Transfer methods too because both the methods call Response.End internally.

When a call is made to the Abort method to destroy a thread, the CLR throws a ThreadAbortException. It is a special exception that can be caught, but will automatically be raised again at the end of the catch block. When this exception is re-raised, the CLR executes all the finally blocks before ending the thread.

Using Visual Studio debugger, we can see the internal message for the exception as “Thread was being aborted.”

Resolution

Try one of the following that suits your workflow:

  • Use a try-catch statement to catch the exception if needed
try { 
  // your code here
} 
catch (System.Threading.ThreadAbortException ex){ 
  // log/handle it
}
  • For Response.End:
    Invoke HttpContext.Current.ApplicationInstance.CompleteRequest method instead of Response.End to bypass the code execution to the Application_EndRequest event
  • For Response.Redirect
    Use an overload,  Response.Redirect(String url, bool endResponse) that passes false for endResponse parameter to suppress the internal call to Response.End
Response.Redirect ("mynextpage.aspx", false);
  • For Server.Transfer
    Use Server.Execute method to bypass abort. When Server.Execute is used, execution of code happens on the new page, post which the control returns to the initial page, just after where it was called.

Refer:
Microsoft Support Article – 312629
MSDN: HttpResponse.Redirect Method
MSDN: HttpResponse.End Method
MSDN: ThreadAbortException Class
MSDN: HttpServerUtility.Execute Method

Conclusion

This is as designed. This exception has bad effect on Web application performance, which is why handling the scenario correctly is important.

Keep learning!

“Cannot evaluate expression because the code of the current method is optimized”

This is one the common error faced by a lot of Visual Studio users.

Problem description

Typically, they get the below error message during debugging:

“Cannot evaluate expression because the code of the current method is optimized.”

Assessment

In .NET, “Function Evaluation (funceval)” is the ability of CLR to inject some arbitrary call while the debuggee is stopped somewhere. Funceval takes charge of the debugger’s chosen thread to execute requested method. Once funceval finishes, it fires a debug event. Technically, CLR have defined ways for debugger to issue a funceval.

CLR allows to initiate funceval only on those threads that are at GC safe point (i.e. when the  thread will not block GC) and Funceval Safe (FESafe) point (i.e. where CLR can actually do the hijack for the funceval.) together.

Thus, possible scenarios for CLR, a thread must be:
1. stopped in managed code  (and at a GC safe point): This implies that we cannot do a funceval in native code. Since, native code is outside the CLR’s control, it is unable to setup the funceval.
2. stopped at a 1st chance or unhandled managed exception (and at a GC safe point): i.e at time of exception, to inspect as much as possible to determine why that exception occurred. (e.g: debugger may try to evaluate and see the Message property on raised exception.)

Overall, common ways to stop in managed code include stopping at a breakpoint, step, Debugger.Break call, intercepting an exception, or at a thread start. This helps in evaluating the method and expressions.
Refer: MSDN Blog: Rules of Funceval

Possible resolutions

Based on the assessment, if thread is not at a FESafe and GCSafe points, CLR will not be able to hijack the thread to initiate funceval. Generally, following helps to make sure funceval initiates when expected:

Step #1:
Make sure that you are not trying to debug a “Release” build. Release is fully optimized and thus will lead to the error in discussion. By using the Standard toolbar or the Configuration Manager, you can switch between Debug & Release.
For more details about it: How to: Set Debug and Release Configurations

Step #2:
If you still get the error, “Debug option” might be set for optimization. Verify & Uncheck the “Optimize code” property under Project “Properties”:

  • Right click the Project
  • Select option “Properties”
  • Go to “Build” tab
  • Uncheck the checkbox “Optimize code”

Step #3:
If you still get the error, “Debug Info” mode might be incorrect. Verify & set it to “full” under “Advanced Build Settings”:

  • Right click the Project
  • Select option “Properties”
  • Go to “Build” tab
  • Click “Advanced” button
  • Set “Debug Info” as “full”

Step #4:
If you still face the issue, try the following:

  • Do a “Clean” & then a “Rebuild” of your solution file
  • While debugging:
    1. Go to modules window (VS Menu -> Debug -> Windows -> Modules)
    2. Find your assembly in the list of loaded modules.
    3. Check the Path listed against the loaded assembly is what you expect it to be
    4. Check the modified Timestamp of the file to confirm that the assembly was actually rebuilt
    5. Check whether or not the loaded module is optimised or not
  • Remote chance could be that your call stack is getting optimized because your method signature is too large (more than 256 argument bytes). Read more about it at this MSDN blog

Conclusion

It’s not an error but an information based on certain settings and as designed based on how .NET runtime works.

Keep learning!

“Invalid postback or callback argument”

This is one the common issues that a lot of ASP.NET beginners face, post and ask about.

Problem description

Typically, they post the error message as below and seek for resolution without sharing much about what they were trying to do.

[ArgumentException: Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation=”true” %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.]

Though, error stack trace itself suggests a quick resolution by setting eventvalidation off, it is not a recommended solution as it opens up a security hole. It is always good to know why it happened and how to solve/handle that root problem.

Assessment

Event validation  is done to validate if the origin of the event is the related rendered control (and not some cross site script or so). Since control registers its events during rendering, events can be validated during postback or callback (via arguments of __doPostBack). This reduces the risk of unauthorized or malicious postback requests and callbacks.
Refer: MSDN: Page.EnableEventValidation Property

Based on above, possible scenarios that I have faced or heard that raises the issue in discussion are:

Case #1:
If we have angular brackets in the request data, it looks like some script tag is being passed to server

Possible Solution:
HTML encode the angular brackets with help of JavaScript before submitting the form, i.e. replace “<” with “&lt;” and “>” with “&gt;”

function HTMLEncodeAngularBrackets(someString)
{
   var modifiedString = someString.replace("<","<");
   modifiedString = modifiedString.replace(">",">");
   return modifiedString;
}

Case #2:
If we write client script that changes a control in the client at run time, we might have a dangling event. An example could be having embedded controls where an inner control registers for postback but is hidden at runtime because of an operation done on outer control. This I read about on MSDN blog written by Carlo, when looking for same issue because of multiple form tags.

Possible Solution:
Manually register control for event validation within Render method of the page.

protected override void Render(HtmlTextWriter writer)
{     ClientScript.RegisterForEventValidation(myButton.UniqueID.ToString());
   base.Render(writer);
}

As said, one of the other common scenario reported (which looks like falls in the this same category) is building a page where one form tag is embedded in another form tag that runs on server. Removing one of them corrects the flow and resolves the issue.

Case #3:
If we re-define/instantiate controls or commands at runtime on every postback, respective/related events might go for a toss. A simple example could be of re-binding a datagrid on every pageload (including postbacks). Since, on rebind all the controls in grid will have a new ID, during an event triggered by datagrid control, on postback the control ID’s are changed and thus the event might not connect to correct control raising the issue.

Possible Solution:
This can be simply resolved by making sure that controls are not re-created on every postback (rebind here). Using Page property IsPostback can easily handle it. If one want to create control on every postback, then it is necessary to make sure that the ID’s are not changed.

protected void Page_Load(object sender, EventArgs e)
{
    if(!Page.IsPostback)
    {
      // Create controls
      // Bind Grid
    }
}

Conclusion

As said, easy/direct solution can be adding enableEventValidation="false" in the Page directive or Web.config file but is not recommended. Based on the implementation and cause, find the root cause and apply the resolution accordingly.

Keep learning!