Continue from our previous post "Posting compressed data in JSON format to the ASP.NET website using WinForm", in HttpWebRequest, there is a property called "AutomaticDecompression" (boolean) which is able to decompress the server response without extra codes.
Now, the question is that if we set this property to true, does it compress the data before sending it to the web server? After research and confirm that it does not compress the data before sending.
Below is the sample code to upload the data after
string url = "http://localhost:30000/myHandler.ashx";
System.Net.HttpWebRequest req = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
req.ContentType = "text/json";
req.Method = "POST";
req.AutomaticDecompression = System.Net.DecompressionMethods.GZip
| System.Net.DecompressionMethods.Deflate;
// generate dummy data.
string s = "";
for (int i = 0; i < 100; i++)
{
s += Guid.NewGuid().ToString();
}
using (System.IO.StreamWriter w = new System.IO.StreamWriter(req.GetRequestStream()))
{
w.WriteLine("helo me.." + s);
}
In the ASHX handler, you may verify the content length that has been submitted from the client:
public class myHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0}-header=>"
+ context.Request.ContentLength.ToString(),
DateTime.Now.ToString("d/MMM/yy @ HH:mm:ss.fff")));
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable
{
get
{
return false;
}
}
}
Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts
Sunday, May 27, 2018
Wednesday, October 4, 2017
Cross-Origin Request Blocked (CORS)
To speed up the development and future upgrade, we split the huge
application into multiple AJAX services. Each AJAX service in running in
it's own application pool and it can be run on different server. The
design works perfectly. But, when you want to consume the AJAX services
through the browser, you bang your head: "Cross-Origin Request Blocked".
This is the error message that appeared in the Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/schedule/q?code=tx&ts=1507099862873. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘(null)’).
Google Chrome returned an error message that is slightly different:
Failed to load http://localhost/schedule/q?code=tx&ts=1507099946004: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://localhost:56269' is therefore not allowed access.
Now, if you are googling for the solution, you will end up with add the following settings in the web.config.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
But, the wild card origin is no longer supported. You ended up with adding the specific origin.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:56292" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Imagine that you are hosting your AJAX services in multiple servers with different sub-domains.... the above solution will not work. This is because you are not allowed adding more than one domain name to "Access-Control-Allow-Origin".
To solve the problem, we need to handle the OPTIONS verb by adding the following settings in the web.config:
<system.webServer>
<handlers>
<add verb="OPTIONS" name="check_opt" path="*" type="ajaxLib.CORS_OPTIONS" />
</handlers>
</system.webServer>
And below is the simplified code that allows CORS:
namespace ajaxLib {
public class CORS_OPTIONS : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod.ToUpper() == "OPTIONS") {
string s = context.Request.Headers["Origin"];
if (!string.IsNullOrWhiteSpace(s))
{
context.Response.AppendHeader("Access-Control-Allow-Origin", s);
context.Response.AppendHeader("Access-Control-Allow-Headers", "Content-Type");
context.Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
}
}
}
public bool IsReusable { get { return false; }}
}}
Two possibilities if you want to use the above code in the live environment,
1. If your service allows public access without any restriction, skip checking the Origin value.
2. If your service allows specific domain to access, you must check the Origin value before return it to the caller.
This is the error message that appeared in the Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/schedule/q?code=tx&ts=1507099862873. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘(null)’).
Google Chrome returned an error message that is slightly different:
Failed to load http://localhost/schedule/q?code=tx&ts=1507099946004: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://localhost:56269' is therefore not allowed access.
Now, if you are googling for the solution, you will end up with add the following settings in the web.config.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
But, the wild card origin is no longer supported. You ended up with adding the specific origin.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:56292" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Imagine that you are hosting your AJAX services in multiple servers with different sub-domains.... the above solution will not work. This is because you are not allowed adding more than one domain name to "Access-Control-Allow-Origin".
To solve the problem, we need to handle the OPTIONS verb by adding the following settings in the web.config:
<system.webServer>
<handlers>
<add verb="OPTIONS" name="check_opt" path="*" type="ajaxLib.CORS_OPTIONS" />
</handlers>
</system.webServer>
And below is the simplified code that allows CORS:
namespace ajaxLib {
public class CORS_OPTIONS : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod.ToUpper() == "OPTIONS") {
string s = context.Request.Headers["Origin"];
if (!string.IsNullOrWhiteSpace(s))
{
context.Response.AppendHeader("Access-Control-Allow-Origin", s);
context.Response.AppendHeader("Access-Control-Allow-Headers", "Content-Type");
context.Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
}
}
}
public bool IsReusable { get { return false; }}
}}
Two possibilities if you want to use the above code in the live environment,
1. If your service allows public access without any restriction, skip checking the Origin value.
2. If your service allows specific domain to access, you must check the Origin value before return it to the caller.
Labels:
.Net,
AJAX,
ASP.NET,
C#,
Security Design,
System Design
Tuesday, October 4, 2016
Using partial HTML UI + ASHX to speed up page loading
Just to share with everyone that I developed many LOB app (line of business application) and I'm still developing new LOB for my clients. LOB is very different from blog engine, corporate websites and static websites. In LOB, we can happily ignore the contents to be "readable" by SEO because some of the contents were loaded by AJAX.
As per my last blog dated 26th-June-2016, I mentioned the new strategy: JQuery + AJAX + partial HTML UI. Now, the question is how is partial HTML UI that can help out is speeding up the page loading? The answer is simple, we need to rely on the browser cache by checking the "If-Modified-Since" flag in the request header. Then, responding either status code 304 (resource has not been modified) or returning the partial HTML to the browser.
You will find tons of references if you are searching for "asp.net If-Modified-Since". Below is one of the reference that I found:
http://madskristensen.net/post/use-if-modified-since-header-in-aspnet
The down side of this strategy is that the user will feel a bit slower on the first request to load the full page. But, the subsequent page loading or if the user is requesting for the same page, then, the time taken will be shorter. For example, we want to develop a page for user to key in the sales invoice and it allows the user from choosing the item from the list. The sales invoice is stored in a HTML file (not ASPX) and the item list HTML design is stored in another HTML file (where this item list will be reused by supplier invoice).
One of the advantage using this strategy is that it allows all these partial HTML file to be hosted in CDN (Content Delivery Network). Then, the whole LOB app will be loaded faster than using only one ASPX which could be crazily huge and hard to reuse some of the HTML design.
Note: "partial HTML UI" can be refer as "template" and it does not contains the HEAD and BODY tags. It just contains some DIV-s which eases the web designer to design and test in the browser. You don't need a programmer to start full coding but just some simple JQuery and AJAX to complete the demo.
As per my last blog dated 26th-June-2016, I mentioned the new strategy: JQuery + AJAX + partial HTML UI. Now, the question is how is partial HTML UI that can help out is speeding up the page loading? The answer is simple, we need to rely on the browser cache by checking the "If-Modified-Since" flag in the request header. Then, responding either status code 304 (resource has not been modified) or returning the partial HTML to the browser.
You will find tons of references if you are searching for "asp.net If-Modified-Since". Below is one of the reference that I found:
http://madskristensen.net/post/use-if-modified-since-header-in-aspnet
The down side of this strategy is that the user will feel a bit slower on the first request to load the full page. But, the subsequent page loading or if the user is requesting for the same page, then, the time taken will be shorter. For example, we want to develop a page for user to key in the sales invoice and it allows the user from choosing the item from the list. The sales invoice is stored in a HTML file (not ASPX) and the item list HTML design is stored in another HTML file (where this item list will be reused by supplier invoice).
One of the advantage using this strategy is that it allows all these partial HTML file to be hosted in CDN (Content Delivery Network). Then, the whole LOB app will be loaded faster than using only one ASPX which could be crazily huge and hard to reuse some of the HTML design.
Note: "partial HTML UI" can be refer as "template" and it does not contains the HEAD and BODY tags. It just contains some DIV-s which eases the web designer to design and test in the browser. You don't need a programmer to start full coding but just some simple JQuery and AJAX to complete the demo.
Labels:
.Net,
AJAX,
ASHX,
ASP.NET,
C#,
Enhancement,
Optimization,
Reusable,
System Design,
System Development
Sunday, June 26, 2016
System design with ASHX web services (JQuery + AJAX + partial HTML UI)
Recently, we are working on a few new systems with ASP.NET. In the past, we are using Page (ASPX) + ScriptManager and we are facing some limitation in the system design which includes the following:
To solve this problem, here is the list of frequent use "web service" to be implemented with Handler (ASHX):
<system.web>
<urlMappings>
<add url="~/q" mappedUrl="~/myWebService/q.ashx"/>
</urlMappings>
</system.web>
The design these web services:
- The system does not allow the user to add a new "item" into the drop down list on the fly.
- The drop down list contains a few hundred items and we need to incorporate the 'search' functionality or paging to avoid all items to be loaded in one shot.
- The data submitted to server failed to meet the validation process and causing the entire page sent back to the client (which travel from client to the server and then back to the client).
- We must use JQuery + AJAX + partial HTML UI design so that it allows the user from adding "item" to the drop down list on the fly. The partial HTML UI will appear on the screen as a popup for user adding new item. After the user has submitted the new item to the server, validated OK and it will be added to the drop down list on the fly (with JQuery) without reloading the page or navigating to another page.
- The drop down list that contains lots of item will be replace by a textbox. Upon the user clicking on this textbox, the items will be loaded from the server (with AJAX calls) and then display in the popup (with JQuery + partial HTML UI). To improve the user's experience, you may consider the auto-complete feature upon the user typing the text or divide the data using the paging concept.
- We must do more AJAX calls for submitting the user input to be validated by the system. In case of any failure such as validation failed, the server should returns the error message only. This avoids the entire page to be re-created in the server and then send to the browser.
To solve this problem, here is the list of frequent use "web service" to be implemented with Handler (ASHX):
- ~/q - this web service handles the "query" that includes CRUD (create, return, update & delete) processes, daily process, ad-hoc process and all other business processes. The report request is another area which you may consider to put into this service.
- ~/t - this web service returns the "HTML template" (partial HTML UI design) to be injected to the current web page. By creating the partial HTML UI file, it allows the designer to work on the layout without have to go through all the JQuery + the DOM element generation (i.e., low level stuffs). Modifying the DOM elements using JQquery is very time consuming and it requires a more expensive Javascript programmer. But, we have done it with a cheaper costing. The nice partial HTML UI has been done by the designer and the programmer requires to populate the JSON data into the appropriate placeholder.
- ~/f - this web service handles all the file services that include upload, download/view. For example, when the user calls out the "contact list", it shows the profile photo of the contact. This profile photo IMG SRC is "~/f?contact_id=124567" where "contact_id" is the primary key value of the contact. It does not point to any physical file name. The "f" service will do all the necessary at the server side and returns the binary of the photo (an image file).
<system.web>
<urlMappings>
<add url="~/q" mappedUrl="~/myWebService/q.ashx"/>
</urlMappings>
</system.web>
The design these web services:
- Client is making a request to the web service:
- "code" - the command code, object type or process code to be executed.
- "action" - this includes CRUD and other actions (such as run daily job, run hour job).
- "query parameters" - the query parameters are wrapped into a JSON object. For example, the client is requesting the customers who is owing more than $10,000 for more than 90 days.
- Responding to the client:
- "msg" - the message to the client. "ok" to indicate the query has successfully executed. Otherwise, it contains the error message.
- "list" - the list of JSON formatted data requested by the client. This information is optional.
Labels:
.Net,
AJAX,
ASHX,
ASP.NET,
C#,
Enhancement,
JQuery,
Optimization,
System Design
Thursday, July 2, 2015
Posting data in JSON format to the ASP.NET website using WinForm
Previously, we have shown how to post JSON data using JQuery to ASP.NET.
http://laucsharp.blogspot.com/2013/03/posting-data-in-json-format-to-aspnet.html
Now, we are going to post JSON data using WinForm:
This is our business object which will reside at the server and client.
public class Class1
{
public string code { get; set; }
public string name { get; set; }
public override string ToString()
{
return string.Format("code={0}, name={1}",
this.code,
this.name);
}
}
In the WinForm client program, when the user hit Button1 after keyed in the client code and name, the data will be submitted to the server:
private void button1_Click(object sender, EventArgs e)
{
// store the user input into the business object.
Class1 data = new Class1();
data.code = this.client_code.Text;
data.name = this.client_name.Text;
// convert it into json format.
JavaScriptSerializer js = new JavaScriptSerializer();
string json_data = js.Serialize(data);
// create the web request.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost:57655/dataGateway.ashx");
request.ContentType = "application/json;";
request.Method = "POST";
// write the json data into the request stream.
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(json_data);
}
// get the server response.
using (WebResponse response = request.GetResponse())
{
// read the server response.
Stream response_stream = response.GetResponseStream();
using (StreamReader r = new StreamReader(response_stream))
{
// do what ever you want with the response.
this.label5.Text = r.ReadToEnd();
}
}
}
Finally, at the server side, we add a Generic Handler (dataGateway.ashx) and it looks like this:
<%@ WebHandler Language="C#" Class="dataGateway" %>
using System;
using System.Web;
using System.IO;
using System.Web.Script.Serialization;
public class dataGateway : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string s;
// get the contents from the request stream
Stream stream = context.Request.InputStream;
using (StreamReader r = new StreamReader(stream))
{
s = r.ReadToEnd();
}
// ensure that the content is not empty.
if (string.IsNullOrEmpty(s) || s.Length == 0)
{
context.Response.Write("'data' cannot be blank");
return;
}
// convert it from json format to our business object
JavaScriptSerializer js = new JavaScriptSerializer();
Class1 obj = js.Deserialize<Class1>(s);
// do whatever you want
context.Cache["data"] = obj;
// returns the response code/status to the caller.
context.Response.Write("ok. received the data =>" + s);
}
public bool IsReusable { get { return false; } }
}
Next, sending compressed data in WinForm:
http://laucsharp.blogspot.my/2018/04/posting-compressed-data-in-json-format.html
http://laucsharp.blogspot.com/2013/03/posting-data-in-json-format-to-aspnet.html
Now, we are going to post JSON data using WinForm:
This is our business object which will reside at the server and client.
public class Class1
{
public string code { get; set; }
public string name { get; set; }
public override string ToString()
{
return string.Format("code={0}, name={1}",
this.code,
this.name);
}
}
In the WinForm client program, when the user hit Button1 after keyed in the client code and name, the data will be submitted to the server:
private void button1_Click(object sender, EventArgs e)
{
// store the user input into the business object.
Class1 data = new Class1();
data.code = this.client_code.Text;
data.name = this.client_name.Text;
// convert it into json format.
JavaScriptSerializer js = new JavaScriptSerializer();
string json_data = js.Serialize(data);
// create the web request.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost:57655/dataGateway.ashx");
request.ContentType = "application/json;";
request.Method = "POST";
// write the json data into the request stream.
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(json_data);
}
// get the server response.
using (WebResponse response = request.GetResponse())
{
// read the server response.
Stream response_stream = response.GetResponseStream();
using (StreamReader r = new StreamReader(response_stream))
{
// do what ever you want with the response.
this.label5.Text = r.ReadToEnd();
}
}
}
Finally, at the server side, we add a Generic Handler (dataGateway.ashx) and it looks like this:
<%@ WebHandler Language="C#" Class="dataGateway" %>
using System;
using System.Web;
using System.IO;
using System.Web.Script.Serialization;
public class dataGateway : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string s;
// get the contents from the request stream
Stream stream = context.Request.InputStream;
using (StreamReader r = new StreamReader(stream))
{
s = r.ReadToEnd();
}
// ensure that the content is not empty.
if (string.IsNullOrEmpty(s) || s.Length == 0)
{
context.Response.Write("'data' cannot be blank");
return;
}
// convert it from json format to our business object
JavaScriptSerializer js = new JavaScriptSerializer();
Class1 obj = js.Deserialize<Class1>(s);
// do whatever you want
context.Cache["data"] = obj;
// returns the response code/status to the caller.
context.Response.Write("ok. received the data =>" + s);
}
public bool IsReusable { get { return false; } }
}
Next, sending compressed data in WinForm:
http://laucsharp.blogspot.my/2018/04/posting-compressed-data-in-json-format.html
Thursday, April 25, 2013
Session is not missing in the Handler
I still remember the first time that I'm developing with generic handler (.ashx) and found out that the session is missing. This is because the handler implements only the basic feature (as compared to Page class).
In order for the AJAX call accessing the session information, your handler must implement the following interface:
System.Web.SessionState.IRequiresSessionState
OR
System.Web.SessionState.IReadOnlySessionState
That's all you need.
In order for the AJAX call accessing the session information, your handler must implement the following interface:
System.Web.SessionState.IRequiresSessionState
OR
System.Web.SessionState.IReadOnlySessionState
That's all you need.
Labels:
.Net,
AJAX,
ASHX,
ASP.NET,
C#,
System Design,
System Development
Friday, January 11, 2013
Handler (ashx) VS Page (aspx)
We used to do development with Page (aspx) which comes with lots of rapid application development feature such as postback handling, drag & drop support, etc. But, this becomes expensive when the application is hosted in the Internet (not in a LAN). The viewstate, the control object instance generation, etc are all come with a price. A more complicated situation is that when you try to use AJAX (ScriptManager + UpdatePanel), the performance become questionable (when traffic goes up) and the coding become very complicated.
On the other hand, Handler (ashx) is a class that provides very basic functionality as compared to Page. There is no visual designer for Handler. No viewstate. No control object generation. No postback. You have to handle everything by yourself. The advantage of Handler as compared to Page is the performance (by giving up all the rapid application development features).
With JQuery and JSON, implementing AJAX become very easy. Modifying the DOM objects at the client site become easier as well. Using JQuery AJAX call to the Handler will boost up the performance because the viewstate is no longer require to transmit back and fore between the server and the client. At the server side, it also does not requires to re-generate all the control object instances.
Try this out:
On the other hand, Handler (ashx) is a class that provides very basic functionality as compared to Page. There is no visual designer for Handler. No viewstate. No control object generation. No postback. You have to handle everything by yourself. The advantage of Handler as compared to Page is the performance (by giving up all the rapid application development features).
With JQuery and JSON, implementing AJAX become very easy. Modifying the DOM objects at the client site become easier as well. Using JQuery AJAX call to the Handler will boost up the performance because the viewstate is no longer require to transmit back and fore between the server and the client. At the server side, it also does not requires to re-generate all the control object instances.
Try this out:
- Design a data entry form in Page (aspx).
- Click on the Submit button and the client will make a AJAX call to the Handler (ashx) with the user input values.
- Then, the Handler will return the result in JSON format to the client.
- The client will then check the result and make the appropriate response.
- Faster response time
- Reduce the data to be transmitted between the server and the client.
- The server CPU load will reduce due to the Page call is lesser.
- The developer requires to more JavaScript/JQuery knowledge.
- Harder to debug.
- Because the input controls in the Page is sometimes unpredictable (in .Net 3.5), getting the input field with JQuery will become troublesome.
Labels:
.Net,
AJAX,
ASHX,
ASP.NET,
C#,
System Design,
System Development
Subscribe to:
Posts (Atom)