- Hands-On Network Programming with C# and .NET Core
- Sean Burns
- 710字
- 2021-06-24 16:05:29
The constructors
WebRequest defines only two base constructors for its sub-classes. The first is the default parameter-less constructor. The second allows developers to specify an instance of the SerializationInfo and StreamingContext classes to more narrowly define the scope of valid use cases for the newly-created instance of the class. So, our constructor signatures will look like the following code block:
public WebRequest() {
...
}
public WebRequest(SerializationInfo si, StreamingContext sc) {
...
}
So far this is pretty straightforward, but why use the second constructor at all? What is so common about using SerializationInfo and StreamingContext in WebRequest instances that the base class defines a constructor which accepts instances of those classes?
We'll look more closely at streaming contexts in later chapters, but we did briefly discuss the need for reliably serialized data in the previous chapter, and this is a good place to consider the concept more fully. Every request or response payload will need to be serialized prior to transport, and deserialized upon arrival at the destination machine. As we discussed before, this is the process of taking unordered, locally-addressed chunks of data and converting it into ordered strings of zeros and ones. Specifically, it must be ordered in such a way that the same strings can be traversed in order and used to compose locally-addressed in-memory objects by the recipient machine.
So, while our software might store an ordered list of integers as an array of contiguous memory addresses, this is an implementation detail that is fundamentally independent of the data structure it represents. The only key details are that the list is ordered, and that it is a list of integers. It could just as easily be represented as a linked list under the hood, with each node in the list containing the integer stored at that node, as well as the address of the next node in the list, which may or may not be contiguous. In memory, these two data structures are significantly different:
However, as long as the proper serialization information is given for how those two lists should be represented, they should look the same to any recipient receiving those lists as the payload to a request or response over the network. They should be nothing more than a well-delimited list of the integers. If your serialization mechanism is in the typical Javascript Object-Notation (JSON) format, both of those implementations would serialize the same output:
[
int,
int,
int,
...
]
Often, you'll find that WebRequest and WebResponse instances are instantiated and leveraged over and over again for the same kinds of messages, and their payloads should be serialized in the same way each and every time. Being able to provide SerializationInfo as a constructor input gives you the flexibility to define your serialization rules and details once, and then leverage them for a theoretically infinite number of requests.
The same goes for the StreamingContext parameter. As most network software is written to facilitate the same sorts of operations that are being executed in the same way over the lifespan of the software, it's unlikely that in a given application, your requests will need to leverage different kinds of I/O streams. Later on, we'll look more closely at the different kinds of streams available to you. It's a dense topic; however, for now, just know that this input parameter gives you the same flexibility as the SerializationInfo parameter. It allows you to define your streaming context once, and use it over and over again.
And with only those two signatures, we've covered the only constructors explicitly defined by the WebRequest base class. This should give you a pretty clear idea of how the writers of this library anticipated it would likely be used. Of course, if you wanted to, you could write a sub-class that accepted HTTP verbs and default header values, and all sorts of other aspects of a given request that you will likely need to define before you can send the request. But at its most basic, these constructor signatures tell you that this is a class that is meant to provide reliable serialization of data over a reliable data stream.