Compile lightweight ajax components 02 -- Analysis of AjaxPro, 02 -- ajaxpro

Source: Internet
Author: User
Tags key string

Compile lightweight ajax components 02 -- Analysis of AjaxPro, 02 -- ajaxpro

Preface

The previous article introduced some ajax implementation methods on the webform platform and implemented a base class. Here is an open-source component: ajaxpro. Although this is an old component, the Implementation ideas and source code are worth learning. Through the previous introduction, we know that the method for calling page objects is implemented by reflection. The key is the entire processing process, including reflection call methods and parameter ing. Ajaxpro not only helped us implement this process in the background, but also encapsulated the request calling method in the front. For example, ajax-related methods, the ajaxpro method can be used to send asynchronous requests, you do not need to encapsulate js by yourself or use the js library. Next, we will analyze this component.

I. Use of ajaxpro

Let's first look at how to use this component.

  1. Register AjaxHandlerFactory

Perform the following configuration in web. config:

To put it simply, the request url complies with the ajaxpro/*. ashx format and will be processed by AjaxHandlerFactory. This is a factory class that implements the IHandlerFactory interface and is used to obtain the IHandler processing program. The format of type is: "name control. Class Name, assembly name ".

  2. register the Page_Load event on the page

protected void Page_Load(object sender, EventArgs e){ AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxProPage));}

We passed the Type of the object on this Page to the ResisterTypoForAjax method. This method is used to register the script on the foreground. It will call the RegisterClientScriptBlock of the current Page object for registration. the aspx file must contain <form runat = "server"> </form>. Otherwise, the script cannot be registered. (Type is passed here, which can be passed without actually being passed. This Type can also be obtained through HttpContext. Current. Handler. GetType (). BaseType internally)

  3. Mark the method with AjaxMethod 

[AjaxMethod]public List<string> GetList(string input1,string input2){ return new List<string> { input1, input2 };}

AjaxMethod is a tag attribute, indicating that this method is used to process ajax requests and is finally executed through reflection. It has several constructor pairs and can set the cache time for some data to be cached; if the Session is not required for our request, you can set HttpSessionStateRequirement. If the request requires Asynchronization, such as requesting a time-consuming web service, you can also set the handler to asynchronous.

The Return Value of the method can be a simple type or a complex type. For example, the collection type is obtained at the front-end as an array.

  4. Foreground call

The configuration and use of the background are very simple. Next we will look at how the foreground initiates a request.

function GetList() { //var result = AjaxProNamespace.AjaxProPage.GetList("a", "b").value; //console.log(result); AjaxProNamespace.AjaxProPage.GetList("a", "b", function (result) {  console.log(result); });  }

Here, AjaxProNamespace is the namespace of the page class, AjaxProPage is the name of the page class, And GetList is the marking method. Why can I write it like this? As mentioned above, ajaxpro will register the script at the front end, which will generate the following script based on the relevant information of our page object, so we can call it like this, instead, you do not need to write js or use the jquery library method.

if(typeof AjaxProNamespace == "undefined") AjaxProNamespace={};if(typeof AjaxProNamespace.AjaxProPage_class == "undefined") AjaxProNamespace.AjaxProPage_class={};AjaxProNamespace.AjaxProPage_class = function() {};Object.extend(AjaxProNamespace.AjaxProPage_class.prototype, Object.extend(new AjaxPro.AjaxClass(), { GetList: function(input1, input2) {  return this.invoke("GetList", {"input1":input1, "input2":input2}, this.GetList.getArguments().slice(2)); }, url: '/ajaxpro/AjaxProNamespace.AjaxProPage,TestAjaxProSourceCode.ashx'}));AjaxProNamespace.AjaxProPage = new AjaxProNamespace.AjaxProPage_class();

The GetList parameter corresponds to the parameter of the background method. The type must be convertible; otherwise, the call will fail. The last parameter is the callback function. The callback function is an object that encapsulates the returned results. Its value attribute is the value returned after successful execution. For example, the returned result is an array object. Its error includes the failure information.

Note: The above comments are about Synchronous requests. This is often not what we want. I have seen such a mistake.

Ii. ajaxpro request processing principles

Here we mainly focus on the process of processing ajax requests by components. Other auxiliary functions are not described here.

 1. Generate auxiliary scripts

In the Page_Load event, we call AjaxPro. Utility. RegisterTypeForAjax (typeof (AjaxProPage) to register the required script. We noticed that the following script was introduced on the front-end page:

That is, each page will initiate these requests. These are all. files at the end of ashx are actually JavaScript code. Some of these js codes are embedded in the dll as resources, some are automatically generated, and the ajax request-related methods are encapsulated, and let's use: namespace. page class name. mark the method name to call the method. Why not use. ashx instead of. js? As the resource file inside the component, the external cannot directly request the. js file, and. ashx can be intercepted, and then the content is output using Response. Write.

If the efficiency of generating and sending these scripts each time is very low, the internal processing of ajaxpro is to judge the If-None-Math and If-Modified-Since of the request header, if the two are the same as those cached, A 304 status code is returned. Therefore, the client only requests the server for the first time to return the content of the file. In the future, only 304 is returned, indicating that the local cache is used. Refresh the page to verify the process:

 2. Request Interception

HttpHandler (IHttpHandler) and HttpModule (IHttpModule) are two important components of asp.net, so that we can easily expand them based on asp.net. HttpHandler corresponds to a specific request, such as. ashx and. aspx. HttpModule is an interceptor that intercepts all requests in an event in the pipeline. In short, HttpApplication triggers a series of events in the pipeline. We register an event through HttpModule. For example, we can intercept the request before the processing program object is generated, then it is mapped to its own processing program. HttpHandler is used to generate html for the actual result returned by processing the request, for example, Page.

Taking the asp.net mvc framework as an example, it is based on the asp.net routing mechanism. The asp.net routing system intercepts requests through a UrlRoutingModule, specifically in the PostResolveRequestCache event, parse the url, encapsulate the corresponding route data, and finally send the request to an MvcHandler for processing. MvcHandler implements the IHttpHandler interface.

We configured the following: <add verb = "POST, GET" path = "ajaxpro /*. ashx "type =" AjaxPro. ajaxHandlerFactory, AjaxPro "/> indicates any ajaxpro/any name. all Post/Get requests at the end of ashx are sent to AjaxPro. ajaxHandlerFactory is a processing factory that implements IHandlerFactory to generate a specific IHttpHandler. Multiple classes implementing IHttpHandler are defined in the component. Some classes are used to generate js scripts. ajax requests are mainly divided into two types: asynchronous (IHttpAsyncHandler) and non-asynchronous (IHttpHandler ); based on these two types, the support for Session status is divided into three types: Handler supporting read/write (implementing the IRequiresSessionState flag Interface) and read-only (implementing the IReadOnlySessionState flag Interface) and do not support Session Handler. The specific Handler generated is determined by AjaxMethod.

IHttpHandler's ProcessRequest (Asynchronous is BeginProcessRequest) is used to execute the request to return the output result. If you only need one processing program, we can also implement IHttpHandler. IHandlerFactory is defined as follows:

public interface IHttpHandlerFactory{ IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated); void ReleaseHandler(IHttpHandler handler);} 

Therefore, all requests of ajaxpro will comply with ajaxpro /*. the ashx format can be processed in the GetHandler method. The returned result is IHttpHandler. The non-asynchronous state is used as an example. If we configure the Session, A Handler implementing IHttpHandler and IRequiresSessionState is generated. If a read-only Session is required, a Handler implementing IHttpHandler and IReadOnlySessionState is generated. The information can be obtained from the AjaxMethod tag attribute through reflection. The main code of AjaxHandlerFactory is as follows:

Public IHttpHandler GetHandler (HttpContext context, string requestType, string url, string pathTranslated) {string filename = Path. getFileNameWithoutExtension (context. request. path); Type t = null; Exception typeException = null; bool isInTypesList = false; switch (requestType) {// Get request, GET the previous four scripts case "Get ": switch (filename. toLower () {case "prototype": return new EmbeddedJavaScriptHandler ("prot Otype "); case" core ": return new embedded?cripthandler (" core "); case" ms ": return new embedded=cripthandler (" ms "); case" prototype-core ": case "core-prototype": return new embedded?cripthandler ("prototype, core"); case "converter": return new converter=cripthandler (); default: return new type=cripthandler (t );} case "POST": IAjaxProcessor [] p = new IAjaxProcessor [2]; p [0] = new XmlHttpRequestProcessor (context, t); p [1] = new IFrameProcessor (context, t); for (int I = 0; I <p. length; I ++) {if (p [I]. canHandleRequest) {// obtain the AjaxMethod attribute AjaxMethodAttribute [] ma = (AjaxMethodAttribute []) p [I]. ajaxMethod. getCustomAttributes (typeof (ajaxmethodattriment), true); bool useAsync = false; HttpSessionStateRequirement sessionReq = HttpSessionStateRequirement. readWrite; if (ma. len Expiration> 0) {useAsync = ma [0]. UseAsyncProcessing; if (ma [0]. RequireSessionState! = HttpSessionStateRequirement. useDefault) sessionReq = ma [0]. requireSessionState;} // six Handler types. The session status returns the specified Handler switch (sessionReq) {case HttpSessionStateRequirement. read: if (! UseAsync) return new AjaxSyncHttpHandlerSessionReadOnly (p [I]); else return new AjaxAsyncHttpHandlerSessionReadOnly (p [I]); case HttpSessionStateRequirement. ReadWrite: if (! UseAsync) return new AjaxSyncHttpHandlerSession (p [I]); else return new AjaxAsyncHttpHandlerSession (p [I]); case HttpSessionStateRequirement. None: if (! UseAsync) return new AjaxSyncHttpHandler (p [I]); else return new AjaxAsyncHttpHandler (p [I]); default: if (! UseAsync) return new AjaxSyncHttpHandlerSession (p [I]); else return new AjaxAsyncHttpHandlerSession (p [I]) ;}} break;} return null ;}

 3. Reflection execution Method

After obtaining a Handler that processes this request, you can run the specified method in its ProcessRequest (BeginProcessRequest asynchronously. To execute a Page Object method, we must know the Assembly, namespace, name of the page class, And Method Name of the specified page. This seems to be in line with the above: namespace. Class Name. method name call method. In order to distinguish from common requests and make the components sufficiently independent, ajaxpro only intercepts requests in the "ajaxpro/*. ashx format, which means that our ajax requests must also comply with this format. For example: http: // localhost: 50712/ajaxpro/AjaxProNamespace. AjaxProPage, TestAjaxProSourceCode. ashx. This format is automatically generated by the foreground script and does not need to be constructed. Observe carefully and you will find AjaxProNamespace. ajaxProPage, TestAjaxProSourceCode is the fully qualified name of the page class: namespace. class Name and Assembly name. Through this, we can generate a specific Type and then obtain information through reflection. What about the method name? Ajaxpro puts it in the http header named X-AjaxPro-Method. With this information, you can reflect the execution method. The core code here is:

Internal void Run () {try {// set that the output result is not cached (this is not necessarily what we want) p. context. response. expires = 0; p. context. response. cache. setCacheability (System. web. httpCacheability. noCache); p. context. response. contentType = p. contentType; p. context. response. contentEncoding = System. text. encoding. UTF8; // verify the ajax request if (! P. isValidAjaxToken () {p. serializeObject (new System. security. securityException ("The AjaxPro-Token is not valid. "); return;} // method parameter object array object [] po = null; // request processing result object res = null; try {// get the parameter po = p. retreiveParameters ();} catch (Exception ex) {}// obtain the cached Key string cacheKey = p. type. fullName + "|" + p. getType (). name + "|" + p. ajaxMethod. name + "|" + p. getHashCode (); if (p. context. cache [cacheKe Y]! = Null) {// If the cache exists, directly use the cache p. context. response. addHeader ("X-" + Constant. ajaxID + "-Cache", "server"); p. context. response. write (p. context. cache [cacheKey]); return;} try {if (p. ajaxMethod. isStatic) {// call the static method try {res = p. type. invokeMember (p. ajaxMethod. name, System. reflection. bindingFlags. static | System. reflection. bindingFlags. public | System. reflection. bindingFlags. invokeMethod, null, null, Po);} catch (Exception ex) {}} else {try {// create an instance object, reflection call the instance method object c = (object) Activator. createInstance (p. type, new object [] {}); if (c! = Null) {res = p. ajaxMethod. invoke (c, po) ;}} catch (Exception ex) {}} catch (Exception ex) {}try {// judge whether the result is xml, set ContentType if (res! = Null & res. getType () = typeof (System. xml. xmlDocument) {p. context. response. contentType = "text/xml"; p. context. response. contentEncoding = System. text. encoding. UTF8; (System. xml. xmlDocument) res ). save (p. context. response. outputStream); return;} string result = null; System. text. stringBuilder sb = new System. text. stringBuilder (); try {result = p. serializeObject (res);} catch (Exception ex) {}// write the result to the cache if (p. serverCacheAttributes. length> 0) {if (p. serverCacheAttributes [0]. isCacheEnabled) {p. context. cache. add (cacheKey, result, null, DateTime. now. add (p. serverCacheAttributes [0]. cacheDuration), System. web. caching. cache. noSlidingExpiration, System. web. caching. cacheItemPriority. normal, null) ;}} catch (Exception ex ){}}

Iii. Summary

We will summarize the core processing process of ajaxpro. It intercepts the url in the specified format through an IHttpHandlerFactory, obtains the fully qualified name of the type from it to generate the type object, and then obtains the features of the TAG method through reflection, generate a custom IHttpHandler interface object. In its ProcessRequest method, obtain the method name from http headers, map parameters through reflection, and execute functions.

  Ajaxpro has the following advantages:

1. easy configuration.

2. It can be used with other components.

3. encapsulate foreground scripts. We do not need to encapsulate or use other script libraries.

4. process the returned values. We can automatically serialize the returned values of simple or complex types.

  Disadvantages:

1. Four more requests will be sent to the page. Although the 304 cache is used, a request must be sent to the server.

2. ajax cannot use Get requests. Because of the custom url format, Get requests cannot be used in this format. We know that Get requests can be cached by browsers. One of Yahoo's frontend optimization suggestions is to use get requests. In fact, we should put the namespace. Class Name and assembly in the http header, and then provide a type parameter for us to choose freely.

3. bind with <form runat = "server">. The purpose is to use the. html file +. aspx. the cs method cannot be used (this method is used for some pages in the blog Park). Even our interfaces may be used for mobile terminals. This convenience becomes a limitation.

4. reflection. In this way, the efficiency is relatively low. It does not even cache MethodInfo like our previous page class.

It can be seen that this component is worth using if you do not care much about efficiency. Here is just a core introduction, there are many other functions, this is the source code of the ajaxpro component, interested friends can study.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.