- Hands-On Network Programming with C# and .NET Core
- Sean Burns
- 688字
- 2021-06-24 16:05:30
Request execution methods
As I said before, most of these methods are designed to be leveraged asynchronously, but at least a few of them have synchronous, or blocking, counterparts. While we'll talk more about async programming later, what's important now is to note that there are two primary operations or tasks around which the WebRequest class is focused. The first is accessing the actual request data stream, and the second is accessing the response returned by the remote resource.
With a WebRequest instance, the RequestStream is .NET's representation of the open connection. Think of it as the wire over which you can transmit your signal. Anytime you want to pass data through a WebRequest instance, you'll first need to access that wire. Once you have it, you can start passing data through that stream, and trust that the WebRequest class is going to broker its transmission accordingly.
Bear in mind that writing to a stream typically requires the raw byte array for a given object (this is where serialization comes into play), so once we have our stream, writing to it isn't as simple as passing our objects or messages directly over the wire, although it's not prohibitively complicated either. In practice, however you choose to access the request stream for an active instance of WebRequest, writing to it will typically look similar to the following code block:
using System.Text;
...
// convert message to bytes
string message = "My request message";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
//write bytes to stream
Stream reqStream = req.GetRequestStream();
reqStream.Write(messageBytes, 0, messageBytes.length);
And that's all there is to it. There are some nuances with this method in some of the common sub-classes of WebRequest, but the basic principle will always apply.
That, right there, accounts for about half of the request execution methods. The BeginGetRequestStream()/EndGetRequestStream(), GetRequestStream(), and GetRequestStreamAsync() methods are three different ways of accessing the same logical component of your network transaction. They simply provide varying degrees of control over the synchronization of the operation. For example, the BeginGetRequestStream()/EndGetRequestStream() method provides an opportunity for the user to cancel the request before it has completed transmission by explicitly calling the Abort() method. Meanwhile, the GetRequestStreamAsync() method doesn't provide the opportunity to explicitly abort the operation, but it does perform the operation asynchronously. Circumstances will dictate what method or methods you should be using, but if handled correctly and resolved properly by the underlying connection, the result object is the same.
Finally, we can look at the response processing methods, and it should be no surprise to you that in the request/response pattern that is typical of most network transactions, the response handlers match, almost exactly, with the request handler method signatures. So, where the act of retrieving a request stream from the WebRequest instance was exposed through four different methods with various levels of granular control over the synchronization of the operations, so too is response processing. The methods we have available to us are BeginGetResponse()/EndGetResponse() (the processing for which cannot be interrupted by Abort(), however), GetResponseAsync(), and of course, GetResponse().
Understanding the shape of a given response will depend on the specific protocol over which it was received. Just as the WebRequest class has protocol-specific sub-classes, so too does the WebResponse base class. We'll explore each of them in their respective chapters, and look at how their responses can be handled more concretely. But for now, it is sufficient to say that the WebResponse class provides us with a reliable enough interface to meaningfully interact with whatever we get back from our request.
So, by now, you should have an extremely clear understanding of exactly what problem the WebRequest class was written to solve. You should understand its scope and the limits of its use cases, and hopefully, you will know exactly how to tune it so that you can fully leverage it for any scenario in which it could save you time and effort. With this understanding in mind, let's take a look at some of the most common ways the base class is explicitly leveraged through some of the sub-classes provided as part of the .NET Standard.