Three of the Microsoft. Net Remoting Series Tutorials: Remoting event Handling Full Contact _ self-study process

Source: Internet
Author: User
Tags soap one more line serialization wrapper port number

It's not complicated to handle events in remoting, but there are some techniques that you need to dig out. It is these techniques, as if heavily guarded, that many people are intimidated by, or are unaware of, the use of events at the end of the remoting. On this topic, there are also many discussions on the Internet, the relevant technical articles are also many, unfortunately, many articles outlined are not too comprehensive. When I studied remoting, I also took an interest in event handling. After reference to the relevant books, documents, and after repeated experiments, I am convinced that I can explain the problem clearly.

This article is no longer an introduction to the basics of remoting and events, and interested in viewing my series of articles, or consulting related technical documents.

This sample code downloads:

Remoting event (client sends fax)

Remoting event (server-side broadcast)

Remoting event (server-side broadcast improvements)

The distributed handler that applies remoting technology, usually includes three parts: remote object, server side, client. So from the direction of the event, there should be three forms:

1, server-side subscription client events
2. Client Subscription server Events
3. Client Subscription Client Events

Server-side Subscription client event, that is, the client sends a message, the server catches the message, and then responds to the event, which is equivalent to a subordinate sending a fax to the parent. In turn, the client subscribes to the server-side event, and the server sends the message, at which point all clients catch the message, firing the event, which is equivalent to a system broadcast. And what about clients subscribing to client events? It's kind of like chatting. The message is sent by a client, and the other client catches the message and fires the event. Unfortunately, I did not find a solution to the private conversation. When a client sends a message, the information is obtained whenever the event is subscribed to.

However, either way, the real thing is the remote object that really contains the event. The principle is very simple, we think about, in the remoting, the client and service side of the content is passed? There is no doubt that the remote object. Thus, the event messages we pass are naturally wrapped by remote objects. It's like EMS Express, the remote object is the car that transports the letter, and the event message is the car loaded with the letter. As for the direction of the event delivery, the role of the sender and the Subscriber has changed only.

First, server-side subscription client events

Server-side subscription client events are relatively straightforward. Let's take the example of sending a fax. First, we must have a fax machine and a file to fax, which is like our remote object. And this fax machine must have a "send" Operation button. This is like a delegate in a remote object. When a customer sends a fax, it is necessary to activate a message-sending method on the client, as we press the "Send" button. When a message is sent to the server, the event is triggered and the event is the service-side subscription. When the server obtains the event message, it then processes the related business. This is like the person receiving the fax, when the fax received, you will hear the sound of the connected, then select "Receive", the message was captured.

Now we're going to simulate this process. First define the remote object, which should handle a business that sends faxes:
The first is the public interface of the remote object (Common.dll):

public delegate void Faxeventhandler (string fax);
Public interface ifaxbusiness
{
 void SendFax (string fax);
}

Note that in the public interface assembly, a public delegate is defined.

Then we define the remote object Class (FaxBusiness.dll), which handles the fax business specifically, in which you add a reference to the common interface assembly:

public class faxbusiness:marshalbyrefobject,ifaxbusiness
{public 
 static event Faxeventhandler faxsendedevent;

 #region public

 void SendFax (string fax)
 {
 if (faxsendedevent!= null)
 {
 faxsendedevent (fax);
 }
 }

 #endregion public

 Override Object InitializeLifetimeService ()
 {return
 null;
 }
}

In this remote object, the type of the event is the delegate type that we defined in the public assembly Common.dll. SendFax implements the method in the interface ifaxbusiness. The signature of this method is consistent with the defined delegate, and it invokes the event faxsendedevent.
The special place is that the remote object we define is best to rewrite the InitializeLifetimeService () method of the MarshalByRefObject class. Returns a null value that indicates that the remote object has a lifetime of infinite size. Why rewrite the method? The truth is self-evident, if the lifecycle is not limited, the event cannot be activated once the remote object's lifecycle is over.
The next step is to implement the client and service side separately. The server side is a Windows application with the following interface:

When we load a form, we register the channel and the remote object:

private void Serverform_load (object sender, System.EventArgs e)
{
 HttpChannel channel = new HttpChannel (8080); C3/>channelservices.registerchannel (channel);

 RemotingConfiguration.RegisterWellKnownServiceType (
 typeof (Faxbusiness), "Faxbusiness.soap", Wellknownobjectmode.singleton);
 Faxbusiness.faxsendedevent + + new Faxeventhandler (onfaxsended);
}

We are using the singleton mode, registering a remote object. Look, what's the difference between this code and the General remoting server? Yes, it has one more line of code to register the event:

Faxbusiness.faxsendedevent + = new Faxeventhandler (onfaxsended);

This line of code, like our server-side fax machine, has been switched to "automatic" mode. It will always listen for fax information from the client, and once the fax message is sent from the client, respond to the event method, that is, the Onfaxsended method:

public void onfaxsended (string fax)
{
 txtfax.text = fax;
 Txtfax.text + + System.Environment.NewLine;
}

The simple way to do this is to display the fax from the client to the Txtfax text box control.

And what about the client? is still a Windows application. The code is very simple, first for the sake of simplicity, we still let it activate the remote object when the form is loaded:

private void Clientform_load (object sender, System.EventArgs e)
{
 HttpChannel channel = new HttpChannel (0);
 ChannelServices.RegisterChannel (channel);

 Faxbus = (ifaxbusiness) Activator.GetObject (typeof (Ifaxbusiness),
 "Http://localhost:8080/FaxBusiness.soap");
}

Oh, it can be said that the client-activated object method and ordinary remoting client application is not different. It's time to write a fax! We put a text box object on the form and change its multiline property to true. Another button, responsible for sending the fax:

private void Btnsend_click (object sender, System.EventArgs e)
{
 if (txtfax.text!= String.Empty)
 {
 String fax = "from" + getipaddress () + "client's Fax:"
 + System.Environment.NewLine;
 Fax + + txtfax.text;
 Faxbus.sendfax (fax);
 else
 {
 MessageBox.Show ("Please enter fax content!");
 }

private string getipaddress ()
{ 
 Iphostentry iphe = Dns.gethostbyname (Dns.gethostname ());
 Return iphe.addresslist[0]. ToString (); 
}

In this button click event, just call the remote object Faxbus SendFax () method is OK, very simple. But wait, why does your code have so many lines? In fact, nothing strange, I just think the fax customers may be a lot. In order to avoid the service personnel to be confused, do not know who sent, so asked to add their respective signatures on the fax, that is, the IP address of the client. If you want to get the IP address of your computer, be sure to add a namespace reference to DNS:
Using System.Net;

Because we strictly follow the way distributed handlers are deployed, it is only necessary to add a public assembly (Common.dll) reference to the client. On the server side, you must add a reference to both the public assembly and the remote object assembly.

OK, the procedure is complete, let's take a look at this simple fax machine:
Client:

Hey, I want to have a holiday in my dreams. OK, the fax is written, send it! Then look at the service side, great, the boss has received my leave a fax!

Second, client-side subscription server events

Hey, eat sugar cane to eat first sweet paragraph, do things I also like to do first easy. Now, the good days have passed, and it's time to suffer. Let's take a look at the implementation, and then think about how to implement the client-side subscription server event?

In the previous section, the event was placed in a remote object, and after the client activated the object, the message could be sent. On the server side, you only need to subscribe to the event. Now the idea should be reversed by the client subscribing to the event and the server sending the message. Is it that simple? Don't get too excited before. Let's think about the task of sending a message, who's going to do it? is a remote object. And when was the remote object created? We think carefully about several ways in which remoting can be activated, whether server-side activation or client-activated, and how they work: The client determines the time when a remote object instance is created, such as a method that invokes a remote object. The service side does the job of registering the remote object.

Recall the three types of activation in the service-side code:

SingleCall activation mode:

RemotingConfiguration.RegisterWellKnownServiceType (
 typeof (Broadcastobj), "Broadcastmessage.soap",
 WellKnownObjectMode.SingleCall);

Singleton activation Mode:

RemotingConfiguration.RegisterWellKnownServiceType (
 typeof (Broadcastobj), "Broadcastmessage.soap",
 Wellknownobjectmode.singleton);

Client activation mode:

Remotingconfiguration.applicationname = "Broadcastmessage.soap"
Remotingconfiguration.registeractivatedservicetype (typeof (Broadcastobj));

Please note that the register is registered. That is, creating a remote object instance that is not displayed on the server side. Without this instance, how do you broadcast messages?

Some might think, after registering a remote object, is it OK to explicitly instantiate the object? In other words, add this piece of code after registering:

Broadcastobj obj = new Broadcastobj ();

However, we need to understand the fact that the server side and the client are in two different application domains. So in remoting, the remote object that the client obtains is actually the proxy for the server-side registration object. If we manually create an instance after registering, rather than remoting an object that is automatically created after activation, then the client-acquired object and the server-side-created instance are two distinct objects. The proxy object obtained by the client does not point to the obj instance you just created. So obj sent the message that the client could not capture at all.

So, we only have exclaiming, helpless? Don't worry, don't forget. In the server registration object method, there is another method, namely Marshal method. Do you remember how Marshal was implemented?

Broadcastobj OBJ = new Broadcastobj ();
ObjRef ObjRef = Remotingservices.marshal (OBJ, "Broadcastmessage.soap");

This method is not the same as before. In the previous three ways, the remote object was created automatically based on the way the client invoked it. And what about the Marshal method? An instance of the remote object is explicitly created and then marshal into the channel to form a ObjRef to the object's proxy. This object persists as long as the life cycle is not over. The object that the client obtains at this point is the proxy for the instance of obj that was created.

OK, this problem has been solved, let's look at the concrete implementation.
Common assemblies and remote objects, similar to the previous one, are no longer redundant, with code only:
Common Assembly:

public delegate void Broadcasteventhandler (string info);

Public interface Ibroadcast
{
 event broadcasteventhandler broadcastevent;
 void Broadcastinginfo (string info);

Remote Object class:

public event Broadcasteventhandler Broadcastevent;

#region Ibroadcast member

//[oneway] public
void Broadcastinginfo (string info)
{
 if (broadcastevent!= NULL)
 {
 broadcastevent (info);
 }
}

#endregion public

Override Object InitializeLifetimeService ()
{return
 null;
}

Below, the implementation of the service side. Before I realize it, I want to say a few words. In the first section, we implemented the server-side subscription client event. Because the subscription event occurs on the server side, the event itself is not delivered. What is serialized is only the message delivered, that is, fax. Now, the direction has changed, the message is delivered by the server, and the client subscribes to the event. But this event is placed in the remote object, so the event must be serialized. In. Net Framework1.1, Microsoft has limited the level of serialization security. Serialization and deserialization of delegates and events are prohibited by default, so we should set the TypeFilterLevel property value to full enumeration value. So the way to register the channel on the server side has changed:

private void StartServer ()
{
 BinaryServerFormatterSinkProvider serverprovider = new
 BinaryServerFormatterSinkProvider ();
 Binaryclientformattersinkprovider clientprovider = new
 binaryclientformattersinkprovider ();
 Serverprovider.typefilterlevel = Typefilterlevel.full;

 IDictionary props = new Hashtable ();
 props["port"] = 8080;
 HttpChannel channel = new HttpChannel (props,clientprovider,serverprovider);
 ChannelServices.RegisterChannel (channel);

 OBJ = new Broadcastobj ();
 ObjRef ObjRef = Remotingservices.marshal (OBJ, "Broadcastmessage.soap"); 
}

Note Statement serverprovider.typefilterlevel = Typefilterlevel.full; This statement sets the level of serialization security. To use the TypeFilterLevel property, you must declare the namespace:
Using System.Runtime.Serialization.Formatters;

The following two statements are registered as remote objects. Because the Send broadcast message is placed in another window in my broadcast program, I declare the remote object as a public static object:

public static broadcastobj OBJ = null;

Then add the following in the call window event:

private void Serverform_load (object sender, System.EventArgs e)
{
 startserver ();
 LBMONITOR.ITEMS.ADD ("Server started!");

To look at the interface, first start the Service side main window:

I put a ListBox control to display some information, such as the display server started. The broadcast button is the broadcast message, and clicking the button pops up a dialog box:

Code for the Braodcast button:

private void Btnbc_click (object sender, System.EventArgs e)
{ 
 Broadcastform bcform = new Broadcastform ();
 Bcform.startposition = formstartposition.centerparent;
 Bcform.showdialog ();
}

In the dialog box, the most important is the Send button:

if (Txtinfo.text!= string. Empty)
{ 
 ServerForm.Obj.BroadCastingInfo (txtinfo.text);
}
else
{
 MessageBox.Show (Please enter information!) ");
}


But the simple thing is to invoke the sending message method of the remote object.

Now it's time to implement the client. We can refer to the previous example, just change the server to client only. In addition to the issue of serialization security levels, the code would look like this:

private void Clientform_load (object sender, System.EventArgs e)
{
 BinaryServerFormatterSinkProvider Serverprovider = new
 binaryserverformattersinkprovider ();
 Binaryclientformattersinkprovider clientprovider = new
 binaryclientformattersinkprovider ();
 Serverprovider.typefilterlevel = Typefilterlevel.full;

 IDictionary props = new Hashtable ();
 props["Port" = 0;
 HttpChannel channel = new HttpChannel (props,clientprovider,serverprovider);
 ChannelServices.RegisterChannel (channel);

 Watch = (ibroadcast) activator.getobject (
 typeof (Ibroadcast), "Http://localhost:8080/BroadCastMessage.soap"); 
 Watch. Broadcastevent + + new Broadcasteventhandler (broadcastingmessage);
}

Note the port number for the client channel should be set to 0, which means that the client automatically chooses the available port number. If you want to set the port number you specify, you must ensure that the port number is not the same as the server-side channel.
And then, the Broadcasteventhandler delegate method:

public void Broadcastingmessage (String message)
{
 Txtmessage.text = "I got it:" + message; 
 Txtmessage.text + + System.Environment.NewLine; 
}

The client interface is shown in figure:

Well, let's hope for the next run of the program. Start the server-side application first, then start the client. Oops, bad, there was an error message!

"The people of the bad things, ten lives eight or nine." "Don't be discouraged, let's analyze the cause." First look at the error message, which reports that we did not find the client assembly. In fact, however, the client assembly is certainly available. So again to debug, which step is the problem? Set breakpoints and follow-by-statement. Front registration channel All normal, when running to watch. Broadcastevent + = new Broadcasteventhandler (broadcastingmessage) statement, error occurred!

That is, the remote object was created successfully, but failed while subscribing to the event. What is the reason? Originally, the client's delegate was obtained by serialization, and when subscribing to the event, the delegate attempted to load an assembly containing the same method as the signature, that is, the assembly client in which the Broadcastingmessage method resides. However, this process of loading occurs on the server side, and there is no client assembly in the server, and there is a natural occurrence of the above exception.

The reason is clear, how to solve? First of all, the Broadcastingmessage method must be in the client, so it is inevitable that the process of entrusting the client Assembly will also have to be done on the clients. Server-side events are also captured by remote objects, so it must be a remote object event to register on the client. A requirement must be on the client, and one must be on the service side, and things appear to contradict the place.

So let's think about an example of this first. Let's say we want to swap values for x and Y, so do we? It's simple to introduce an intermediate variable.

int x=1,y=2,z;
z = x;
x = y;
y = Z;

This game is believed that everyone can play, so good, we also need to introduce such a "middle" object. This intermediate object and the original remote object have exactly the same code in terms of event handling:

public class Eventwrapper:marshalbyrefobject
{public
 event Broadcasteventhandler Localbroadcastevent;

 [OneWay] public
 void Broadcasting (String message)
 {
 localbroadcastevent (message);
 }

 public override Object InitializeLifetimeService ()
 {return
 null;
 }
}

The difference, however, is that this wrapper class must be deployed on both the client and server side, so this class should be placed in the public assembly Common.dll.

Now to modify the original client code:

Watch = (ibroadcast) activator.getobject (
 typeof (Ibroadcast), "Http://localhost:8080/BroadCastMessage.soap"); 
Watch. Broadcastevent + = new Broadcasteventhandler (broadcastingmessage);

Modified to:

Watch = (ibroadcast) activator.getobject (
 typeof (Ibroadcast), "Http://localhost:8080/BroadCastMessage.soap");
Eventwrapper wrapper = new Eventwrapper (); 
Wrapper. Localbroadcastevent + = new Broadcasteventhandler (broadcastingmessage);
Watch. Broadcastevent + = new Broadcasteventhandler (wrapper. Broadcasting);

Why would you do that? Maybe it's easy to draw a picture, but unfortunately my artistic talent is really bad and I hope I can improve on that later. Let's just say it in words.

As stated earlier, the delegate is to load the client assembly. Now we hand over the right to entrust the remote object to the Eventwrapper. Because this class object is placed on the client side, it does not matter if it is loaded with the clients assembly. Statement:

Eventwrapper wrapper = new Eventwrapper (); 
Wrapper. Localbroadcastevent + = new Broadcasteventhandler (broadcastingmessage);

Realize this function.

However, although the event was subscribed to at this time, the event was still client-side and did not relate to the server. The server-side event is placed in the remote object, so you also subscribe to the event, which is done by the remote object watch. But at this time it is no longer subscribed to the Broadcastingmessage, but the Eventwrapper trigger event method Broadcasting. The delegate also loads the assembly at this point, but at this point it is the assembly where broadcasting resides. Because the location of the loading takes place is on the service side. Well, happily, broadcasting's assembly is the common assembly (previously said, Eventwrapper should be placed in the public assembly Common.dll), and the public assembly is already deployed on both the server and client side. Naturally, there is no problem finding an assembly.

Note: Eventwrapper will still inherit the MarshalByRefObject class because you want to override the InitializeLifetimeService () method.

Now let's run the program again. Run the server first, then run the client, OK, the client form appears:

Then we click the "Broadcast" button on the server and send a broadcast message:

Click "Send" to send, and then look at the client, what will it be? Fine,i got it!

It's cool, isn't it? You can also open multiple clients at the same time, and they will all receive this broadcast message. If you think the radio is too noisy, please cancel the broadcast at the client. In the Cancle button:

private void Btncancle_click (object sender, System.EventArgs e)
{
 watch. Broadcastevent-= new Broadcasteventhandler (wrapper. Broadcasting);
 MessageBox.Show ("Cancel subscription broadcast successful!");
}

Of course this time wrapper object should be declared as private object:
Private Eventwrapper wrapper = null;

After cancellation, you try to broadcast again, congratulations, you will not hear the noise!

Third, client-side subscription client events

With the previous foundation, it is much simpler to look at client-side subscription events. And this article to write here, I am also very tired, you have been my long-winded impatient. You shout in your heart, "Spare me!" "In fact, I did not so." So I only provide a train of thought, interested friends, can write a program on their own.

In fact, the method is very simple and similar to the second case. Send the information to the client, only need to get the remote object, send the message. The client receiving the information is responsible for subscribing to the event. Because events are placed in remote objects, the method of subscribing is no different from the second.

In particular, we can replace the second one with the third. As long as you send the message to the client on the server can be. Of course need to do some extra work, interested friends can go to realize. In my example program, this method has been used to simulate the implementation of the service-side broadcast, you can go to see.

41 points Added

I used the default EventArgs in the previous event handling. If you want to define your own eventargs, it's not the same. Because the information is serialized by value, it must be added [Serializable] and must be placed in a public assembly, deployed to the server side and the client. For example:

[Serializable]
public class Broadcasteventargs:eventargs
{
 private string msg = null;
 Public Broadcasteventargs (String message)
 {
 msg = message;
 }

 public string
 : {get
 {return msg;}
 }
}

V. Continuous improvement (with beta reminders, I have improved my program and made changes to the article December 13, 2004)

Perhaps the attentive reader noticed that in my remote object class and in the Eventwrapper class, the Attribute[oneway that triggered the event method was commented out by me. I've seen a lot of information about how events are handled in remoting, and the methods that trigger events must have this attribute. What is the use of this attribute?

When an event message is sent, the subscriber of the event triggers the event and then responds to the event. But what happens when the Subscriber to the event is wrong? For example, when an event message is sent, no event subscriber is found at all, or the Subscriber to the event fails, such as a power outage, or an abnormal shutdown. At this point, the sending event party will have an exception because the correct event subscriber cannot be found. Take my program for example. When we open the server and client programs separately, the broadcast information is normal at this time. However, when we close the client, the exception occurs when the client does not unsubscribe, and the message is shown as follows:

(I don't know why, this exception is the exception that appears on the client Connection server.) This is an exceptionally easy mistake to make. )

If we open more than one client at the same time, other clients will not be able to receive broadcast information because of the error caused by this client shutdown. So let's start with the first step:

1, first consider the normal situation. In my client, although the unsubscribe operation was provided, it did not take account of the user shutting down the client. That is, the subscription to the event is not canceled when the client is closed, so we should write in the Close client form:

private void Clientform_closing (object sender, System.ComponentModel.CancelEventArgs e)
{
 watch. Broadcastevent-= new Broadcasteventhandler (wrapper. Broadcasting);
}

2, just this is not enough. If the client does not shut down properly, it causes the client to shut down because of a sudden power outage? At this point, the client has not had time to cancel the event subscription. In this case, we need to use OneWayAttribute.

As mentioned earlier, an exception occurs if the correct event subscriber is not found on one side of the sending event. In other words, this event is unreachable. Luckily, OneWayAttribute just solved the problem. In fact, from the name of this feature oneway, can also guess the meaning of it. When an event is unreachable and cannot be sent, an exception message is normally returned. If you add OneWayAttribute, the event is sent in a one-way way. If an exception occurs at this time, the system will automatically throw out the exception information. Because no exception information is returned, the sending message will assume that the message was sent successfully. The program works correctly, the wrong client is ignored, and the correct client is still able to receive broadcast information.

Therefore, the code for the remote object should be like this:

public event Broadcasteventhandler Broadcastevent;

Ibroadcast Members

public override Object InitializeLifetimeService ()
{return
 null;
}

3, the final improvement

The use of OneWay of course can solve the above problems, but not friendly enough. For the one on the radio message, like being blindfolded, is ignorant of what happens to the client. It's not a good idea. In Ingo Rammer's advanced. NET Remoting Book, Mr. Ingo proposed a better way to check the chain of trust when sending information to one side. And to catch exceptions in the traversal of the delegate chain. Displays a prompt when one of the delegates has an exception. Then continue to traverse the subsequent delegates, so that both the hint of exception information, but also ensure that other Subscribers to receive messages normally. So I modified the remote object for this example, commented out [OneWay], and modified the Broadcastinfo () method:

[OneWay] public
void Broadcastinginfo (string info)
{
 if (broadcastevent!= null)
 {
 Broadcasteventhandler tempevent = null;

 int index = 1; Log the index of the event Subscriber delegate, starting at 1 for easy identification.
 foreach (Delegate del in Broadcastevent.getinvocationlist ())
 {
 try
 {
 tempevent = (broadcasteventhandler) del;
 Tempevent (info);
 }
 Catch
 { 
 MessageBox.Show ("event subscriber" + index.) ToString () + "error occurred, the system will cancel the event subscription!");
 Broadcastevent-= tempevent;
 }
 index++
 } 
 }
 else
 {
 MessageBox.Show ("event not subscribed or subscribed to error!");
 }


Let's experiment. First open the service side, then open three clients at the same time. Broadcast message:

Messages are sent normally.

Then close one of the client Windows and broadcast the message (note that to simulate the client exception, the Clientform_closing method should be used to improve the unsubscribe code annotation in the first step.) Otherwise, no exception will occur. Are you really willing to use a power outage to cause the anomaly to happen? ^_^), as shown in figure:

The server side reported an "event Subscriber 1 Error, and the system will cancel the event subscription." Note that at this point the other two clients, like the previous one, have only two broadcast messages.

When we click on the "OK" button on the Cue box, the broadcast still sends:

Through this improvement, the program is more perfect, but also more robust and friendly!

Report:
Sample Code Description:
1, remoting event (client send fax) Compressed package: for the first section;
2, remoting event (service-side broadcast) compressed package: For the second section, the third section of the content, which:
The second section of the code is contained in:
#region Client subscriber-side events
#endregion
The third section of the code is contained in:
#region client-side subscription events
#endregion
If you want to implement the program in the second section, comment out the third section of the code, and vice versa. The example program defaults to the second section of the program.
3, run the sample program, please run the server-side program, and then run the client program. Otherwise, the "underlying connection is closed" exception is thrown.
4. The solutions are placed in the common (or Icommon) folder.

5, the improved code into the remoting event (service-side broadcast Improvement) compression package, we can compare the improvement of the program after how different!

The above is a. Net remoting in the remoting event processing of all the content, I hope to give you a reference, but also hope that we support cloud habitat community.

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.