Wcf4.0 -- restful WCF Services (5) (cache)

Source: Internet
Author: User

Cache is an important technology in Web development. When developing restful services, you also need to pay attention to it. The rational use of cache can greatly improve the service response capability. In terms of technical implementation, there are two major components: Client Cache and server cache. Regardless of the cache, some data is required to determine whether the cache expires. The cache rules in HTTP protocol include cache-control, etag, expires, and last-modified. Expires is an unconditional cache (controlled by expiration time). Last-modified and etag are conditional caches (controlled by the Data identifier (time or ID.

The client browser checks the expiration time of expires to determine whether to send a request. If the client cache is conditional, the server submits the last-modified-since or etag for the server to check whether the request has changed, if 304 (not modified) is returned, the system prompts that the data queried by the client has not changed. Therefore, the client needs to keep the cache. If it is a server cache, 200 (OK) is returned, but the data is read from the server cache. In addition, the cache policy is usually used for queries or get operations.

Different cache policies have different application scenarios. For WCF rest, the client cache requires additional encoding control on the client. The server cache should consider the amount of data as much as possible to cache shared data. If private data of each client is cached, it is a test for the storage space.

Here is an example of conditional Client Cache:
The server provides a gettasks method to return the task array. Adds a addtask method. Every time a task is added, _ lastmodifed (datetime) is modified)
[Servicecontract] <br/> [aspnetcompatibilityrequirements (requirementsmode = aspnetcompatibilityrequirementsmode. allowed)] <br/> [servicebehavior (instancecontextmode = instancecontextmode. percall)] <br/> public class service1 <br/>{< br/> Private Static list <task> _ tasks = NULL; <br/> Private Static datetime? _ Lastmodified = NULL; <br/> static service1 () <br/>{< br/> _ tasks = new list <task> <br/>{< br/> new task {id = "001 ", content = "task1", Title = "title1"}, <br/> new task {id = "002", content = "task2", Title = "title2 "}, <br/> new task {id = "003", content = "task3", Title = "title3" },< br/> }; <br/> _ lastmodified = datetime. utcnow; <br/>}< br/> [webget (uritemplate = "Tasks", responseformat = webmessageformat. JSON)] <br/> public list <task> gettasks () <br/> {<br/> var Req = weboperationcontext. current. incomingrequest; <br/> var resp = weboperationcontext. current. outgoingresponse; <br/> var modifiedsince = req. ifmodifiedsince; <br/> If (modifiedsince. hasvalue) <br/> req. checkconditionalretrieve (_ lastmodified. value); <br/> resp. lastmodified = _ lastmodified. value; <br/> return _ tasks; <br/>}< br/> [webinvoke (uritemplate = "newtask", method = "Post", requestformat = webmessageformat. JSON)] <br/> Public void addtask <br/> {<br/> lock (_ tasks) <br/>{< br/> task. id = (_ tasks. count + 1 ). tostring ("000"); <br/> _ tasks. add (task); <br/> _ lastmodified = datetime. utcnow; <br/>}< br/> weboperationcontext. current. outgoingresponse. statuscode = system. net. httpstatuscode. accepted; <br/>}< br/> // [webget (uritemplate = "Tasks", responseformat = webmessageformat. JSON)] <br/> // [aspnetcacheprofile ("cachefor5seconds")] <br/> // public list <task> gettasks () <br/> // {<br/> // return _ tasks; <br/>/}< br/>}< br/> public class task <br/>{< br/> Public String ID {Get; set ;} <br/> Public String title {Get; Set ;}< br/> Public String content {Get; Set ;}< br/>}
You can use the browser to call http: // localhost: 52533/service1/tasks twice in a row and use Fiddler to intercept it.
200 is returned for the first time, 304 is returned for the second time, and no response body (Hoho, so the cost of network transmission is reduced)
In the above Code:CheckconditionalretrieveMethod, and check the date according to the request's if-modified-since header. If the header exists and the resource has not been modified since the dateWebfaultexceptionAnd return the HTTP status code 304. The "query operation" (return _ tasks) after checkconditionalretrieve is not actually performed.


The above is only the result of the browser's behavior. Let's take a look at how the client simulates the call:
Tip: The WebClient has restrictions on last-modified-since. Therefore, you cannot use the WebClient. headers. Add () method to add header information. (Exception thrown)
VaR url = "http: // localhost: 20000/service1/tasks"; <br/> var Req = webrequest. create (URL) as httpwebrequest; <br/> req. method = "get"; <br/> If (! String. isnullorempty (lastmodified) <br/> req. ifmodifiedsince = datetime. parse (lastmodified); <br/> var result = ""; <br/> using (VAR resp = req. getresponse () <br/>{< br/> lastmodified = resp. headers ["last-modified"]; <br/> using (VAR sr = new system. io. streamreader (resp. getresponsestream () <br/>{< br/> result = sr. readtoend (); <br/>}< br/> var tasks = jsonconvert. deserializeobject <list <task> (result); <br/> If (tasks = NULL) return; <br/> tasks. foreach (t => console. writeline (t ));

This code retrieves the last-modified from response and adds it to the last-modified-since of the next request. If the server checks that the data has not changed () webexception (no modify) is thrown ). Obviously, this requires us to maintain such data on the client, so that we can use it when no modify is found.
This will undoubtedly increase the complexity of the client encoding. I think the exception "data has not changed" can be thrown to the UI for direct display during actual use.

Here, the concept of server cache is extended. The client wants to get a 200 (OK) response in any way. In WCF 4.0, the compatibility mode of ASP. NET services and the [aspnetcacheprofile] feature can be used. The preceding gettasks method is modified as follows:
[Webget (uritemplate = "Tasks", responseformat = webmessageformat. JSON)] <br/> [aspnetcacheprofile ("cachefor5seconds")] <br/> public list <task> gettasks () <br/> {<br/> return _ tasks; <br/>}
Cachefor5secondsAdd the following configuration in Web. config:
<System. web> <br/> <compilation DEBUG = "true" targetframework = "4.0"/> <br/> <caching> <br/> <outputcachesettings> <br/> <outputcacheprofiles> <br/> <Add name = "cachefor5seconds" Duration = "5" varybyparam = "NONE"/> <br/> </outputcacheprofiles> <br/> </outputcachesettings> <br/> </caching> <br/> </system. web>
The most important feature of cache configuration files isCachedurationAndVarybyparam. Both features are required.CachedurationSet the response time to be cached (in seconds ). UseVarybyparamYou can specify the query string parameters used to cache the response. All requests sent using different query string parameter values are cached independently. For example, for http: // myserver/myhttpservice/myoperation? After the initial request is sent, all subsequent requests sent using the same URI will return the cached response (as long as the cache duration has not ended ). Responses to similar requests in the same format but with different query string parameter values will be cached separately. If you do not need this separate cache action, setVarybyparamSet it to "NONE ".

Client:
// Obtain tasks <br/> static void gettasks () <br/> {<br/> var url = "http: // localhost: 20000/service1/tasks "; <br/> var client = new WebClient (); <br/> var result = client. downloadstring (URL); <br/> var tasks = jsonconvert. deserializeobject <list <task> (result); <br/> If (tasks = NULL) return; <br/> tasks. foreach (t => console. writeline (t); <br/> console. writeline ("------"); <br/>}< br/> // Add tasks <br/> static void addtask () <br/> {<br/> var url = "http: // localhost: 20000/service1/newtask"; <br/> var client = new WebClient (); <br/> var task = new task {id = "", Title = "title_test", content = "content_test" }; <br/> var JSON = jsonconvert. serializeobject (task); <br/> client. headers ["Content-Type"] = "application/JSON"; <br/> client. uploadstring (URL, "Post", JSON); <br/>}< br/>
To prove the effect of the server cache, I run addtask () once after one gettasks () and then gettasks () twice in a row every one second, gettasks () is performed every four seconds (). In this way, the first three queries are within five seconds after addtask (), and the last query is within 6th seconds after addtask.
Gettasks (); <br/> addtask (); <br/> thread. sleep (1000); <br/> gettasks (); <br/> thread. sleep (1000); <br/> gettasks (); <br/> thread. sleep (4000); <br/> gettasks ();
Running result:

As you can see, although addtask is successful, during the cache period, the server does not actually execute the "Return _ tasks" operation. The returned data is only cached.

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.