Document directory
- Send binary data objects to client programs
- Control Message Size
- Start the stream mode in the WCF Service and client program
- Security considerations after starting the stream mode
Enabling MTOM to transmit data MTOM is a mechanism used to transmit large binary attachments containing SOAP messages in the form of raw bytes, so that the transmitted messages are smaller. A soap message is often composed of a message header and a message body. The message header provides the address, route information, and security information. The message body provides data and load of the message. The message body is composed of XML, which is contained in the request sent to the service or the response information of the returned client program. The actual structure of message body information is specified by the WSDL description of the operation. These operations are derived from the operation contract you specified in the service. For example, the ProductService service you created in chapter 1 of this book defines the ChangeStockLevel operation in the IProductsService service contract: when the client program calls the ChangeStockLevel operation, the following message is created during the WCF operation: you can see that the message body contains the parameters required for the operation. These parameters are encoded as XML Information sets. This data structure makes parameters appear in a very intuitive way. However, remember that when an XML message is transmitted over the network, it is converted into a series of text characters rather than text data. For example, the <newStockLevel> and <bin> elements in the preceding example must be converted to text when sent by the client and a number when received by the Service. This conversion increases system overhead in two aspects: 1. Converting integers in binary format to text and converting texts back to Integers consumes time, memory, and computing power. 2. After the data is converted to text, it may not have a simplified original data type when it is transmitted over the network. A larger value of the original data requires more text characters after being converted to text. In the above example, the added system overhead is weak. However, how do you process binary data, such as an image data. One possible solution is to convert the binary format to a text format that only contains the corresponding 0 and 1 characters. However, considering the system overhead added by this method. Converting 1 MB of binary data will contain a string of 1 million characters, which requires a large amount of memory and time. What happens if WCF converts binary data to a base64-encoded string instead of a string text consisting of 0 and 1? The result is a Base64 encoded string, which simplifies text data. However, on average, the Base64 encoding mechanism increases the string length by 40% than the original string length. In addition, the recipient must transfer the original data type after receiving the data. Obviously, when we need to transmit large binary data messages, we need to find another solution. The MTOM specification is another solution. When you use MTOM to transmit messages that contain binary data, the binary data is not encoded as text, but as an attachment and is understood by both parties as MIME (multi-function Internet Mail extended specifications) the specified format is transmitted to the receiver. All text information in the original message is encoded as an XML Information set, but the binary information is referenced as a MIME attachment. Demonstrate how MTOM encodes binary data:
As usual, security considerations must also be taken into account when MTOM is required. When MTOM-encoded messages are signed, the signature calculated by WCF contains all MIME attachments of the message. If any part of the message, including MIME attachments, changes during sending and receiving, the message signature will become invalid. For more information about signatures, refer to Chapter 4 "protecting internal enterprise WCF services ". In WCF, MTOM is processed by a specific encoding channel. If you use standard HTTP binding (basicHttpBinding, wsDualHttpBinding, wsFederationHttpBinding, or ws2007HttpBinding), you can change the message encoding attribute to MTOM in message encoding configuration. Other transmission protocols, such as TCP, MSMQ, and named pipes, use their own binary encoding by default. Their corresponding standard bindings do not have the MessageEncoding attribute, however, if you want to enable MTOM-encoded messages on these bindings, you must create a custom binding. To send binary data objects to a client, consider the following scenario: AdventureWorks wants to extend the WCF Service ShoppingCartService so that users can view the company's product images. Product images are stored in the database in binary format. The developer has created the ShoppingCartPhotoService service prototype, which provides the GetPhoto operation, which retrieves images from the database and returns the images to the client program. In the following exercise, you will check the project and learn how to configure the Service to use MTOM to encode messages. Exercise: Check ShoppingCartPhotoService1. start Visual Studio and open the MTOMService solution under the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 \ MTOM folder. This solution contains a service prototype named ShoppingCartPhotoService, which implements the GetPhoto operation and is provided by the ASP. NET development Web server. The solution also contains a simple WPF client program. 2. Open the IShoppingCartPhotoService. cs file under the App_Code folder in the C: \... \ MTOMService project. Check the IShoppingCartPhotoService interface that defines the service contract. This interface contains the GetPhoto operation, which allows the client program to send a product code to request a product image. After obtaining the image, the service returns the image to the client as a return parameter. Because images are stored in the database in binary format, the type of returned parameters is byte []. Finally, the return value of this operation is bool to specify whether the operation succeeds or fails. 3. Check the ShoppingCartPhotoService. cs file in the App_Code folder. You can see how the service implementation class implements the GetPhoto method. This method does not contain any WCF-related things. It executes a LINQ query through the ProductsPhotoModel object, and obtains the image of the corresponding product from the ProductPhoto table of the database based on the specified product code; finally, this query returns a ProductPhoto object. The image information is saved in the LargePhoto column of the ProductPhoto table. The data type of this column is varbinary. The Entity Framework obtains the varbinary data and fills it with the LargePhoto attribute of the PruductPhoto returned object in the LINQ query (the data type of this attribute is byte []). The value of the LargePhoto attribute of this object is assigned to the output parameter photo. If a product is found in the database and an image is obtained, true is returned for this method. If an exception occurs, false is returned. 4. Open the ClientWindow. xaml file in the ShoppingCartGUIClient program. The XAML file defines a WPF window, which contains an image control that occupies most of the window. The window also contains a text tag, a text input box, and a button control. You can enter the product code in the text box and click the button to obtain the product image. 5. Open the ClientWindows. xaml. cs file. You can see that when you click the get image button, the getPhoto_Click method is run. The preceding method creates a client proxy instance, reads the product code entered by the user, creates a new byte array, and calls the GetPhoto operation, and pass the byte array and product code as parameters to the operation. If true is returned, the method uses the byte array containing the product image to fill in the BitmapImage object, which is responsible for displaying the product image. 6. Run the solution in non-adaptive mode. ShoppingCartPhotoService starts ASP. NET to develop the Web server and listens for client requests on port 9080. When the ShoppingCartGUI client window appears, enter the WB-H098 in the product number text box, and then click the get photo button. A photo containing two water bottles is displayed. 7. Close the ShoppingCartGUI client window and return to Visual Studio. 8. C: \... \ MTOMService project, select web. config, right-click, and select use the WCF Service configuration management tool. This will start the WCF Service configuration management tool to edit the web. config file. 9. On the configuration panel, click the diagnosis folder. On the diagnosis panel, click Start message log. 10. On the configuration panel, click the Message Log node in the diagnostic folder. On the Message Log panel, set the LogEntireMessage attribute to true. 11. In the configuration panel, expand the listener folder and click the ServiceModelMessageLoggingListener node. In the right pane, set the InitData attribute to web_messages.svclog. The file is located in the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 \ folder. 12. On the configuration panel, expand the source node in the diagnostic folder and click ServiceModelMessageLogging. On the right panel, set the tracing level to Verbose (detailed output information is provided ). 13. In the configuration panel, expand the diagnostic folder again. On the diagnosis panel, click Start tracing. With this option, you can capture the behavior information generated during the WCF runtime to send and receive messages. 14. On the configuration panel, click the ServiceModelTraceListener node under the listener folder. In the right pane, set the InitData attribute to web_trace.svclog. The file is located in the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 \ folder. 15. On the configuration panel, click System. ServiceModel node in the source folder. On the right panel, set the tracing Level Attribute to Verbose. 16. Save the configuration file. 17. Return to Visual Studio and run the solution in non-debug mode. In the ShoppingCartGUI client, enter the WB-H098 and PU-M044 in the product code text box, and you will get two pictures of the product. Then close the client program and stop ASP. NET Web development server. 18. Start the service tracing viewer. In the service tracing viewer, open web_messages.svclog19 in the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 \ Folder. In the right pane, click the message tag. You will see four messages listed: Two request messages and two response messages (because the ShoppingCartPhotoService service configuration is practical basicHttpBinding binding, no additional messages are produced; for example, a security credential or a message that establishes a reliable message session ). 20. Click the first message. In the lower right pane, click the message tag and scroll to the bottom of the message. You will see a product image of the message requesting product WB-H098. 21. On the left panel, click the second message. In the lower right pane, click the "message" tab. This is a response message that includes the image data in the <photo> element. You can see that the data contains a long string, which is base64-encoded binary data. Check the remaining messages, the third message requests the product image of the product PU-M044, and the fourth response message contains Base64 encoded image data. 22. Open the web-tracelog.svclog file under the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 \ folder. Click the "activity" tab in the left-side navigation pane. The first file contains a log generated during the WCF runtime, and the activity panel displays a series of tasks executed by the server-side WCF runtime. 23. find and click the first activity named "Process action 'HTTP: // adventure-works.com/2010/07/01/ShoppingCartPhotoService/GetPhoto'". The upper-right panel displays the task executed by the activity, which includes receiving messages from the channel, open the service instance, execute the operation, create a response message, and close the service instance. 24. In the upper right panel, scroll down the task list and select "A Message was written ". The lower right panel displays information about the message. In the header of the message attribute, note that the attribute value of the encoder is text/xml and charset = UTF-8. This indicates that the message uses text encoding: 25. In the service tracing viewer menu, click a file and close all files. The above exercise demonstrates that, by default, all messages sent by ShoppingCartPhotoService, including messages containing a large amount of binary data, are encoded and transmitted in text. For messages containing binary images, MTOM encoding is more effective for messages containing images in ShoppingCartPhotoService. In the following exercise, you will learn how to modify the binding configuration of ShoppingCartService to use MTOM to encode binary data, and then use HTTP to transmit the encoded data from the server to the client. Exercise: Configure ShoppingCartPhotoService to start MTOM1. return to the WCF Service configuration editor. The editor displays the web. config file of ShoppingCartPhotoService 2. On the left-side pane, click bind folder. On the binding panel, click Create new binding configuration. Add a new binding configuration for basicHttpBinding. The bound name is ShoppingCartPhotoServiceBasicHttpBindingConfig and the MessageEnconding attribute value is Mtom. 3. On the configuration panel, expand ShoppingCartPhotoService. ShoppingCartPhotoServiceImpl node under the service folder, expand the endpoint folder, and click "untitled service endpoint. On the service endpoint panel, set the BindingConfiguration attribute to ShoppingCartPhotoServiceBasicHttpBindingConfig. 4. Save the configuration file and close the WCF Service configuration editor. 5. In Visual Studio, use the WCF Service configuration editor to open the app. config file under the ShoppingCartGUIClient project. 6. In the configuration panel, expand the binding folder, and then click BasicHttpBinding_ShoppingCartPhotoService to bind the configuration. The client endpoint uses the binding configuration. This binding configuration is automatically generated when you use the add service wizard. 7. On the right panel, set the MessageEncoding attribute bound to BasicHttpBinding_ShoppingCartPhotoService to Mtom to match the configuration bound to the service. 8. Save the configuration file. 9. Use the Windows file browser to delete the web_messages.svclog and web_tracelog.svclog files under the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 folder. 10. Return to Visual Studio and run the solution in non-adaptive mode. Enter the product number WB-H098 and PU-M044, respectively, and confirm that the images for these two products are displayed in the client window. Then close the client program and stop ASP. NET development Web server. 11. Open the web_tracelog.svclog file in the WCF Service tracing viewer. On the activity tab, locate and select "Process Action 'HTTP: // adventure-works.com/2010/07/01/ShoppingCartPhotoService/GetPhoto '". In the upper right pane, find and click Task "A message was written ". In the lower right panel, check the Encoder attribute of the header area of the message attribute. The attribute value of this encoder is multipart/related; type = 'application/xop + xml '. This indicates that the Service uses the MTOM-encoded MIME message to transmit data. 12. Disable the WCF Service tracing viewer. Controlling the Message Size you have seen that configuring binding with MTOM encoding is a simple task. Enabling MTOM does not affect the function of your program, and you do not have to write any special encoding to change the binding to use MTOM encoding. However, you should note that the environment using MTOM is a very suitable environment for using MTOM encoding. Services that send and receive messages containing big binary data are prone to DOS attacks. If a service enables MTOM, attackers may try to send some very large messages to try to make the service "Traffic Jam ". Similarly, a malicious service may return a large number of response messages to client requests in an attempt to interrupt user computers. Therefore, you can limit the size of messages that can be received by clients and services during the running of WCF. In the following exercise, you will check what happens when you try to accept data that exceeds the size allowed by the WCF runtime, and learn how to configure binding to support large messages. Exercise: receive big messages on the client 1. Run the solution in non-adaptive mode in Visual Studio. In the ShoppingCartClientGUI program, enter the BK-M38S-46 in the product code, and then click the Get Photo button. The ShoppingCartClientGUI program displays the following exception message dialog box: the cause of the exception is that by default, only 16384 bytes (16 KB) of the array in the message are allowed during the running of WCF ). In the AdventureWorks database, the picture size of Mountain-400-W bicycle products exceeds 16 kb. The service is allowed to send data during the running of WCF (the data that the service can send is not restricted), but the client program is prevented from receiving the data. 2. In the message dialog box, click OK and close the ShoppingCartGUI client window. 3. Return to the WCF Service configuration editor and open app. config under the ShoppingCartGUIClient project. In the control panel, click "BasicHttpBinding_ShoppingCartPhotoService" under the BIND folder to bind. 4. Scroll down the content in the binding area on the right panel and find the ReaderQuota attribute. Note that the current value is 16384. 32768. The result of the change is that the maximum number of arrays contained in messages that can be received by the client is 32 KB during the WCF runtime. Save the configuration file and exit the WCF Service configuration editor. 5. Run the solution again in non-debug mode. Enter the BK-M38S-46 at the product encoding of the client program. The product image will be displayed successfully. 6. Close the client program window. In addition to the MaxArrayLength attribute, the ReaderQuotas element also includes the attributes associated with all bindings: MaxBytesPerRead, MaxDepth, MaxNameTableCharCount, and MaxStringContentLength. These attributes determine the complexity before the WCF runtime processes a message and throws an exception. The data contained in the message body is an XML document. Internally, the XmlDictionaryReader object is used during the WCF runtime to convert the content of the message body and split the content into appropriate data, then return the data to the service or client program with the expected value. Use the ReaderQuota attribute to configure the XmlDictionaryReader object and limit the size and structure of messages that can be processed by the object. The MaxBytesPerRead attribute specifies the number of bytes of data that can be read from the message at a time when XmlDictionaryReader processes the message. The MaxDeptch attribute specifies the maximum depth of element nodes in a message. The MaxNameTableCharCount attribute limits the total number of characters in the atomic string in the NameTable of XmlDictionaryReader. (When the atomic string is used, the string is inserted into the NameTable and will never be removed. This causes a large amount of character data to be accumulated in NameTable. Therefore, you must set a limit on the amount of data that can be buffered in the NameTable of XmlDictionaryReader ). MaxStringContentLength limits the length of the string created and returned by various APIs. If you set these attributes to 0, XmlDictionaryReader uses their default values. In the ReaderQuotas attribute, you are most likely to modify the MaxArrayLenght attribute and MaxStringContentLenght attribute, because these two attributes are directly related to the size of the data contained in the sent message. However, this is not over yet. A message may contain multiple arrays or strings. The attribute of ReaderQuotas only limits the size of a single element, rather than the size of all elements in a message. Therefore, DOS attacks may still occur. If you check a binding configuration in the WCF Service configuration editor, you will find that the binding has a maxcompute edmessagesize attribute, which manages the total size of messages that can be received. Note that the value of this attribute is included in the header of the SOAP message or other management information (if the Helper does not use SOAP ). The default size of this attribute is 65536 bytes (65Kb), which is sufficient for most cases, but you can increase the value if necessary. You can set the maximum value to 2,147,483,647 (the maximum value of Int32 ). If there are not enough reasons, do not change the maximum value. Instead, make sure that the value is at least greater than MaxArrayLength and MaxStringContentLength. If the value to be modified is small, the value to be modified will break the restrictions set by the ReaderQuotas attribute. Another attribute, MaxBufferSize, is worth noting. When a message is transmitted, it is transmitted in byte streams over the network. When a message is received, the stream must be reorganized as a message. The memory buffer is used to complete the task during the running of WCF. The maximum cache allocated by the memory is determined by the MaxBufferSize attribute. In most cases, MaxBufferSize and maxcompute edmessagesize are the same. However, when you use stream mode, the size of the MexBufferSize will be significantly reduced. In the WCF Service, enabling the stream mode to transmit Big Data MTOM is very useful for encoding large binary data objects in messages, but if these objects become very large, they consume a considerable amount of memory on the computers that host the WCF Service and the computers that receive the message client. In addition, it takes a long time to create and transmit huge messages, and the client may time out while waiting for a response message containing a large binary object. In most cases, it is meaningless to package data into a single message. Assume that a WCF Service outputs audio and video data. In this case, data is transmitted by using only one "big data block (all data is placed in a tag of the same message, it is more effective to start the stream mode to send and receive data. Stream mode allows the client program to receive and process data before the service transmits a complete message, so that the service and client do not need a large cache to accommodate the entire message, the timeout problem is also solved. To enable stream mode in the WCF Service and client programs, you only need to modify the TransferMode attribute of the binding configuration based on basicHttpBinding, netTcpBinding, and netNamedPipeBinding. You can set the value of this attribute:
- Buffered, which is the default value of the TransferMode attribute. After the entire message is created in the memory, transmission starts.
- StreamedRequest, which sends request messages in stream mode and receives and returns responses in buffer mode.
- StreamedResponse sends and receives requests in a buffer mode, but returns a response in streaming mode.
- Streamed. Both Directions use stream mode to send/receive requests/responses.
After the stream mode is enabled, the maximum value of the received message is determined by the bound maxcompute edmessagesize attribute. However, after you bind the stream-starting mode, only the message header needs to be buffered in the receiver. Therefore, you should reduce the value of the MaxBufferSize attribute. Design operations to support stream mode
If you enable stream mode, in addition to changing the value of the TransferMode attribute, there is more work, and not all operations can use the stream mode. To support sending requests in stream mode, an operation can only receive one input parameter. this parameter is either a stream object, a message object, or an object that can be serialized as XML. To support response in stream mode, an operation either does not have any return type or is returned using an output parameter, which is the same as an input parameter, the output parameter must also be a stream object or an object that can be serialized as XML. Why is there such a limit? This is because input parameters (or output parameters) must constitute a complete input message or output message. Exercise: Implement stream mode in ShoppingCartPhotoService to return Response Message 1. open C :\... \ MTOMService project IShoppingCartPhotoService under the App_Code folder. cs file, add the following new version to get the product image, which is used to support the stream mode: 2. open the ShoppingCartPhotoService service implementation class in the App_Code folder. cs file, add a new GetPhoto method, and return a MemoryStream object, which contains image data: 3. use the WCF Service configuration editor to modify the binding configuration of the ShoppingCartPhotoServcie service and ShoppingCartGUIClient program, and change the TransferMode of the two to StreamResponse so that the service can return response messages in stream mode. Note, the binding setting of ShoppingCartGUI must also be set to Streame. DResponse; otherwise, the client's WCF will buffer the received response message before the message is delivered to the client program. 4. Update the service reference in ShoppingCartGUIClient and modify the getPhoto_Click method: 5. Delete the web_messages.svclog and web_tracelog.svclog files in the * \ WCF \ Step. by. Step \ Solutions \ Chapter13 folder. 6. Run the solution in non-adaptive mode, and then enter the WB-H098 in the client product code. If everything works, the client window displays the picture of the product. 7. Close the client program and stop ASP. NET Web server development. 8. start the WCF Service tracing viewing tool, click the message tag in the left-side Navigation Pane, click the first action, select the second message in the upper-right pane, and click the message tag in the lower-right corner, the message body of the message is shown in:
After starting the stream mode, you need to consider the message-level security features, such as signature and encryption, which are widely used in ws2007HttpBinding binding and require that the entire message be accessible during the WCF runtime. When you start the stream mode on the binding, the entire message is no longer accessible during the running of WCF. For this reason, neither ws2007HttpBinding nor other related bindings support stream mode. The solution is to implement basicHttpBinding security at the transmission level. In addition, you cannot use reliable message transmission. This feature relies on Buffering to enable the Protocol to know the transmission status of the entire message (messages will be sorted if sorting is set in the binding configuration ). Similarly, this becomes a problem for ws2007HttpBinding series binding. This is because the TCP transmission protocol and the named pipe themselves provide a reliable transmission mechanism, which is independent of the WS-ReliableMessaing Protocol implemented by WCF. The last focus of security matters is that by default, the bindings created by WCF allow receiving messages of a maximum size of 64 KB. If a received message exceeds this limit, an exception is thrown during the WCF operation and the operation is terminated. As mentioned earlier, this restriction mainly reduces the scope of DOS attacks. This value is sufficient for most message-oriented operations, but it is too low for most scenarios that support stream modes. In these scenarios, you need to increase the value of the maxcompute edmessagesize attribute in the binding configuration. However, this attribute is a global variable corresponding to the binding, so it will affect all operations exposed to the client on the binding; therefore, it is best to define a separate service contract for operations that do not support stream mode. For more information about large data and streams, see MSDN http://msdn.microsoft.com/zh-cn/library/ms733742.aspx.