Elaborate form (form)-The way Ajax

Source: Internet
Author: User
Tags html form

Simple forms, simple processing methods

Well, let's go into today's topic and look at this simple HTML form below.

<form action= "Handler1.ashx" method= "POST" ><p> Customer Name: <input type= "text" name= "CustomerName" style= " width:300px "/></p><p> customer Phone: <input type=" text "name=" Customertel "style=" width:300px "/></p ><p><input type= "Submit" value= "Submission"/></p></form>

In this HTML form, I have defined two text input boxes, a submit button, and the form will be submitted to handler1.ashx for processing, and in the form of post.
Note that if we want a purely static page to be able to submit data to the server, it can be handled in this way: Point the Action property to the address that the server can handle.

Note: When we use the WebForms server form control, it is generally submitted to the page itself for processing (the Action property points to the current page), which makes it easy to use button events and access from the server control to input the results of the controls submitted from the browser.
If you want to keep the URL intact when the URL is rewritten, that is, if the action is an overridden URL, you can execute the following call in the page class:

Form.action = Request.rawurl;    Supported in the following versions: 3.5 SP1, 3.0 SP1, 2.0 SP1

OK, let's go back to that HTML form and see how the browser sends out the contents of the form if the user clicks the "Submit" button. Here, we need the assistance of Fiddler Tools, please launch the Fiddler before submitting the form. I have done the following for the submission request process for this form.

is the input to the form that will be submitted, which is the request content of the browser that was seen with fiddler.

In this image, we can see that the browser did send the request to the address I specified in the action earlier and sent it as post. The input values of the two controls of the form are placed in the request body and are "encoded", encoded in the form of a request header "Content-type", so that when the server receives the request, it knows how to read the requested content. Note: The data for the form is submitted as name1=value1&name2=value2, where name,value corresponds to the corresponding property of the form control.

We can also switch the view to the WebForms tab in Fiddler, which will make it clearer to view only the data submitted by the browser, such as.

Looking at the client's page and the content of the request, let's take a look at how to get input from a browser-submitted form on the server, the code is as follows:

String name = Context. request.form["CustomerName"];string Tel = context. request.form["Customertel"];

The code is simple enough to access Request.Form directly based on the Name property of the form control.

Back to top form submission, success control

Let's look at how the browser submits the form, or what the browser does when it submits the form.

Instead of sending all of the form controls to the server, the browser looks for all the successful controls, sending only the data from the successful controls to the service side, and what are the successful controls?
Simply put, the success control is that each control in the form should have a Name property and a "current value," which, when committed, will be name=value as part of the submission data.
For some special cases, the success control also has the following provisions:
1. The control cannot be a "disabled" state, which specifies "disabled=" disabled "". That is, the disabled control will not be a success control.
2. If a form contains multiple submit keys, then only the Commit button clicked by the user is considered a success control.
3. For a CheckBox control, only a successful control is checked by the user.
4. For radio button, only a successful control is checked by the user.
5. For the select control, all selected options are made as success controls, and name is provided by the Select control.
6. For file Upload files control, if it contains the selected file, it will be a success control.
In addition, the browser does not consider the reset button and the object element.

Attention:
1. For a CheckBox, radio button, if they are recognized as successful controls, but do not specify the Value property for the control, they will be "on" as their value when the form is submitted
2. If you cannot read the value of a form control on the server, check that it meets the above rules.

How to submit: in the previous sample code, I specified the method= "post" for the form, which determines how the browser passes the data when it submits it.
If it is "post", then the form data will be sent out in the request body.
If it is "get", then the form data is appended to the query string and submitted to the server as a query string.
Recommendation: It is usually better to submit a form as a post, so that you do not break the URL, and the URL has a length limit.

encoding of the data: I used the browser's request details as a fiddler, from which we can see that the content of the control input is not sent directly, but is processed by an encoding rule. Currently, only two encoding rules are used: application/x-www-form-urlencoded and Multipart/form-data, the use of these two rules is simply: the latter is used when uploading files, other situations use the former ( Default).
Where does this rule be specified? In fact, the form also has a Enctype property, with which you can specify the encoding rules, when I write code in VS2008, there are the following tips:

According to the coding rule selection Logic I said earlier, application/x-www-form-urlencoded is the default value, so we don't usually specify it explicitly. The enctype= "Multipart/form-data" must be set at this time unless we are uploading the file.

Well, with such a lot of theories, let's take a look at how browsing is working with form data. The process is broadly divided into 4 phases:
1. Identify all successful controls.
2. Create a data collection for all successful controls that contain value pairs such as Control-name/current-value.
3. Encode the previously prepared data according to the encoding rules specified by Form.enctype. The encoding rules will be placed in the request, indicated by "Content-type".
4. Submit the encoded data. This distinguishes post,get two cases where the submitted address is specified by the Form.action property.

Back to the top multi-submit button's form

People who have used the ASP. WebForms framework may have written this page: A page contains multiple server-side buttons. The way it works, it's simple: write the corresponding code on each button's event handler and it's done without us thinking too much.
However, for developers who do not understand the process behind this, when they go to the MVC framework, they may get stuck: There is no button event in the MVC framework! Even with the use of the MVC framework, using the ASHX Universal processor, you will encounter this problem, how to do?
For this issue, this article will stand in the HTML perspective to give two of the most fundamental solution.

Method 1: According to the "Success control" definition, we set the name of the button and use name on the server to differentiate which button is submitted:

HTML code

<form action= "Handler1.ashx" method= "POST" ><p> Customer Name: <input type= "text" name= "CustomerName" style= " width:300px "/></p><p> customer Phone: <input type=" text "name=" Customertel "style=" width:300px "/></p ><p><input type= "Submit" Name= "Btnsave" value= "save"/>    <input type= "Submit" Name= "Btnquery" value= "Query"/></p></form>

Service-Side processing code

Note: We just have to determine if the specified name exists.        if (string. IsNullOrEmpty (context. request.form["Btnsave"]) = = False) {    //Saved processing logic}if (string. IsNullOrEmpty (context. request.form["Btnquery"]) = = False) {    //query processing logic}

Method 2: I set the name of the two buttons to the same value (according to the previous success control rule, only the clicked button will be committed), on the server to determine the value, the sample code is as follows:

<form action= "Handler1.ashx" method= "POST" ><p> Customer Name: <input type= "text" name= "CustomerName" style= " width:300px "/></p><p> customer Phone: <input type=" text "name=" Customertel "style=" width:300px "/></p ><p><input type= "Submit" name= "Submit" value= "save"/> <input    type= "Submit" name= "Submit" value= " Query "/></p></form>

String action = context. request.form["Submit"];if (action = = "Save") {    //Saved processing logic}if (action = = "Query") {    //query processing logic}

Of course, there are many ways to solve this problem, and we can also modify the Form.action property before committing. For MVC, some people might choose to use the filter method to handle it. Finally choose which method, you can choose according to their preferences.
I may prefer to use Ajax directly to submit to a specific URL, which is also very intuitive, on the service side will not use these judgments. Then look down.

Back to the top upload a file form

Earlier I said "data encoding" refers to Form.enctype, which is the difference between the upload form and the normal form, see the following example code:

<form action= "Handler2.ashx" method= "post" enctype= "Multipart/form-data" ><p><input type= "text" name= "Str" value= "a string, forget it"/></p><p> the file to be uploaded 1<input type= "files" name= "File1"/></p><p> File to upload 2<input type= "file" Name= "File2"/></p><p><input type= "Submit" value= "Submit"/></p> </form>

I will upload 2 small files

Let's take a look at what the browser sends when I click the Submit button:

Notice the part that I'm using in the red border, and the content in the request body. At this time, the value of the request header Content-type changed, but also a parameter called boundary, it will tell the server: the content of the request body is separated by this token. also, each separator tag in the request body takes on a separate line, with the following content: "--" + boundary, and the end delimiter is: "--" + Boundary + "--" is also an exclusive line. From the picture we can also find that there is a piece of descriptive information before each piece of data in the request body.
This is how the content is generated, you can refer to the implementation code later in this article.

Take a look at how the uploaded files are read on the server side.

Httppostedfile file1 = context. request.files["File1"];if (file1! = null && string. IsNullOrEmpty (File1. FileName) = = False)    File1. SaveAs (context. Server.MapPath ("~/app_data/") + file1. FileName); Httppostedfile file2 = context. request.files["File2"];if (file2! = null && string. IsNullOrEmpty (file2. FileName) = = False)    file2. SaveAs (context. Server.MapPath ("~/app_data/") + file2. FileName);

Or

httpfilecollection files = context. Request.files;foreach (string key in Files. AllKeys) {    httppostedfile file = Files[key];    if (string. IsNullOrEmpty (file. FileName) = = False)        file. SaveAs (context. Server.MapPath ("~/app_data/") + file. FileName);}

Two methods, the former more can reflect the name of the control and the server read the relationship, the latter in the multi-file upload has better extensibility.

Security issues: Note that this is extremely insecure in the example code above. The correct approach should be to regenerate a random file name, and it is best to check the contents of the file, for example, if it is a picture, you can call some graphics classes of. NET to open the file and then "save" the file. In short, there is only one principle in front of security issues: do not trust the user input, must be checked or converted.

Back to the top MVC controller. Incoming parameters for multiple custom types

There is a pattern in all the previous sample code: when the server reads the data submitted by the browser, it uses the control's Name property, which is basically handled in ASP. But in MVC, MS, in order to simplify the code that reads the form data, allows us to specify directly in the controller's method in the form of an incoming parameter, and the framework automatically finds the corresponding input data based on the parameter name of the method (and, of course, more than the form data). Here's a simple example:

<form action= "/home/submit" method= "POST" ><p> Customer Name: <input type= "text" name= "name" style= "width:300px" /></p><p> Customer Phone: <input type= "Text" name= "tel" style= "width:300px"/></p><p>< Input type= "Submit" value= "Commit"/></p></form>

Signature of the method in Conntroller:

Public ActionResult submit (customer customer) {}public ActionResult Submit (String name, String tel) {}

The above two methods are OK, of course, the former will be better, but need to define a customer class beforehand, the code is as follows:

public class customer{Public    string Name {get; set;}    public string Tel {get; set;}}

If the form is simple or the business logic is simple, we may never get into trouble, and the code above works well. However, if one day we have new business requirements, we need to add some other content in this form, for example, to put the clerk's information into it together. The entity class of the salesman is defined as follows:

public class salesman{Public    string Name {get; set;}    public string Tel {get; set;}}

The controller's interface needs to be modified to:

Public ActionResult Submit (Customer customer, salesman salesman) {}

Then, how should the HTML form be written? Just like the (partial) attribute names of these two classes, it is clear that the Name,tel in the preceding form cannot correspond. At this point we can write the form as follows:

<form action= "/home/submit" method= "POST" ><p> Customer Name: <input type= "text" Name= "customer. Name "style=" width:300px "/></p><p> customer Phone: <input type=" text "Name=" customer. Tel "style=" width:300px "/></p><p> Salesperson Name: <input type=" text "Name=" salesman. Name "style=" width:300px "/></p><p> Salesperson Tel: <input type=" text "Name=" salesman. Tel "style=" width:300px "/></p><p><input type=" Submit "value="/></p></form>

Note The parameter names in the Controller method are related to name in the HTML form.

Back to top F5 refresh problem is not WebForms's fault

Just talked about the MVC framework, and then the WebForms framework. I used to hear some people complaining about the F5 of a WebForms form with a duplicate commit problem. Here I would like to say a fair sentence for WebForms: This problem is not webforms itself, is a browser problem, but if you have been using the webforms of the more traditional usage, it is easy to produce this phenomenon. So what is called "traditional usage"? Here I will give a definition of myself: the traditional usage of the so-called WebForms is to say: Your page has been using the server control submission method (postback), after the event processing, the page again into the recurrence process, or that the current page has been using the Post method to submit to the current page.

So how to avoid this problem? There are roughly 2 ways of doing this:

1. PRG mode (post-redirect-get), after the event processing, call the redirect Operation Response.Redirect (), and do not go to the end of event processing to give some server control bound data Items!
Recommendation: Button events do only a few commit data processing, and data-bound operations are handled in the OnPreRender method rather than written in each event (everywhere). However, in this way, perhaps the great viewstate will not play a big role, if you find that viewstate useless, in Web. config in the global shutdown, and found that many of the Advanced Server control events are not available! Well, the cup has AH.
This topic goes on and on and on and on, but don't think this method is going backwards.

2. Submit your form in Ajax, and continue reading this article.

Go back to the top and submit the entire form in an AJAX way

The front has been saying "browser Submission form", in fact, we can also use JavaScript to submit forms, there are many benefits, such as the previous F5 refresh problem. The larger advantage of submitting a form in Ajax is that it is asynchronous, and it can also implement partial refreshes, which are not available in the browser submission mode. Before I mentioned the form in the submission, the browser to implement the 4 steps, basically using JS to complete this operation is the same. However, the previous steps seem like a lot of trouble, is there a simple way to implement this process? Well, yes, I'll use jquery and jquery.form.js this plugin to demonstrate the simple handling of this complex process.

The HTML form for the example or the code I used earlier does not need to be modified at all:

<form action= "Handler1.ashx" method= "POST" ><p> Customer Name: <input type= "text" name= "CustomerName" style= " width:300px "/></p><p> customer Phone: <input type=" text "name=" Customertel "style=" width:300px "/></p ><p><input type= "Submit" value= "Submission"/></p></form>

The JS code is as follows:

$ (function () {    $ (' form '). Ajaxform ({        success:function (responsetext) {            alert (responsetext);});}    );

Yes, it's that simple, just call Ajaxform (). You can also pass in any parameters that $.ajax () can accept.
It does this by modifying the way the form is submitted and then submitting it as an Ajax method. Finally, when the user clicks on the "Submit" button , it is no longer the browser's commit behavior, but is submitted using AJAX, the submitted URL and the submission method is the parameter specified in the form.

If you want users to be able to submit a form (without the submit button) when they click on a button or link, you can use the following method:

$ (function () {    $ ("#btnId"). Click (function () {        $ (' form '). Ajaxsubmit ({            success:function (responsetext) {                alert (responsetext);});});    

Change is very small, just need to change ajaxform to Ajaxsubmit on OK. Unlike Ajaxform (), calling the Ajaxsubmit () method submits the form immediately.

Go back to the top and submit some forms in AJAX form

In the previous example, we saw that submitting a form in Ajax is very easy, and it completely simulates the behavior of the browser. However, sometimes we may need to submit only part of the form for better partial updates, so how do we do that?
If I have a part of the following form, I only want to submit it to the server when the user has a button:

<div id= "Divcustomerinfo" ><p> Customer Name: <input type= "text" name= "CustomerName" style= "width:300px"/> </p><p> Customer Phone: <input type= "text" name= "Customertel" style= "width:300px"/></p></div>

We can submit the data for this part of the form:

$ ("#btnId"). Click (function () {    $.ajax ({        URL: "Handler1.ashx", type: "POST",        Data: $ (' #divCustomerInfo: Text '). Fieldserialize (),        success:function (responsetext) {            alert (responsetext);        }    });    return false;});

Note the key line of code: Data: $ (' #divCustomerInfo: Text '). Fieldserialize ()
Note: Instead of using the filter logic of a successful control, you will be specifying a jquery selector to filter the controls to be submitted.

Alternatively, you can use the method that is described below, still using data: {}, but you need to specify the members manually.

Back to the top using jquery, don't spell the URL again!

jquery is becoming so popular that when it comes to creating an MVC project, the VS IDE will also be ready for jquery, and Ms May think that developing a Web project is inseparable from jquery.
Indeed, jquery is very handy, especially when it comes to working with the DOM, but it's also very handy when it comes to Ajax requests.

However, there is one thing that makes me wonder: often see someone in using jquery to implement Ajax, put a bunch of parameters in the URL to pass, of course, send GET request, this is good, but, let me puzzled is: The URL is stitched up, and the code is smelly and long!

If it's a simple argument: "aaa.aspx?id=" + Xxid, that's it. But when a bunch of parameters are stitched together, it may be impossible to see exactly how many parameters there are. and experienced developers will find that this sometimes can be garbled problem, may search after the Internet, know that there are coding work to deal with, so added a bunch of coding methods. So far, this code will make people look tired!

If you do this usually, then I will tell you today: Do not splice the URL! $.ajax () parameter is not a data member, use it. Look at the code:

$.ajax ({    URL: "Handler1.ashx", type: "POST",    data: {id:2, Name: "AAA", Tel: "[email protected]#$%^&* () _+-=& Lt;>?| ", xxxx:" How much more can be written ", Encoding:" Hell to go.?&:) "},    success:function (responsetext) {        $ (" #divResult ") . html (responsetext);    }});

What do you mean, you can only use Get? Well, then change the type parameter.

$.ajax ({    URL: "Handler1.ashx", type: "GET",    data: {id:2, Name: "AAA", Tel: "[email protected]#$%^&* () _+-=&L T;>?| ", xxxx:" How much more can be written ", Encoding:" Hell to go. "?&:)"},    success:function (responsetext) {        $ ("#divResult"). HTML (responsetext);    }});

Looking at this example, will you continue to spell the URL?

Description: In order to make the layout simple, I put the parameters on one line, it is suggested that the actual use, do not squeeze in a row.

Back to the top ID, what does name matter

Usually when we write HTML code, we give the control an ID attribute, which is used only by JS and CSS, and it has no effect when the form is submitted.

In the example code above, it is possible that the individual value in data {} is derived from each of the different controls, so specifying the appropriate ID property for those controls will make it easy to find them.
However, if you do not need to use JS and CSS control, perhaps they are only used to display some data (read-only), then there is no need to specify the id attribute, of course, the Name property can also not be given (to avoid committing meaningless data).

Back to top submit a form using the C # simulation browser

The browser is also a common application, and the. NET Framework also provides classes that allow us to initiate HTTP requests directly. Today I will use C # again to emulate the browser's submission request, as well as to deepen my understanding of the HTTP request.

The sample code is divided into two paragraphs, a demonstration of the use of Application/x-www-form-urlencoded encoding method of submission, the other section demonstrates the use of Multipart/form-data encoding.
In order for everyone to use this code again, I have written the key part in an independent way, hoping that you will be able to use it immediately when you need it. The code is as follows:

1. application/x-www-form-urlencoded

<summary>///initiates a POST request to the specified URL address and can upload some data items. </summary>///<param name= "url" > URL address to request </param>///<param name= "keyvalues" > Data item to be uploaded </param>///<param name= "encoding" > Send, received character encoding </param>///<returns> server return result </returns >static string sendhttprequestpost (string url, dictionary<string, string> keyvalues, Encoding Encoding) {if (s Tring.        IsNullOrEmpty (URL)) throw new ArgumentNullException ("url");    string postdata = null; Convert data items into name1=value1&name2=value2 form if (keyvalues! = null && keyvalues. Count > 0) {postdata = string. Join ("&", (from KVP in KeyValues-let item = KVP. Key + "=" + Httputility.urlencode (kvp. Value, select item).    ToArray ());    } if (encoding = = null) encoding = ENCODING.UTF8;    HttpWebRequest request = (HttpWebRequest) webrequest.create (URL); Request. Method = "POST";                Request. ContentType = "application/x-www-form-urlencoded; charset= "+ Encoding.        WebName; if (postdata! = null) {byte[] buffer = encoding.        GetBytes (PostData); Stream stream = Request.        GetRequestStream (); Stream. Write (buffer, 0, buffer.        Length); Stream.    Close (); } using (WebResponse response = Request. GetResponse ()) {using (StreamReader reader = new StreamReader (response. GetResponseStream (), encoding) {return reader.        ReadToEnd (); The sample code for the above method is called by}}//string Test_sendhttprequestpost () {String url = "Http://localhost:1272/FormWebSite1/Handler1.ashx"    ;    dictionary<string, string> keyvalues = new dictionary<string, string> (); KeyValues.    ADD ("CustomerName", "I am Li Chipheng,$%@+& #^/"); KeyValues.    ADD ("Customertel", "1381723505x"); Return sendhttprequestpost (URL, keyvalues, null);}

2. Multipart/form-data . Note that this part of the code is a bit complicated, so I added a lot of comments.

<summary>///initiates a POST request to the specified URL address, and can upload some data items and upload files. </summary>///<param name= "url" > URL address to request </param>///<param name= "keyvalues" > Data item to be uploaded </param>///<param name= "fileList" > List of files to be uploaded </param>///<param name= "encoding" > Send data Items, The received character encoding </param>///<returns> server returns the result </returns>static string sendhttprequestpost (string URL, Dictionary<string, string> keyvalues, dictionary<string, string> fileList, Encoding Encoding) {if (filel    ist = = null) return Sendhttprequestpost (URL, keyvalues, encoding); if (string.            IsNullOrEmpty (URL)) throw new ArgumentNullException ("url");    if (encoding = = null) encoding = ENCODING.UTF8;    HttpWebRequest request = (HttpWebRequest) webrequest.create (URL); Request.        Method = "POST";    To upload a file, it must be the Post method//data block separator tag, used to set the request header, note: This place is best not to use Chinese characters. string boundary = "---------------------------" + guid.newguid ().    ToString ("N"); Delimited tag of the data block,Used to write to the request body.    Note: There are a few more previous: "--", and they will be exclusive.    byte[] Boundarybytes = Encoding.ASCII.GetBytes ("\r\n--" + boundary + "\ r \ n"); Sets the request header.    The indicator is an upload form, and a separator tag for each block of data. Request. ContentType = "Multipart/form-data;        boundary= "+ boundary;    Get the request stream first and prepare to write the data. Stream stream = Request.    GetRequestStream (); if (keyvalues! = null && keyvalues.            Count > 0) {//write keyvalues portion of non-file foreach (keyvaluepair<string, string> kvp in KeyValues) { Writes the delimited tag stream of the data block.            Write (boundarybytes, 0, boundarybytes.length); Writes the data item description, where the value section can be encoded without a URL string str = string. Format ("Content-disposition:form-data; Name=\ "{0}\" \r\n\r\n{1} ", kvp. Key, kvp.            Value); byte[] data = encoding.            GetBytes (str); Stream. Write (data, 0, data.        Length); }}//write to the file to be uploaded foreach (keyvaluepair<string, string> kvp in fileList) {//write data block delimited tags Strea M.write (boundarybyteS, 0, boundarybytes.length);        Write a description of the file, set here a generic type description: Application/octet-stream, the specific description in the registration table has. String description = String. Format ("Content-disposition:form-data; Name=\ "{0}\"; Filename=\ "{1}\" \ r \ n "+" content-type:application/octet-stream\r\n\r\n ", kvp. Key, Path.getfilename (kvp.        Value));        Note: If you do not use UTF-8 here, there will be garbled characters for kanji.        Byte[] Header = Encoding.UTF8.GetBytes (description); Stream. Write (header, 0, header.        Length); Write file contents byte[] Body = file.readallbytes (kvp.        Value); Stream. Write (body, 0, body.    Length);    }//write end tag boundarybytes = Encoding.ASCII.GetBytes ("\r\n--" + boundary + "--\r\n"); Stream.    Write (boundarybytes, 0, boundarybytes.length); Stream.    Close ();    Initiates the request and obtains the results returned by the server. using (WebResponse response = Request. GetResponse ()) {using (StreamReader reader = new StreamReader (response. GetResponseStream (), encoding) {return reader.        ReadToEnd ();  }  }}//calls the example code of the above method string Test_sendhttprequestpost2 () {String url = "Http://localhost:1272/FormWebSite1/Handler2.ashx";    dictionary<string, string> keyvalues = new dictionary<string, string> (); KeyValues.    ADD ("Key1", "This sample code is provided by Fish Li"); KeyValues.    ADD ("Key2", "Http://www.cnblogs.com/fish-li"); KeyValues. ADD ("Key3", "come to a few special characters: [email protected]#$%^&* ()-=_+{}[]:; '        \ "<>?/.,|\\");    dictionary<string, string> fileList = new dictionary<string, string> ();    Filelist.add ("File1", @ "H:\AllTempFiles\ascx in text. gif");    Filelist.add ("File2", @ "H:\AllTempFiles\asax in text. gif"); Return sendhttprequestpost (URL, keyvalues, fileList, Encoding.UTF8);}

Elaborate form (form)-The way Ajax

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.