Professional Documents
Culture Documents
Web
To improve performance of Web service methods that invoke long-running methods that block their thread, you should consider exposing them as asynchronous Web service methods. Implementing an asynchronous Web service method allows that thread to execute other code when it is returned to the thread pool. This allows one more of the limited number of threads in the thread pool to execute, enhancing the overall performance and scalability of the system. In general, Web service methods that call methods that perform I/O operations are good candidates for asynchronous implementation. Examples of such methods include methods that communicate with other Web services, access remote databases, perform network I/O, and read and write to large files. All these methods spend the bulk of their time executing in hardware, which leaves the thread for executing the Web service method blocked. That thread can be freed up to execute other code if the Web service method is implemented asynchronously. Regardless of whether a Web service method is implemented asynchronously, clients can communicate with it asynchronously. Asynchronous communication is exposed to .NET clients within the proxy class that is generated by the Web Services Description Language (WSDL.EXE) tool, even if a Web service method is implemented synchronously. The proxy class contains Begin and End methods for communicating with each Web service method asynchronously. Therefore, the decision to implement a Web service method asynchronously or synchronously should be based upon performance.
The second from the last parameter must be an AsyncCallback. The AsyncCallback parameter allows a client to supply a delegate, which is invoked when the method completes. When an asynchronous Web service method calls another asynchronous method, this parameter can be passed into the second from last parameter for that method. The last parameter is an Object. The Object parameter allows a caller to supply state information to the method. When an asynchronous Web service method calls another asynchronous method, this parameter can be passed into the last parameter for that method.
o
3.
The parameter list for the End method consists of an IAsyncResult followed by any out and by reference parameters specific to the method's functionality. o The return value is the same type as the return value of a synchronous Web service method.
Example
C# VB
using System; using System.Web.Services; [WebService(Namespace="http://www.contoso.com/")] public class MyService : WebService { public RemoteService remoteService; public MyService() { // Create a new instance of proxy class for // the Web service to be called. remoteService = new RemoteService(); } // Define the Begin method. [WebMethod] public IAsyncResult BeginGetAuthorRoyalties(String Author, AsyncCallback callback, object asyncState) { // Begin asynchronous communictation with a different XML Web // service. return remoteService.BeginReturnedStronglyTypedDS(Author, callback,asyncState); } // Define the End method. [WebMethod] public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult asyncResult) { // Return the asynchronous result from the other Web service. return remoteService.EndReturnedStronglyTypedDS(asyncResult); } }
Example
C# VB
using System.Web.Services; using System.Data; using System; // This imports the proxy class for the Web services // that the sample communicates with. using AsyncWS.localhost; namespace AsyncWS { [WebService(Namespace="http://www.contoso.com/")] public class MyService : System.Web.Services.WebService { public RemoteService remoteService; public MyService() { remoteService = new RemoteService(); } [WebMethod] public IAsyncResult BeginGetAuthorRoyalties(String Author, AsyncCallback callback, Object asyncState) { // Saves the current state for the call that gets the author's // royalties. AsyncStateChain state = new AsyncStateChain(); state.originalState = asyncState; state.Author = Author; state.originalCallback = callback; // Creates an intermediary callback. AsyncCallback chainedCallback = new
AsyncCallback(AuthorRoyaltiesCallback); return remoteService.BeginGetAuthors(chainedCallback,state); } // Intermediate method to handle chaining the // asynchronous calls. public void AuthorRoyaltiesCallback(IAsyncResult ar) { AsyncStateChain state = (AsyncStateChain)ar.AsyncState; RemoteService rs = new RemoteService(); // Gets the result from the call to GetAuthors. Authors allAuthors = rs.EndGetAuthors(ar); Boolean found = false; // Verifies that the requested author is valid. int i = 0; DataRow row; while (i < allAuthors.authors.Rows.Count && !found) { row = allAuthors.authors.Rows[i]; if (row["au_lname"].ToString() == state.Author) { found = true; } i++; } if (found) { AsyncCallback cb = state.originalCallback; // Calls the second Web service, because the author is // valid. rs.BeginReturnedStronglyTypedDS(state.Author,cb,state); } else { // Cannot throw the exception in this function or the XML Web // service will hang. So, set the state argument to the // exception and let the End method of the chained XML Web // service check for it. ArgumentException ex = new ArgumentException( "Author does not exist.","Author"); AsyncCallback cb = state.originalCallback; // Call the second Web service, setting the state to an // exception. rs.BeginReturnedStronglyTypedDS(state.Author,cb,ex); } } [WebMethod] public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult asyncResult) { // Check whehter the first Web service threw an exception. if (asyncResult.AsyncState is ArgumentException) throw (ArgumentException) asyncResult.AsyncState;
else return remoteService.EndReturnedStronglyTypedDS(asyncResult); } } // Class to wrap the callback and state for the intermediate // asynchronous operation. public class AsyncStateChain { public AsyncCallback originalCallback; public Object originalState; public String Author; } }
Wsdl.exe
and
the
.NET
Framework
<NameOfWebServiceMethod>
Sends a message for the Web service method named <NameOfWebServiceMethod> synchronously.
Begin<NameOfWebServiceMethod>
Begins asynchronous message communication with a Web service method named <NameOfWebServiceMethod>. The client instructs the Begin method to start processing the service call, but return immediately. The return value is not the data type specified by the Web service method, but rather a type implementing the IAsyncResult interface. Ends an asynchronous message communication with a Web service method named <NameOfWebServiceMethod>, returning a value that is the result of the Web service method call.
End<NameOfWebServiceMethod>
The Begin and End methods follow the naming convention for the .NET Framework's asynchronous design pattern. The design pattern predicates that there are two asynchronous methods named as such for each synchronous method. For an example, consider a Web service class PrimeFactorizer that has a Web service method that searches for prime factors, with the following signature:
public long[] Factorize(long factorizableNum)
Such a method could take a relatively extended period of time to finish processing, depending on the input. Thus, it is a good example of when you should have your Web service client to call the Web service method asynchronously. If Wsdl.exe used this Web service as an input for generating client proxy code (using the ?wsdl query string for an ASP.NET Web service), it would generate methods with the following signatures:
C#
public long[] Factorize(long factorizableNum) public System.IAsyncResult BeginFactorize(long factorizableNum, System.AsyncCallback callback, object asyncState) public long[] EndFactorize(System.IAsyncResult asyncResult)
Implementing a Web Service Client That Makes an Asynchronous Method Call Using the Begin/End Pattern
How does a client know when to call the End method? There are two techniques for implementing a client to determine this, as defined by the .NET Framework:
Wait technique: Use one of the methods of the WaitHandle class to cause a client to wait for the method to complete. Callback technique: Pass a callback function into the Begin method, which is then called to retrieve the results when the method has completed processing.
Note: Regardless of which of the two techniques a client chooses to communicate with a Web service asynchronously, the SOAP messages sent and received are identical to the SOAP messages generated through the synchronous proxy method. That is, there is still only one SOAP request and SOAP response sent and received across the network. The proxy class accomplishes this by handling the SOAP response using a different thread than the thread the
client used to call the Begin method. Therefore, the client can continue to perform other work on its thread, while the proxy class handles receiving and processing the SOAP response.
The WaitHandle class implements methods that support waiting for synchronization objects to be signaled: WaitOne, WaitAny, and WaitAll. The signaling of a synchronization object is an indication that threads waiting upon the specified resource can then access the resource. The Web service client accesses a WaitHandle object through the AsyncWaitHandle property of the IAsyncResult object returned by the Begin method. For an example of this technique, see How to: Implement an Asynchronous Web Service Client Using the Wait Technique.
With the callback technique, a callback function implements the AsyncCallback delegate, which enforces the signature: For an example of this technique, see How to: Implement an Asynchronous Web Service Client Using the Callback Technique. If the callback requires synchronized/thread-affinity context, it is dispatched through the context dispatcher infrastructure. In other words, the callback might execute asynchronously with respect to its caller for such contexts. That is precisely the semantics of the one-way qualifier on method signatures. It means that any such method call might execute synchronously or asynchronously, with respect to the caller, and the caller cannot make any assumptions about completion of such a call when execution control returns to it. Calling the End method before the asynchronous operation is complete will block the caller. The behavior for calling it a second time with the same IAsyncResult returned by the Begin method is undefined.
2.
<%@ WebService Language="VB" Class="ServerUsage" %> Add a reference to the System.Web.Services namespace.
C#
using System.Web.Services;
VB
3.
Imports System.Web.Services Derive the class that implements the Web service from WebService .
C#
4.
Public Class ServerUsage : Inherits WebService Declare a Web service method, setting the EnableSession property of the WebMethod attribute to true.
C#
5.
< WebMethod(EnableSession:=True) > _ Public Function PerSessionServiceUsage() As Integer Store state in the Session, which specifies a name for the state for later retrieval. In the following example the value 1 is stored in a state variable named MyServiceUsage.
C#
Session["MyServiceUsage"] = 1;
VB
6.
Session("MyServiceUsage") = 1 Access the state variable stored in the Session . In the following example, the MyServiceUsage state variable is accessed to increment its value.
C#
Session("MyServiceUsage") = CInt(Session("MyServiceUsage")) + 1
To access and store state specific to the Web application hosting the Web service
1. Declare a Web service. C#
2.
<%@ WebService Language="VB" Class="ServerUsage" %> Add a reference to the System.Web.Services namespace.
C#
using System.Web.Services;
VB
3.
Imports System.Web.Services Derive the class that implements the Web service from WebService .
C#
4.
5.
< WebMethod > _ Public Function PerSessionServiceUsage() As Integer Store state in the Application, which specifies a name for the state for later retrieval. In the following example the value 1 is stored in a state variable named appMyServiceUsage.
C#
Application["appMyServiceUsage"] = 1;
VB
6.
Application("appMyServiceUsage") = 1 Access the state variable stored in the Application. In the following example, the appMyServiceUsage state variable is accessed to increment its value.
C#
Application("appMyServiceUsage") = _ CInt(Application("appMyServiceUsage")) + 1
Example
C# VB
<%@ WebService Language="C#" Class="ServerUsage" %> using System.Web.Services; public class ServerUsage : WebService { [ WebMethod(Description="Number of times this service accessed.") ] public int ServiceUsage() { // If the Web service method hasn't been accessed, // initialize it to 1. if (Application["appMyServiceUsage"] == null) { Application["appMyServiceUsage"] = 1; } else { // Increment the usage count. Application["appMyServiceUsage"] = Application["appMyServiceUsage"]) + 1; } return (int) Application["appMyServiceUsage"]; }
has
been
((int)
[ WebMethod(Description="Number of times a particular client session has accessed this Web service method.",EnableSession=true) ] public int PerSessionServiceUsage() { // If the Web service method hasn't been accessed, initialize // it to 1. if (Session["MyServiceUsage"] == null) { Session["MyServiceUsage"] = 1; } else { // Increment the usage count. Session["MyServiceUsage"] = ((int) Session["MyServiceUsage"]) + 1; } return (int) Session["MyServiceUsage"]; } }
VB
<%@ WebService Language="VB" Class="Orders" %> 2. Add an Assembly directive to System.EnterpriseServices. 3. <%@ Assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,Pu blicKeyToken=b03f5f7f11d50a3a" %> 4. Add references to the System.Web.Services and System.EnterpriseServices namespaces.
C#
VB
5.
Imports System.Web.Services Imports System.EnterpriseServices Declare a Web service method, setting the TransactionOption property of the WebMethodAttribute attribute to System.EnterpriseServices.TransactionOption.RequiresNew .
C#
VB
TransactionOption Enumeration
Specifies the automatic transaction type requested by the component. Namespace: System.EnterpriseServices Assembly: System.EnterpriseServices (in System.EnterpriseServices.dll)
Syntax
C# C++ F# VB
Members
Member name Description
Disabled
NotSupported
Supported
Required
RequiresNew
Creates the component with a new transaction, regardless of the state of the current context.
Remarks
When using the .NET Installation a ServicedComponent defaults to Disabled. Tool (Regsvcs.exe), the transaction option for
Examples
The following code example demonstrates the use of the TransactionOption type. C# C++ VB
using System; using System.EnterpriseServices; using System.Reflection; // References: // System.EnterpriseServices // An instance of this class will not participate in transactions, but can // share its caller's context even if its caller is configured as // NotSupported, Supported, Required, or RequiresNew. [Transaction(TransactionOption.Disabled)] public class TransactionAttribute_TransactionDisabled : ServicedComponent { } // An instance of this class will not participate in transactions, and will // share its caller's context only if its caller is also configured as // NotSupported. [Transaction(TransactionOption.NotSupported)] public class TransactionAttribute_TransactionNotSupported : ServicedComponent { } // An instance of this class will participate in its caller's transaction // if one exists. [Transaction(TransactionOption.Supported)] public class TransactionAttribute_TransactionSupported : ServicedComponent { }
// An instance of this class will participate in its caller's transaction // if one exists. If not, a new transaction will be created for it. [Transaction(TransactionOption.Required)] public class TransactionAttribute_TransactionRequired : ServicedComponent { } // A new transaction will always be created for an instance of this class. [Transaction(TransactionOption.RequiresNew)] public class TransactionAttribute_TransactionRequiresNew : ServicedComponent { }
Syntax
C# C++ F# VB
Property Value
Type: System.EnterpriseServices.TransactionOption The transaction support of an XML Web service method. The default is Disabled.
Remarks
XML Web service methods can only participate as the root object in a transaction, due to the stateless nature of the HTTP protocol. XML Web service methods can invoke COM objects that participate in the same transaction as the XML Web service method, if the COM object is marked to run within a transaction in the Component Services administrative tool. If an XML Web service method with a TransactionOption property ofRequired or RequiresNew invokes another XML Web service method with a TransactionOption property of Required or RequiresNew, each XML Web service method participates in its own transaction, because an XML Web service method can only act as the root object in a transaction.
Item Disabled
Description Indicates that the XML Web service method does not run within the scope of a transaction. When a request is processed, the XML Web service method is executed without a transaction. [WebMethod(TransactionOption= TransactionOption.Disabled)] Indicates that the XML Web service method does not run within the scope of a transaction. When a request is processed, the XML Web service method is executed without a transaction. [WebMethod(TransactionOption= TransactionOption.NotSupported )] Indicates that the XML Web service method does not run within the scope of transactions. When a request is processed, the XML Web service is created without a transaction. [WebMethod(TransactionOption= TransactionOption.Supported)] Indicates that the XML Web service method requires a transaction. Since XML Web service methods can only participate as the root object in a transaction, a new transaction will be created for the XML Web service method. [WebMethod(TransactionOption= TransactionOption.Required)] Indicates that the XML Web service method requires a new transaction. When a request is processed, the XML Web service is created within a new transaction. [WebMethod(TransactionOption= TransactionOption.RequiresNew) ]
NotSupporte d
Supported
Required
RequiresNew
If an exception is thrown from or not caught by an XML Web service method, the transaction is automatically aborted. If no exceptions occur the transaction is automatically committed unless the method explicitly callsSetAbort.
Examples
The example below begins a new transaction when the Transfer method is called. C# VB
<%@ WebService Language="C#" Class="Bank"%> <%@ assembly name="System.EnterpriseServices,Version=1.0.3300.0,Culture=neutral,PublicKe yToken=b03f5f7f11d50a3a" %> using System; using System.Web.Services; using System.EnterpriseServices; public class Bank : WebService {
[ WebMethod(TransactionOption=TransactionOption.RequiresNew) ] public void Transfer(long Amount, long AcctNumberTo, AcctNumberFrom) { MyCOMObject objBank = new MyCOMObject(); if (objBank.GetBalance(AcctNumberFrom) < Amount ) // Explicitly abort the transaction. ContextUtil.SetAbort(); else { // Credit and Debit methods explictly vote within // the code for their methods whether to commit or // abort the transaction. objBank.Credit(Amount, AcctNumberTo); objBank.Debit(Amount, AcctNumberFrom); } } }
long
WebMethodAttribute Class
Adding this attribute to a method within an XML Web service created using ASP.NET makes the method callable from remote Web clients. This class cannot be inherited. Namespace: System.Web.Services Assembly: System.Web.Services (in System.Web.Services.dll)
Syntax
C# C++ F# VB
Constructors
Show: Inherited Protected
Name
Description
WebMethodAttribute()
of
WebMethodAttribute(Boolean)
of
WebMethodAttribute(Boolean, TransactionOption)
of
of
of
Properties
Show: Inherited Protected
Name
Description
BufferResponse
CacheDuration
Gets or sets the number of seconds the response should be held in the cache.
Description
EnableSession
Indicates whether session state is enabled for an XML Web service method.
MessageName
The name used for the XML Web service method in the data passed to and returned from an XML Web service method.
TransactionOption
TypeId
Top
When implemented in a derived class, gets a unique identifier for this Attribute. (Inherited from Attribute.)
Methods
Show: Inherited Protected
Name
Description
Equals
Infrastructure. Returns a value that indicates whether this instance is equal to a specified object. (Inherited from Attribute.)
Finalize
Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object.)
GetHashCode
Returns the hash code for this instance. (Inherited from Attribute.)
GetType
the
current
instance. (Inherited
IsDefaultAttribute
When overridden in a derived class, indicates whether the value of this instance is the default value for the derived class. (Inherited from Attribute.)
Match
When overridden in a derived class, returns a value that indicates whether this instance equals a specified object. (Inherited from Attribute.)
MemberwiseClone
ToString
Top
Returns a string that represents the current object. (Inherited from Object.)
Name
Description
_Attribute.GetIDsOfNames
Maps a set of names to a corresponding set of dispatch identifiers. (Inherited from Attribute.)
_Attribute.GetTypeInfo
Retrieves the type information for an object, which can be used to get the type information for an interface. (Inherited from Attribute.)
_Attribute.GetTypeInfoCount
Retrieves the number of type information interfaces that an object provides (either 0 or 1). (Inherited from Attribute.)
_Attribute.Invoke
Top
Provides access to properties and methods exposed by an object. (Inherited from Attribute.)
Remarks
Methods within a class that have this attribute set are called XML Web service methods. The method and class must be public and running inside an ASP.NET Web application.
Topic
Walkthrough: Creating and Using an ASP.NET Web Service in Visual Web Developer
Examples
In the example below the method GetMachineName can be remotely called across the Web, because it has a WebMethodAttribute. GetUserName cannot be called remotely, because it does not have a WebMethodAttribute, even though it is public. C# VB
<%@ WebService Language="C#" Class="Util"%> using System; using System.Web.Services; public class Util: WebService { public string GetUserName() { return User.Identity.Name;
} [ WebMethod(Description="Obtains the Server Machine Name", EnableSession=true)] public string GetMachineName() { return Server.MachineName; } }
the CommittableTransaction object. At that point the Transaction Manager calls the resource managers and informs them to either commit or rollback, based on whether the Complete method was called on the TransactionScope object. The using statement ensures that the Dispose method of the TransactionScope object is called even if an exception occurs. The Dispose method marks the end of the transaction scope. Exceptions that occur after calling this method may not affect the transaction. This method also restores the ambient transaction to it previous state. A TransactionAbortedException is thrown if the scope creates the transaction, and the transaction is aborted. A TransactionIndoubtException is thrown if the transaction manager cannot reach a Commit decision. No exception is thrown if the transaction is committed.
Managing
transaction
flow
using
TransactionScopeOption
Transaction scope can be nested by calling a method that uses a TransactionScope from within a method that uses its own scope, as is the case with the RootMethod method in the following example, C#
void RootMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ SomeMethod(); scope.Complete(); } } void SomeMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ scope.Complete(); } } The top-most transaction scope is referred to as the root scope. The TransactionScope class provides several overloaded constructors that accept an enumeration of the type TransactionScopeOption, which defines the transactional behavior of the scope. A TransactionScope object has three options: Join the ambient transaction, or create a new one if one does not exist. Be a new root scope, that is, start a new transaction and have that transaction be the new ambient transaction inside its own scope. Not take part in a transaction at all. There is no ambient transaction as a result. If the scope is instantiated with Required, and an ambient transaction is present, the scope joins that transaction. If, on the other hand, there is no ambient transaction, then the scope creates a new transaction, and become the root scope. This is the default value. When Required is used, the code inside the scope
does not need to behave differently whether it is the root or just joining the ambient transaction. It should operate identically in both cases. If the scope is instantiated with RequiresNew, it is always the root scope. It starts a new transaction, and its transaction becomes the new ambient transaction inside the scope. If the scope is instantiated with Suppress, it never takes part in a transaction, regardless of whether an ambient transaction is present. A scope instantiated with this value always have null as its ambient transaction. The above options are summarized in the following table.
TransactionScopeOption
Ambient Transaction
New Transaction (will be the root) New Transaction (will be the root) No Transaction Ambient Transaction New Transaction (will be the root) No Transaction
When a TransactionScope object joins an existing ambient transaction, disposing of the scope object may not end the transaction, unless the scope aborts the transaction. If the ambient transaction was created by a root scope, only when the root scope is disposed of, does Commit get called on the transaction. If the transaction was created manually, the transaction ends when it is either aborted, or committed by its creator. The following example shows a TransactionScope object that creates three nested scope objects, each instantiated with a different TransactionScopeOption value. C#
using(TransactionScope scope1 = new TransactionScope()) //Default is Required { using(TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Required)) { ... } using(TransactionScope scope3 TransactionScope(TransactionScopeOption.RequiresNew)) { ... } using(TransactionScope scope4 = new TransactionScope(TransactionScopeOption.Suppress)) { ... } } = new
The example shows a code block without any ambient transaction creating a new scope ( scope1) with Required. The scope scope1 is a root scope as it creates a new transaction (Transaction A) and makes Transaction A the ambient transaction. Scope1 then creates three more objects, each with a different TransactionScopeOption value. For example, scope2 is created with Required, and since there is an ambient transaction, it joins the first transaction created by scope1. Note that scope3 is the root scope of a new transaction, and that scope4 has no ambient transaction. Although the default and most commonly used value of TransactionScopeOption is Required, each of the other values has its unique purpose. Suppress is useful when you want to preserve the operations performed by the code section, and do not want to abort the ambient transaction if the operations fail. For example, when you want to perform logging or audit operations, or when you want to publish events to subscribers regardless of whether your ambient transaction commits or aborts. This value allows you to have a non-transactional code section inside a transaction scope, as shown in the following example. C#
using(TransactionScope scope1 = new TransactionScope()) { try { //Start of non-transactional section using(TransactionScope scope2 = new TransactionScope(TransactionScopeOption.Suppress)) { //Do non-transactional work here } //Restores ambient transaction here } catch {} //Rest of scope1 }
A CommittableTransaction object cannot be reused. Once a CommittableTransaction object has been committed or rolled back, it cannot be used again in a transaction. That is, it cannot be set as the current ambient transaction context.
Creating a CommittableTransaction
The following sample creates a new CommittableTransaction and commits it. Creating an instance of CommittableTransaction does not automatically set the ambient transaction context. Therefore, any operation on a resource manager is not part of that transaction. The static Current property on the global Transaction object is used to set or retrieve the ambient transaction and the application must manually set it to ensure that resource managers can participate in the transaction. It is also a good practice to save the old ambient transaction and restore it when you finish using the CommittableTransaction object. To commit the transaction, you need to explicitly call the Commit method. For rolling back a transaction, you should call the Rollback method. It is important to note that until a CommittableTransaction has been committed or rolled back, all the resources involved in that transaction are still locked. A CommittableTransaction object can be used across function calls and threads. However, it is up to the application developer to handle exceptions and specifically call the Rollback method in case of failures.
Asynchronous Commit
The CommittableTransaction class also provides a mechanism for committing a transaction asynchronously. A transaction commit can take substantial time, as it might involve multiple database access and possible network latency. When you want to avoid deadlocks in high throughput applications, you can use asynchronous commit to finish the transactional work as soon as possible, and run the commit operation as a background task. TheBeginCommit and EndCommit methods of the CommittableTransaction class allow you to do so. You can call BeginCommit to dispatch the commit holdup to a thread from the thread pool. You can also call EndCommit to determine if the transaction has actually been committed. If the transaction failed to commit for whatever reason, EndCommit raises a transaction exception. If the transaction is not yet committed by the time EndCommit is called, the caller is blocked until the transaction is committed or aborted. The easiest way to do an asynchronous commit is by providing a callback method, to be called when committing is finished. However, you must call the EndCommit method on the original CommittableTransaction object used to invoke the call. To obtain that object, you can downcast the IAsyncResult parameter of the callback method, since the CommittableTransaction class implements IAsyncResult class. The following example shows how an asynchronous commit can be done. C#
public void DoTransactionalWork() { Transaction oldAmbient = Transaction.Current; CommittableTransaction committableTransaction CommittableTransaction(); Transaction.Current = committableTransaction; try { /* Perform transactional work here */ // No errors - commit transaction asynchronously committableTransaction.BeginCommit(OnCommitted,null); } finally {
new
//Restore the ambient transaction Transaction.Current = oldAmbient; } } void OnCommitted(IAsyncResult asyncResult) { CommittableTransaction committableTransaction; committableTransaction = asyncResult as CommittableTransaction; Debug.Assert(committableTransaction != null); try { using(committableTransaction) { committableTransaction.EndCommit(asyncResult); } } catch(TransactionException e) { //Handle the failure to commit } }
Transaction Escalation
Management
Windows hosts a set of services and modules that together constitute a transaction manager. Transaction management escalation describes the process of migrating a transaction from one of the transaction manager's components to another. System.Transactions includes a transaction manager component that coordinates a transaction involving at most, a single durable resource or multiple volatile resources. Because the transaction manager uses only intra-application domain calls, it yields the best performance. Developers need not interact with the transaction manager directly. Instead, a common infrastructure that defines interfaces, common behavior, and helper classes is provided by the System.Transactions namespace. When you want to provide the transaction to another object in another application domain (including across process and machine boundaries) on the same computer, the System.Transactions infrastructure automatically escalates the transaction to be managed by the Microsoft Distributed Transaction Coordinator (MSDTC). The escalation also occurs if you enlist another durable resource manager. When escalated, the transaction remains managed in its elevated state until its completion. Between the System.Transactions transaction and MSDTC transaction, there is an intermediary type of transaction that is made available through the Promotable Single Phase Enlistment (PSPE). PSPE is another important mechanism in System.Transactions for performance optimization. It allows a remote durable resource, located in a different application domain, process or computer, to participate in a System.Transactions transaction without causing it to be escalated to an MSDTC transaction. For more information about PSPE, see Enlisting Resources as Participants in a Transaction.
performance, you should delay or avoid escalation to MSDTC; thus, you need to know how and when the escalation is initiated. As long as the System.Transactions infrastructure handles volatile resources and at most one durable resource that supports single-phase notifications, the transaction remains in the ownership of the System.Transactionsinfrastructure. The transaction manager avails itself only to those resources that live in the same application domain and for which logging (writing the transaction outcome to disk) is not required. An escalation that results in the System.Transactions infrastructure transferring the ownership of the transaction to MSDTC happens when: At least one durable resource that does not support single-phase notifications is enlisted in the transaction. At least two durable resources that support single-phase notifications are enlisted in the transaction. For example, enlisting a single connection with does not cause a transaction to be promoted. However, whenever you open a second connection to a database causing the database to enlist, the System.Transactions infrastructure detects that it is the second durable resource in the transaction, and escalates it to an MSDTC transaction. A request to "marshal" the transaction to a different application domain or different process is invoked. For example, the serialization of the transaction object across an application domain boundary. The transaction object is marshaled-by-value, meaning that any attempt to pass it across an application domain boundary (even in the same process) results in serialization of the transaction object. You can pass the transaction objects by making a call on a remote method that takes a Transaction as a parameter or you can try to access a remote transactional-serviced component. This serializes the transaction object and results in an escalation, as when a transaction is serialized across an application domain. It is being distributed and the local transaction manager is no longer adequate. The following table lists all the possible exceptions that can be thrown during escalation.
Exception type
Condition
InvalidOperationException
An attempt to escalate a transaction with isolation level equal to Snapshot. The transaction manager is down. The escalation fails and the application is aborted.
TransactionAbortedException TransactionException
public class WorkerThread { public void DoWork(DependentTransaction dependentTransaction) { Thread thread = new Thread(ThreadMethod); thread.Start(dependentTransaction); } public void ThreadMethod(object transaction) { DependentTransaction dependentTransaction = DependentTransaction; Debug.Assert(dependentTransaction != null); try { using(TransactionScope ts TransactionScope(dependentTransaction)) { /* Perform transactional work here */ ts.Complete(); } } finally { dependentTransaction.Complete(); dependentTransaction.Dispose(); } }
transaction
as
new
//Client code using(TransactionScope scope = new TransactionScope()) { Transaction currentTransaction = Transaction.Current; DependentTransaction dependentTransaction; dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComp lete); WorkerThread workerThread = new WorkerThread(); workerThread.DoWork(dependentTransaction); /* Do some transactional work here, then: */ scope.Complete(); }
The client code creates a transactional scope that also sets the ambient transaction. You should not pass the ambient transaction to the worker thread. Instead, you should clone the current (ambient) transaction by calling theDependentClone method on the current transaction, and pass the dependent to the worker thread. The ThreadMethod method executes on the new thread. The client starts a new thread, passing the dependent transaction as the ThreadMethod parameter. Because the dependent transaction is created with BlockCommitUntilComplete, you are guaranteed that the transaction cannot be committed until all of the transactional work done on the second thread is finished andComplete is called on the dependent transaction. This means that if the client's scope ends (when it tries to dispose of the transaction object at the end of the using statement) before the new thread calls Complete on the dependent transaction, the client code blocks until Complete is called on the dependent. Then the transaction can finish committing or aborting.
Concurrency Issues
There are a few additional concurrency issues that you need to be aware of when using the DependentTransaction class: If the worker thread rolls back the transaction but the parent tries to commit it, a TransactionAbortedException is thrown. You should create a new dependent clone for each worker thread in the transaction. Do not pass the same dependent clone to multiple threads, because only one of them can call Complete on it. If the worker thread spawns a new worker thread, make sure to create a dependent clone from the dependent clone and pass it to the new thread.
Additionally, ASP.NET offers the ability, known as impersonation, to execute a request using the client credentials. For more information about using impersonation, see ASP.NET Impersonation. This topic summarizes the authentication and authorization options available to Web services built using ASP.NET. For more information about security options available to ASP.NET Web applications, see Securing ASP.NET Web Applications and Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication. For more information about accessing remote resources from ASP.NET-based applications, see the "Impersonation/Delegation Model" and "Trusted Subsystem Model" topics in Chapter 3 of Building Secure ASP.NET Applications.
Windows Basic
Use for non-secure identification of clients, as the user name and password are sent in base 64-encoded strings in plain text. Passwords and user names are encoded, but not encrypted, in this type of authentication. A determined, malicious user equipped with a networkmonitoring tool can intercept user names and passwords. Use for secure identification of clients in Internet scenarios. The user name and password are sent over the network using Secure Sockets Layer (SSL) encryption, rather than plain text. This is relatively easy to configure and works for Internet scenarios. However, using SSL degrades performance. Use for secure identification of clients in Internet scenarios. Uses hashing to transmit client credentials in an encrypted manner so the password is not transmitted in clear text. In addition, Digest authentication can work through proxy servers. However, it is not widely supported on other platforms. Uses NTLM or Kerberos. Uses a cryptographic exchange with the user's Microsoft Internet Explorer Web browser.
Windows Digest
Client Certificates
scenarios. Requires each client to obtain a certificate from a mutually trusted certificate authority. Certificates are optionally mapped to user accounts, which are used by IIS for authorizing access to the Web service. Not supported by Web services. This is a system by which unauthenticated requests are redirected to an HTML form using HTTP client-side redirection. Most clients of Web services will not want to provide credentials using a UI; you must work around this if you want to use forms authentication. Useful for both secure and non-secure Internet scenarios. User credentials are passed within the SOAP header of the SOAP message. The Web server, regardless of the platform hosting the Web service, provides a custom authentication implementation.
Forms
For all options listed above, except the use of SOAP headers, the security settings are specified using a combination of configuration files and IIS. The custom SOAP headers option is detailed following the Authorization section, as that solution involves both authentication and authorization.
Windows Authentication
Both IIS and ASP.NET provide support for authenticating Web applications, including Web services, using security built in to Windows. Windows provides three options for authentication: Basic, Digest, and Integrated Windows. Additionally, each option can be used with SSL. As all Windows authentication options except Basic encrypt the data in some form, the additional level of encryption offered by SSL is typically only used in conjunction with Basic or Client Certificates. Regardless of which Windows authentication option is used, the procedures for setting up both the Web service and Web service client are similar. For more information, see How to: Configure an XML Web Service for Windows Authentication. No code needs to be added to a Web service to use Windows authentication, as the authentication options are set in a configuration file and IIS. Code to pass the client credentials to the Web service must be added to a Web service client. If SSL is chosen as part of the authenticating mechanism used by a Web service, SSL needs to be configured for the Web application hosting the Web service or for the Web service itself, using IIS. The service description and, consequently, proxy classes generated from the service description will reflect that the Web service uses SSL (if the service description and service help page are accessed using SSL). The URL to the Web service within the service description will be prefixed with https. For more information about setting up SSL, see the IIS documentation.
Client Certificates help provide a secure mechanism for authentication, as clients are required to send an electronic document, called a client certificate, identifying a client using an SSL connection to the Web server. The SSL connection encrypts the client credentials contained within the client certificate as they are sent over the network. Communication between the client and the Web server is encrypted using a combination of the encryption keys sent by the client and keys provided by the Web server. Once the communication is established, only the client and server computers can communicate to each other using that SSL connection. A client certificate can be obtained from a certificate authority, which can either be the Web server itself or a trusted intermediary between the client and server. Once a certificate has been obtained, and the Web server has been configured to accept client certificates, a client can send the client certificate to the Web server over an SSL connection, when a Web service is called. For more information about client certificates, see the IIS documentation. For more information about setting up Client Certificate authentication for a Web service, see How to: Configure an XML Web Service for Windows Authentication.
2.
Set the mode attribute of the authentication XML element in a configuration file to "Windows". The following code example modifies a configuration file to use Windows authentication.
6.
The following list is an overview of how to configure IIS to authenticate clients using client certificates. For details, see the IIS documentation. Install SSL. Configure the Web application to accept client certificates. Modify the configuration file to specify Windows authentication for the Web service. Set the mode attribute of the authentication XML element in a configuration file to "Windows". The following code example modifies a configuration file to use Windows authentication.
4.
' Instantiate proxy class to a Bank Web service. Dim bank As BankSession = new BankSession() ' Load the client certificate from a file. Dim x509 As X509Certificate X509Certificate.CreateFromCertFile("c:\user.cer") ' Add the client certificate to the ClientCertificates property ' of the proxy class. bank.ClientCertificates.Add(x509) ' Call the method on the proxy class, which requires authentication ' using client certificates. bank.Deposit(500)
C#
// Instantiate proxy class to a Bank Web service. BankSession bank = new BankSession(); // Load the client certificate from a file. X509Certificate x509 X509Certificate.CreateFromCertFile(@"c:\user.cer"); // Add the client certificate to the ClientCertificates property // of the proxy class. bank.ClientCertificates.Add(x509); // Call the method on the proxy class, which requires // authentication using client certificates. bank.Deposit(500);
Example
When the Credentials property is set to System.Net.CredentialCache.DefaultCredentials then the client negotiates with the server to do Kerberos and/or NTLM authentication depending on how the server is configured. The following code example sets the client credentials passed to a Web service method using Windows authentication. C# VB
public class Calculator { public static void Main() { // Create a new instance of the proxy class to an XML // Web service method. MyMath.Math math = new MyMath.Math();
// Create a new instance of CredentialCache. CredentialCache credentialCache = new CredentialCache(); // Create a new instance of NetworkCredential using the client // credentials. NetworkCredential credentials = new NetworkCredential(UserName,SecurelyStroredPassword,Domain); // Add the NetworkCredential to the CredentialCache. credentialCache.Add(new Uri(math.Url), "Basic", credentials); // Add the CredentialCache to the proxy class credentials. math.Credentials = credentialCache; // Call the method on the proxy class. int result = math.Add(3,5); } }
In the sample provided, the HTTP Module authenticates the user and sets Context properties that a Web service can use to decide whether the client is authorized access to the Web service.
Note:
In this sample, the text is sent over the network in clearly readable text (it is not encrypted). If clear text is not secure enough for your application, add an encryption algorithm.
Example
The following code example is an HTTP Module that parses HTTP messages for SOAP requests. If the HTTP message is a SOAP message, the custom WebServiceAuthenticationEvent is raised. C# VB
namespace Microsoft.WebServices.Security { public sealed class WebServiceAuthenticationModule : IHttpModule { private WebServiceAuthenticationEventHandler _eventHandler = null; public event WebServiceAuthenticationEventHandler Authenticate { add { _eventHandler += value;} remove {_eventHandler -= value;} } public void Dispose() { } public void Init(HttpApplication app) { app.AuthenticateRequest += new EventHandler(this.OnEnter); } private void OnAuthenticate(WebServiceAuthenticationEvent e) { if (_eventHandler == null) return; _eventHandler(this, e); if (e.User != null) e.Context.User = e.Principal; } public string ModuleName { get{ return "WebServiceAuthentication"; } } void OnEnter(Object source, EventArgs eventArgs) {
HttpApplication app = (HttpApplication)source; HttpContext context = app.Context; Stream HttpStream = context.Request.InputStream; // Save the current position of stream. long posStream = HttpStream.Position; // If the request contains an HTTP_SOAPACTION // header, look at this message. if (context.Request.ServerVariables["HTTP_SOAPACTION"] == null) return; // Load the body of the HTTP message // into an XML document. XmlDocument dom = new XmlDocument(); string soapUser; string soapPassword; try { dom.Load(HttpStream); // Reset the stream position. HttpStream.Position = posStream; // Bind to the Authentication header. soapUser = dom.GetElementsByTagName("User").Item(0).InnerText; soapPassword = dom.GetElementsByTagName("Password").Item(0).InnerText; } catch (Exception e) { // Reset the position of stream. HttpStream.Position = posStream; // Throw a SOAP exception. XmlQualifiedName name = new XmlQualifiedName("Load"); SoapException soapException = new SoapException( "Unable to read SOAP request", name, e); throw soapException; } // Raise the custom global.asax event. OnAuthenticate(new WebServiceAuthenticationEvent (context, soapUser, soapPassword)); return; } } }
The following code example is the custom authentication event that is raised by the HTTP Module, if a SOAP request is received.
C# VB
public class WebServiceAuthenticationEvent : EventArgs { private Iprincipal _IPrincipalUser; private HttpContext _Context; private string _User; private string _Password; public WebServiceAuthenticationEvent(HttpContext context) { _Context = context; } public WebServiceAuthenticationEvent(HttpContext context, string user, string password) { _Context = context; _User = user; _Password = password; } public HttpContext Context { get { return _Context;} } public IPrincipal Principal { get { return _IPrincipalUser;} set { _IPrincipalUser = value;} } public void Authenticate() { GenericIdentity i = new GenericIdentity(User); this.Principal = new GenericPrincipal(i, new String[0]); } public void Authenticate(string[] roles) { GenericIdentity i = new GenericIdentity(User); this.Principal = new GenericPrincipal(i, roles); } public string User { get { return _User; } set { _User = value; } } public string Password { get { return _Password; } set { _Password = value; } }
public bool HasCredentials { get { if ((_User == null) || (_Password == null)) return false; return true; } } } }
The following code example is the delegate for the custom WebServiceAuthenticationEvent event. C# VB
namespace Microsoft.WebServices.Security { using System; public delegate void WebServiceAuthenticationEventHandler(Object sender, WebServiceAuthenticationEvent e); } The following code example is a Web service that defines the Authentication SOAP header that a client must pass. The Web service does not have to do the authentication. Rather, it can inspect theUser.Identity.IsAuthenticated property to determine if the HTTP Module has authenticated the user. C#
VB
<%@ WebService Language="C#" Class="SecureWebService" %> using System; using System.Web.Services; using System.Web.Services.Protocols; public class Authentication : SoapHeader { public string User; public string Password; } public class SecureWebService : WebService{ public Authentication authentication; [WebMethod] [SoapHeader("authentication")] public string ValidUser(){ if (User.IsInRole("Customer")) return "User is in role customer"; if (User.Identity.IsAuthenticated) return "User is a valid user"; return "not authenticated"; } }
The following code example is a Web service client that passes the necessary credentials for a custom SOAP header authentication mechanism within an Authentication SOAP header. C# VB
// Create a new instance of a Web service proxy class. SecureWebService s = new SecureWebService(); // Create the Authentication SOAP header and set values. Authentication a = new Authentication(); a.User = user.Value; a.Password = password.Value; // Assign the Header. s.AuthenticationValue = a; string result = s.ValidUser(); span1.InnerHtml = result;
How to: Create Web Services That Parse the Contents of a Web Page
Web services created using ASP.NET provide an HTML parsing solution that enables developers to parse content from a remote HTML page and programmatically expose the resulting data. For a detailed explanation, seeHTML Parsing by ASP.NET XML Web Services.
2. 3.
Note:
The operation name inside a binding must be globally unique or Wsdl.exe can be run with the namespace specified to prevent naming collisions caused by other WSDL files imported in the same application.
1.
Add <match> XML elements in the service description within the <text> XML element for each piece of data you want to return from the parsed HTML page. Apply attributes to the <match> element. The valid attributes are presented in a table under the topic HTML Parsing by ASP.NET XML Web Services.
2.
Example
The following code example is a simple Web page sample containing <TITLE> and <H1> tags.
<HTML> <HEAD> <TITLE>Sample Title</TITLE> </HEAD> <BODY> <H1>Some Heading Text</H1> </BODY> </HTML> The following code example is a service description that parses the contents of the HTML page, extracting the contents of the text within the <TITLE> and <H1> tags. In the code example, a TestHeaders method is defined for the GetTitleHttpGet binding. The TestHeaders method defines two pieces of data that can be returned from the parsed HTML page in <match> XML elements: Title and H1, which parse the contents of the <TITLE> and <H1> tags, respectively. <?xml version="1.0"?> <definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <s:schema targetNamespace="http://tempuri.org/" attributeFormDefault="qualified" elementFormDefault="qualified"> <s:element name="TestHeaders"> <s:complexType derivedBy="restriction"/>
</s:element> <s:element name="TestHeadersResult"> <s:complexType derivedBy="restriction"> <s:all> <s:element name="result" type="s:string" nullable="true"/> </s:all> </s:complexType> </s:element> <s:element name="string" type="s:string" nullable="true"/> </s:schema> </types> <message name="TestHeadersHttpGetIn"/> <message name="TestHeadersHttpGetOut"> <part name="Body" element="s0:string"/> </message> <portType name="GetTitleHttpGet"> <operation name="TestHeaders"> <input message="s0:TestHeadersHttpGetIn"/> <output message="s0:TestHeadersHttpGetOut"/> </operation> </portType> <binding name="GetTitleHttpGet" type="s0:GetTitleHttpGet"> <http:binding verb="GET"/> <operation name="TestHeaders"> <http:operation location="MatchServer.html"/> <input> <http:urlEncoded/> </input> <output> <text xmlns="http://microsoft.com/wsdl/mime/textMatching/"> <match name='Title' pattern='TITLE>(.*?)<'/> <match name='H1' pattern='H1>(.*?)<'/> </text> </output> </operation> </binding> <service name="GetTitle"> <port name="GetTitleHttpGet" binding="s0:GetTitleHttpGet"> <http:address location="http://localhost" /> </port> </service> </definitions> The following code example is a portion of the proxy class generated by Wsdl.exe for the previous service description. C#
VB
' GetTitle is the name of the proxy class. public class GetTitle : HttpGetClientProtocol { public TestHeadersMatches TestHeaders() { return ((TestHeadersMatches)(this.Invoke("TestHeaders", (this.Url + "/MatchServer.html"), new object[0]))); }
2. 3.
Note:
The operation name inside a binding must be globally unique or Wsdl.exe can be run with the namespace speci application.
1.
Add <match> XML elements in the service description within the <text> XML element for each piece of data you want to return from the parsed HTML page. Apply attributes to the <match> element. The valid attributes are presented in a table under the topic HTML Parsing by ASP.NET XML Web Services.
2.
Example
The following code example is a simple Web page sample containing <TITLE> and <H1> tags.
<HTML> <HEAD> <TITLE>Sample Title</TITLE> </HEAD> <BODY> <H1>Some Heading Text</H1> </BODY> </HTML> The following code example is a service description that parses the contents of the HTML page, extracting the contents of the text within the <TITLE> and <H1> tags. In the code example, a TestHeaders method is defined for the GetTitleHttpGet binding. The TestHeaders method defines two pieces of data that can be returned from the parsed HTML page in <match> XML elements: Title and H1, which parse the contents of the <TITLE> and <H1> tags, respectively. <?xml version="1.0"?> <definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <s:schema targetNamespace="http://tempuri.org/" attributeFormDefault="qualified" elementFormDefault="qualified"> <s:element name="TestHeaders"> <s:complexType derivedBy="restriction"/> </s:element> <s:element name="TestHeadersResult"> <s:complexType derivedBy="restriction"> <s:all> <s:element name="result" type="s:string" nullable="true"/> </s:all> </s:complexType> </s:element> <s:element name="string" type="s:string" nullable="true"/> </s:schema> </types> <message name="TestHeadersHttpGetIn"/> <message name="TestHeadersHttpGetOut"> <part name="Body" element="s0:string"/> </message> <portType name="GetTitleHttpGet">
<operation name="TestHeaders"> <input message="s0:TestHeadersHttpGetIn"/> <output message="s0:TestHeadersHttpGetOut"/> </operation> </portType> <binding name="GetTitleHttpGet" type="s0:GetTitleHttpGet"> <http:binding verb="GET"/> <operation name="TestHeaders"> <http:operation location="MatchServer.html"/> <input> <http:urlEncoded/> </input> <output> <text xmlns="http://microsoft.com/wsdl/mime/textMatching/"> <match name='Title' pattern='TITLE>(.*?)<'/> <match name='H1' pattern='H1>(.*?)<'/> </text> </output> </operation> </binding> <service name="GetTitle"> <port name="GetTitleHttpGet" binding="s0:GetTitleHttpGet"> <http:address location="http://localhost" /> </port> </service> </definitions> The following code example is a portion of the proxy class generated by Wsdl.exe for the previous service description. C#
VB
' GetTitle is the name of the proxy class. public class GetTitle : HttpGetClientProtocol { public TestHeadersMatches TestHeaders() { return ((TestHeadersMatches)(this.Invoke("TestHeaders", (this.Url + "/MatchServer.html"), new object[0]))); } } public class TestHeadersMatches { public string Title; public string H1; }
The following code example demonstrates how to use the Duration property on the client application to specify output caching for a period of 60 seconds.
Example
C# VB
<%@ Page Language="C#" %> <%@ Import Namespace="System.Net" %> <%@ OutputCache Duration="60" VaryByParam="none" %> <html> <script language="C#" runat="server"> void EnterBtn_Click(Object Src, EventArgs e) { MyMath.Math math = new MyMath.Math(); // Call the Web service. float total = math.Add(Convert.ToInt32(Num1.Text), Convert.ToInt32(Num2.Text)); // Display the results in a Label control. Total.Text = "Total: " + total.ToString(); } </script> <body> <form action="MathClient.aspx" runat=server> <font face="Verdana"> Enter the two numbers you want to add and press the Total button. <p> Number 1: <asp:textbox id="Num1" runat=server/> + Number 2: <asp:textbox id="Num2" runat=server/> = <asp:button id="Total_Button" text="Total" OnClick="EnterBtn_Click" runat=server/> <p> <asp:label id="Total" runat=server/> </font> </form> </body> </html>
Example
C# VB
<%@ WebService Language="C#" Class="MathService" %> using System; using System.Web.Services; public class MathService : WebService { [WebMethod(CacheDuration=60)] public float Add(float a, float b) { return a + b; } [WebMethod(CacheDuration=60)] public float Subtract(float a, float b) { return a - b; } [WebMethod(CacheDuration=60)] public float Multiply(float a, float b) { return a * b; } [WebMethod(CacheDuration=60)] public float Divide(float a, float b) { if (b==0) return -1; return a / b; }
Interview Questions
1. What are Windows services? Windows services, previously known as NT services, are applications that are installed on the system as system services. In other words, Windows services are applications that run in the background with the Windows operating system. The primary use of Windows services is to reduce the consumption of memory required for performing backend operations. Let's take an example to understand this easily. Suppose you want to perform a variety of functions, such as monitor the performance of your computer or application, check the status of an application, and manage various devices, such as printers. In such a case, you can use Windows services to reduce memory consumption. In addition, Windows services can run on your system even if you have not logged on to your computer. In addition, these services do not have any user interface. 2. Can you share a process between Windows services? Yes, you can share a process between Windows services. 3. In .NET, which is the parent class to create all Windows services? The ServiceBase class is the parent class to create all Windows services. 4. Which class in .NET is used to install a Windows service? The ServiceInstaller class, also known as the project installer class, is used to install a Windows service. 5. While installing a Windows service, an EventLogInstaller class is automatically created to install the event log related to the particular service. Is it true? Yes, it is true. 6. Which property of the ServiceBase class can be used to specify whether a service can be paused and resumed? The CanPauseAndContinue property provides such type of service. 7. Describe the services that UDDI provides to Web applications. UDDI provides the following types of services to a Web application:
XML Schema for business descriptions - Includes information about the service publisher (contact name, address, and so on) and specifications on the Web service Web registry of Web services - Includes business, service, and binding information for the Web service
8. Write the file extension for a Web service. A Web service file extension is .asm file. For example, service1.asmx is a Web service file. 9. Which method is used to uninstall the Windows services? The Uninstall() method is used to uninstall the Windows services. 10. What is the use of the mustUnderstand attribute in the Header element of a SOAP message? The mustUnderstand attribute indicates that a header entry is either required or optional for the recipient to process further. 11. Explain the WSDL. WSDL is a short form for Web Services Description Language, which is used to describe a Web service in terms of the messages that it creates and accepts. The WSDL document is an XML file that contains the interface schema for the Web service. It identifies the methods that are used during the exchange between a Web service consumer and a Web service provider. The following are the elements contained in the WSDL document:
Types - Describe the variations of data types that are used to exchange messages between the user and the provider. Message - Describes the actual message or method call. portType - Describes the set of operations and each related message. binding - Describes the protocol details. service - Used to make groups a set of related ports together.
12. What advantage UDDI has over DISCO? The UDDI directory has an advantage over a DISCO file, as it provides a single location where a client can find the Web services offered by different organizations. 13. How can you ensure that only authorized users access your Web service? You should use the <authorization> element to ensure that only authorized users access your Web service. This element allows or denies access to your Web service according to their role. 14. Describe the EventLog class. The EventLog class is used to access the Windows event logs from Windows services. Using EventLog, you can also customize Windows event logs that record information about important software and hardware events, such as the events of the .NET controls, keyboard, or other hardware devices. The EventLog class allows you to read or write to event logs, delete logs, and create as well as delete event sources. You can use the EventLog class to create event logs while creating an event source. An event source can be used to write to only one event log at a particular time. However, it is possible to associate one event log to multiple sources. 15. How can you prevent your Web services from unauthorized access? The following are the ways to prevent your Web service from unauthorized access:
16. Explain the concept of Web services in brief. A Web service may be defined as an independent and self-sustained unit of a software application that is hosted on the Web and implement specific functionalities to execute the business logic. A Web service provides so many functionalities, such as generating pay slips for employees, computing tax, broadcasting weather report, and providing updated news. The Web service allows application to share information or exchange data with other applications across different operating systems and hardware. Therefore, the work of a Web service is to unite software by exchanging data irrespective of their operating systems, supported hardware, and programming language used in their development. The Web services transfer data in the XML format and use Simple Object Access Protocol (SOAP) to communicate. It is an XML based protocol. The Web services use Web Services Description Language (WSDL) and Universal Description, Discovery, and Integration (UDDI) to describe itself. 17. What advantages have Web services over Component Object Model (COM) and Distributed Component Object Model (DCOM)? The advantages of Web services over COM and DCOM are as follows:
Web services are simple to use and can be implemented on varied platforms. Web services are loosely coupled; as a result, their interfaces and methods can be extended. Web services do not carry any state information with them so that multiple requests can be processed simultaneously.
18. Mention the namespace that you must import in code to build a Web service.
The WebMethod attribute's EnableSession property enables you to enable session state for a Web method. 24. Write the names of public properties defined in the WebService class. There are many properties defined in the WebServices class:
Application - Obtains the application object for the current HTTP request Context - Obtains the HttpContext object for the current request, which encapsulates all
HTTP-specific context used by the HTTP server to process Web requests Server - Obtains the HttpServerUtility object for the current request
Session - Obtains the HttpSessionState object for the current request SoapVersion - Obtains the version of the SOAP protocol used to make the SOAP request to a
Web service User - Obtains the Server User Object. This property can be used to authenticate whether a user is authorized to execute the request.
25. What do you understand by SOAP encoding? The Serialization of the types, such as integers and strings, inside a SOAP message is called encoding. The SOAP objects use XML elements and attributes to serialized data, for example, encodingStyle is an attribute of theEnvelop element, which is used to specify the encoding rules for a SOAP object. 26. What is the use of a .disco file? A client application uses a .disco file to locate or discover the documents that contain the description of a Web service. The .disco file contains links to other resources, which describe essential features, such as capabilities of a Web service. The links contained in a .disco file can refer to other discovery documents or XSD schemas. The description about the services and capabilities of a Web service is written in Web services Description Language (WSDL). A .disco file can also contain the information about other XML Web services that reside on the same or a different Web server. 27. Mention the name of the directory where it is necessary to locate the proxy file to use a Web service. The proxy file must be stored in the /bin directory. This directory is situated under the root directory of the application. 28. Does a Web service have state? The Web services do not have any technique to maintain state. However, it can access ASP.NET objects, such as application and session if they extend from the WebService base class. 29. Which namespace must be included in a code that enables a XML Web service to write events in an event log file? The System.Diagnostics is the namespace, which must be included in a code to enable a Web service for writing events in an event log file. 30. Which tool installs the DLL on your local computer and installs the Windows service in a transactional manner?
Exceptions thrown by a Web service method created using ASP.NET are sent back to the client in the form of a SOAP fault. A SOAP fault is a Fault XML element within a SOAP message that specifies when an error occurred. It may contain details such as the exception string and the source of the exception. For details on SOAP faults, see the SOAP specification on the W3C Web site (http://www.w3.org/TR/SOAP). Fortunately, both clients and Web services created using ASP.NET do not populate or parse the Fault XML element directly, but rather use the common design pattern for throwing and catching exceptions in the .NET Framework. A Web service can throw either a generic SoapException or an exception specific to the problem, such as an ArgumentOutOfRangeException. Either way, ASP.NET serializes the exception into a valid SOAP message by placing the exception into a SOAP Fault element. When the SOAP message is deserialized on an ASP.NET client, the SOAP fault is converted to a SoapException exception, with the exception details placed in theMessage property. A client can thus set up a try/catch block to catch a SoapException. A code example of a Web service throwing an exception is provided in How to: Throw Exceptions from a Web Service Created Using ASP.NET. A code example of a Web service client catching an exception is provided in How to: Handle Exceptions Thrown by a Web Service Method. A Web application can be comprised of multiple Web services. However, the Application_Error event within the Global.asax Syntax file cannot be used for global exception handling. The HttpHandler for Web services consumes any exception that occurs while a Web service is executing and turns it into a SOAP fault before the Application_Error event is called. Build a SOAP extension to process Web service exceptions in a global exception handler. A SOAP extension can check for the existence of an exception in the ProcessMessage method. Within the ProcessMessage method, check the Exception property of the SoapMessage passed when theStage property is set to AfterSerialize. For details on SOAP extensions, see SOAP Message Modification Using SOAP Extensions.
Throw a SoapException exception. Throw a SoapHeaderException exception. Throw an exception specific to the problem. Allow ASP.NET to throw the exception.
The following table describes the exceptions a Web service can explicitly throw and how an ASP.NET client receives each exception:
A Web service method detects an exception case and throws the specific exception, such as ArgumentOutOfRangeException. A .NET Framework client receives a SoapException with the details serialized into text in the Message property. A Web service method detects an exception case and throws a SoapException. It also provides additional details regarding the problem. The Web service method populates the Detailproperty to provide this additional information. A .NET Framework client receives the SoapException with the additional information. A Web service method detects an exception case while processing a SOAP Header element. The Web service method throws a SoapHeaderException, which translates into a Fault element placed inside the response's Header element. The fault must appear in the response header in this situation according to the SOAP specification. A .NET Framework client receives theSoapHeaderException.
SoapException
SoapHeaderException
You should throw an exception that is specific to the problem or provide extra details to a SoapException or SoapHeaderException, as described in the preceding table.
When unhandled
exception occurs
While executing the Web service method While processing SOAP headers
The exception is caught by ASP.NET and thrown back to the client. The Web service client created using the .NET Framework receives a SoapException with the exception details placed in the Message property.
ASP.NET throws a SoapHeaderException. A Web service client created using the .NET Framework receives the SoapHeaderException.
VB
2.
Public Class MyHeader : Inherits SoapHeader Add public fields or properties, matching the names and their respective data types for each element in the SOAP header. For instance, given the following SOAP header, the class following it defines a class representing the SOAP header.
C#
</MyHeader> </soap:Header> public class MyHeader : SoapHeader { public DateTime Created; public long Expires; }
VB
Public Class MyHeader : Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class
[WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader timeStamp;
VB
2.
<WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService ' Add a member variable of the type deriving from SoapHeader. Public TimeStamp As MyHeader Apply a SoapHeader attribute to each Web service method that intends to process the SOAP header. Set the MemberName property of the SoapHeader attribute to the name of the member variable created in the first step.
C#
VB
3.
<WebMethod, SoapHeader("TimeStamp")> _ Public Sub MyWebMethod() Within each Web service method that the SoapHeader attribute is applied to, access the member variable created in the first step to process the data sent in the SOAP header.
C#
[WebMethod] [SoapHeader("myHeaderMemberVariable")] public string MyWebMethod() { // Verify that the client sent the SOAP Header. if (timeStamp == null) timeStamp = new MyHeader(); // Set the value of the SoapHeader returned to the client. timeStamp.Expires = 60000; timeStamp.Created = DateTime.UtcNow; return("Hello World!"); }
VB
<WebMethod,SoapHeader("TimeStamp", _ Direction:=SoapHeaderDirection.InOut)> _ Public Function MyWebMethod() As String ' Process the SoapHeader. If (TimeStamp Is Nothing) Then TimeStamp = New MyHeader End If TimeStamp.Expires = 60000 TimeStamp.Created = DateTime.UtcNow Return "Hello World!" End Function
Example
The following code example demonstrates how to define and process a SOAP header in a Web service created using ASP.NET. The MyWebService Web service has a member variable named myHeaderMemberVariable, which is of a type deriving from SoapHeader (MyHeader) and set to the MemberName property of the SoapHeader attribute. In addition, a SoapHeader attribute is applied to the MyWebMethod Web service method specifying myHeaderMemberVariable. Within the MyWebMethod Web service method, myHeaderMemberVariable is accessed to get the value of the Username XML element of the SOAP header. C# VB
<%@ WebService Language="C#" Class="MyWebService" %> using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public long Expires; }
[WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader myHeaderMemberVariable; // Apply a SoapHeader attribute. [WebMethod] [SoapHeader("myHeaderMemberVariable")] public void MyWebMethod() { // Process the SoapHeader. if (myHeaderMemberVariable.Username == "admin") { // Do something interesting. } } }
In the previous example, if the SOAP request to the MyWebMethod has a MyHeader SOAP header with a UserName element set to Admin, additional code is executed. That is, the following SOAP request causes that code to execute.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <MyHeader xmlns="http://www.contoso.com"> <Created>dateTime</Created> <Expires>long</Expires> </MyHeader> </soap:Header> <soap:Body> <MyWebMethod xmlns="http://www.contoso.com" /> </soap:Body> </soap:Envelope>
C#
2.
MyHeader mySoapHeader = new MyHeader(); Populate the values for the SOAP header.
VB
C#
3.
mySoapHeader.Username = Username; mySoapHeader.Password = SecurelyStoredPassword Create a new instance of the proxy class.
VB
C#
4.
MyWebService proxy = new MyWebService(); Assign the SOAP header object to the member variable of the proxy class representing the SOAP header.
VB
proxy.MyHeaderValue = mySoapHeader
C#
5.
proxy.MyHeaderValue = mySoapHeader Call the method on the proxy class that communicates with the Web service method. The SOAP header portion of the SOAP request sent to the Web service will include the contents of the data stored in the SOAP header object.
VB
C#
Example
The following code example demonstrates how to pass a SOAP header from a client to a Web service. C# VB
<%@ Page Language="C#" %> <asp:Label id="ReturnValue" runat="server" /> <script runat=server language=c#> void Page_Load(Object o, EventArgs e) { MyHeader mySoapHeader = new MyHeader(); // Populate the values of the SOAP header. mySoapHeader.Username = Username; mySoapHeader.Password = SecurelyStoredPassword; // Create a new instance of the proxy class. MyWebService proxy = new MyWebService(); // Add the MyHeader SOAP header to the SOAP request. proxy.MyHeaderValue = mySoapHeader; // Call the method on the proxy class that communicates with // your Web service method. string results = proxy.MyWebMethod(); // Display the results of the method in a label. ReturnValue.Text = results; } </script>
Using a Web service encompasses the communication of Web service methods over a network using industry standard protocols. However, before an application can begin communicating with Web service methods, there are four basic steps it must accomplish: 1. Determine if a Web service exists. You can look in a directory, such as UDDI Services, for the vendors that provide Web services with specific functionalities. The directory has a URL to the vendor's Web site. Discover a Web service. Given a URL to a vendor, Web service discovery is invoked to get the specific details about each Web service that is available at that URL. Information about each Web service is returned to the client in the form of a service description, which is an XML document that describes the Web service in the Web Services Description Language (WSDL). The service description concretely details how to communicate with a Web service. For information about Web service discovery, see Web Service Discovery. Given a service description, generate a proxy class, which can communicate with Web service methods based on the precise definition in the service description. For instructions, see Creating an XML Web Service Proxy. Because the proxy class communicates with the Web service across the Internet, it is a good idea to verify that the Url property of the proxy class references a trusted destination. 4. Create a client application, which invokes methods of the proxy class. The methods of the proxy class can communicate with the Web service methods over the Internet, using industry standard protocols. For more information, see Creating Clients for XML Web Services.
2.
3.
After discovering that a Web service exists using Web service discovery, you can view information about the Web service and the Web service methods it implements in a more user-friendly format than the service description. To do so, access the service help page described in How to: Explore Existing XML Web Services Created Using ASP.NET. Web services can be used by a variety of client applications. You can communicate with a Web service from any Web application, including another Web service. The client of a Web service is not necessarily a clientbased application; in reality, most clients are server-based applications, such as Web Forms and other Web services.
As shown in the previous graphic, there are two Web service clients: an ASP.NET Web Form and a Web service. The ASP.NET Web Form, which the user sees, communicates with the GetCurrentPrices Web service. TheGetCurrentPrices Web service then acts as a Web service client by communicating with the StockServices Web service to obtain the stock quote. The stock quote is then returned to the GetCurrentPrices Web service, which subsequently passes it back to the ASP.NET Web Form.
How to: Explore Existing XML Web Services Created Using ASP.NET
Once you know the URL for a Web service created using ASP.NET, you can use the URL to access a Web page known as the service help page. This page provides information about the functionality of the Web service, including the Web service methods it implements, their parameters, and their return types. In addition, you can use the service help page to test the functionality of the Web service. For example, suppose you are accessing a Web service called Investor, which is used to retrieve the stock price for a valid stock symbol. You know the base URL for this Web service is http://www.contoso.com/Investor.asmx. Entering this URL into a browser with no extensions or parameters produces a Web page with information about the Web service and the Web service methods it implements. In addition to viewing information about the Web service in the browser, you can also obtain a more formal definition of the Web service by viewing its service description, which is an XML document written in the Web Services Description Language (WSDL). A link at the top of the service help page allows you to view the service description. You can use the service description to manually generate a proxy class to the Web service. For more information about creating a proxy class, see Creating an XML Web Service Proxy.
Parameter
Value
servername apppath
The Web server on which the Web service resides. The name of the Web application that is hosting the Web service. The name of the file where the Web service is defined.
webservicename.asmx
3.
For example, to access a Web service called StockServices.asmx, residing on a Web server named StockTicker, enter the following:
4. http://StockTicker/StockServices.asmx
Note:
By default, a Web service created using ASP.NET is able to support multiple protocols, including SOAP over HTTP an the response.
3. http://servername/apppath/webservicename.asmx
Path portion
Value
Servername
The name of the server on which your Web service was deployed. The name of your virtual directory and the rest of the Web application path. The name of the Web service .asmx file.
Apppath
webservicename.asmx
4.
For example, suppose you have published a Web service named StockServices. When published, the base URL for this service is http://<servername>/apppath/StockServices.asmx. You could test this service by entering this HTTP-GET request in the browser's address bar:
5. http://<servername>/apppath/StockServices.asmx 6. The server, in response to this request, displays the Web service's HTML description page. 7. The Web service's HTML description page shows you all the Web service methods supported by a particular Web service. Link to the desired Web service method and enter the necessary parameters to test the method and see the XML response.
3. http://servername/vdir/webservicename.asmx/Methodname?parameter=value
Parameter
Value
Servername
The name of the server on which your Web service is deployed. The name of your virtual directory and the rest of the Web application path. The name of the Web service .asmx file. The name of a public method that is exposed by your Web service. If left blank, the Web service's description page is shown, listing each public method available in the .asmx file. (Optional) The appropriate parameter name and value for any parameters required by your method. If left blank, the Web service's description page is shown, listing each public method available in the .asmx file. (Optional)
Apppath
webservicename.asmx Methodname
Parameter
Note:
The Web service method name in this syntax is case sensitive, but the server, project, and Web service names are not.
5. For example, suppose the StockServices Web service from the preceding procedure contains a Web service method called GetQuote; the Web service method accepts a stock symbol as a parameter, returning the price as a double-precision floating-point number. Enter the following HTTP-GET request in the browser's address bar to test this method:
6. 7.
http://<servername>/apppath/StockServices.asmx/GetStockQuote?tickerName=MSFT The server sends a response containing an XML document, which is displayed in the browser. For the GetQuote example, the XML has the current price of the stock you request. The result might look like the following:
<%@ WebService Language="C#" Class="Math" %> using System.Web.Services; public class Math : WebService { [ WebMethod ] public int Add(int num1, int num2) { return num1+num2; } [ WebMethod ] public int Subtract(int num1, int num2) { return num1-num2; } }
VB
<%@ WebService Language="VB" Class="Math" %> Imports System.Web.Services Public Class Math Inherits WebService <WebMethod> _ Public Function Add(num1 As Integer, num2 As Integer) As Integer Return num1 + num2 End Function <WebMethod> _ Public Function Subtract(num1 As Integer, num2 As Integer) As Integer Return num1 - num2 End Function End Class Create an HTML page with a form that has its method attribute set to POST. Use the following format:
2.
3. 4. 5. 6. 7.
<form action='http://www.contoso.com/math.asmx/Subtract'> <input type="text" size="5" name='num1'\"></td> <input type="text" size="5" name='num2'\"></td> = <input type=submit value="Subtract"> </td> </form>
method=POST
Parameter
Value
Method
POST. If you want to test your Web service using HTTP-POST, use POST. URL to the Web service method. In the previous example, math.asmx is the Web service and Subtract is the Web service method. For each parameter of the Web service method, create input tags with the type attribute set to "text". This allows you to type a parameter value in the text input control. The name of the Web service method parameter. Add as many text input controls on the form as there are parameters in the Web service method. For instance, if a Web service method has three parameters, three text input controls are needed that each have their name attribute set to the name of the parameter. Add a submit button so you can post the data back to the Web service method.
Action
type="text"
name='num1'
type=submit
8. 9.
Access a Web browser and enter the URL for the HTML document you created in the previous step. The HTML document created in the previous step is displayed. Enter the appropriate values for the Web service method in the text boxes and click the submit button. For example, if you entered 6 and then 3 into the two text boxes for the example's Subtract Web service method, the following result is returned:
Proxy. A downloaded discovery document contains information about the existence of other Web services that might reside on a different Web server. For details about the contents of a discovery document, see How to: Enable Discovery for XML Web Services. You can use the Web Services Discovery tool (Disco.exe) from a command prompt to perform Web service discovery on a URL.
/password:mypwd
/domain:mydomain
Note:
The arguments listed are the commonly used arguments for Disco.exe. For the full syntax of Disco.exe, see Web Services Discovery Tool (Disco.exe).
Parameter
Value
http://www.contoso.com/my.disco
The URL to enact the discovery process on. The location to create the file containing the discovery results. The default value is the current directory. (Optional) The user name to use when connecting to a Web server that requires authentication. (Optional) The password to use when connecting to a Web server that requires authentication. (Optional) The domain to use when connecting to a Web server that requires authentication. (Optional)
/out:location
/username:user
/password:mypwd
/domain:mydomain
A Web service client is any component or application that communicates with a Web service using SOAP messages, or a comparable messaging protocol. A Web service client can be a traditional client application. A client can also be another Web application. (In this situation, the Web application would consume the XML within the SOAP message, format it, and send the result back to an ultimate client perhaps a Web browser.) Create a Web service client by following these basic steps: 1. 2. 3. 4. Create a proxy class for the Web service. Reference the proxy class in the client code. Create an instance of the proxy class in the client code. If anonymous access has been disabled for the Web application hosting the Web service, set the Credentials property of the proxy class. Call the method on the proxy class that corresponds to the Web service method with which you want to communicate.
5.
For most clients, these steps differ only in how the proxy class is referenced and how the Web service client is deployed.
Note:
If you create a Web service client using the following topics and your proxy fails with the exception text, "The request failed with HTTP status 401: Access Denied," there is a good chance that you have not yet passed your security credentials to the credential cache on the proxy. For details on passing the correct credential information to the service, see How to: Configure an XML Web Service for Windows Authentication.
service client can then invoke methods of the proxy class, which communicate with a Web service over the network by processing the SOAP messages sent to and from the Web service. Because the proxy class communicates with the Web service across the Internet, it is a good idea to verify that the Url property of the proxy class references a trusted destination. By default, the proxy class uses SOAP over HTTP to communicate with the Web service. However, Wsdl.exe can generate proxy classes to communicate with a Web service, using either the HTTP-GET protocol or HTTP-POST protocol. To specify that the proxy class should use HTTP-GET or HTTP-POST, provide the /protocol switch to the Wsdl.exe tool, as described in the following table.
Wsdl /language:language /protocol:protocol /namespace:myNameSpace /out:filename /username:username /password:password /domain:domain <url or path>
Note:
The arguments listed here are the commonly used arguments for Wsdl.exe. For the full syntax of Wsdl.exe, see Web Language Tool (Wsdl.exe).
Parameter
Value
<url or path>
A URL or path to a service descrip Language). If you specify a file, supply a file th mywebservice.wsdl If you specify a URL, the URL mu created using ASP.NET, you can re service. For example, http://www.contoso.com/MyWebS
/language:language
The language the proxy class is gen Basic .NET, and JScript .NET, resp
/protocol:protocol
/namespace:myNameSpace /out:filename
The name of the file to create that c implements the Web service. (Opti
// Declare MyWebMethod in the Web service. MyWebMethod(out string outStr, string inStr) // This is the corresponding MyWebMethod in the proxy class. MyWebMethod(string inStr, out string outStr). In some cases, the proxy class generated by Wsdl.exe uses a least common denominator approach for casting objects to a type specified in a service description. As a result, the generated type in the proxy class might not be what the developer wants or expects. For example, when Wsdl.exe encounters an ArrayList type in a service description, it creates an Object array in the generated proxy class. To ensure the correct object type casts, open the file that contains the generated proxy class and change any incorrect object types to the expected object type.
Warning: Ignoring duplicate service description with TargetNamespace=<schema namespace> from location <schema URI>. Indicates the TargetNamespace for two or more of the supplied service descriptions are identical. As the TargetNamespace is supposed to be a unique identifier for a particular XML document,
which in this case is a service description, Wsdl.exe assumes that the two service descriptions are identical. In doing so, Wsdl.exe builds just one proxy class for one of the service descriptions. If this is not your intended result, you can change this. For service descriptions that represent Web services created using ASP.NET, you can apply a WebService attribute that specifies a unique Namespace property to the class that implements the Web service. That Namespace property is then used as the TargetNamespace in the service description to uniquely identify the Web service.
Warning: Ignoring duplicate schema with TargetNamespace=<schema Namespace> from location <schema URI>. Indicates the TargetNamespace for two or more XML schemas within the supplied service descriptions are identical. Because the TargetNamespace is supposed to be a unique identifier for a particular XML document, which in this case is the XML schema, Wsdl.exe assumes that the two XML schemas are identical. In doing so, Wsdl.exe builds a class for just one of the schemas. If this is not the intended result, theTargetNamespace for each XML schema must be changed to a unique URI. Exactly how the TargetNamespace is modified depends on the origin of the particular XML schemas.
SOAP Message Formatting Standard SOAP Message Formats Specified Using WSDL
The industry-standard Web Services Description Language (WSDL), which defines a schema for XML documents that in turn define Web services, offers two central SOAP formatting options. Both options are specified in XML elements not in the primary WSDL namespace, http://schemas.xmlsoap.org/wsdl/, but rather in the namespace http://schemas.xmlsoap.org/wsdl/soap/. This secondary namespace commits a Web service to the SOAP protocol.
Style: For the child element, and possibly the grandchildren, of the Body element in a SOAP message. This is specified as the style attribute of a binding WSDL element (typically) or an operation element. Use: For the Web service method parameters, or a return value, that appear at the next level down. This is specified as the use attribute of a body element.
For details on the SOAP specification, see the W3C Web site (http://www.w3.org/TR/SOAP). Details on the WSDL specification can also be found at the W3C Web site ().
RPC: Parameters, or a return value, are automatically placed in a parent element whose own parent is the SOAP Body element. The parameters or return value appear without namespace qualification. This scheme is described in Section 7 of the SOAP 1.1 specification. Specified style="rpc". For a SOAP request, the element below the SOAP Body is named after a WSDL operation element, which corresponds to Web service method. Each element within that element represents a parameter and is named after its respective parameter. For a SOAP response, the name of the element below the SOAP Body is the operation name with Response appended. The name of the element underneath, representing the return value, is the operation name but with the suffix Return.
Document: The contents of the SOAP Body element are fully specified in the WSDL as XML elements defined in an XML Schema definition. The XML schema is specified in, or imported into, the WSDL document. The WSDL is oblivious to parameters and return values; it only deals with XML documents. The developer, or preferably the Web services infrastructure, takes care of how parameters and return values translate into XML Schema elements and types. Specified style="document". The top-level XML elements are specified as message parts -- part elements that are defined in a message element and point to XSD element declarations. Normally, there is no more than one part, so that the SOAPBody contents are truly an XML document, although WSDL itself doesn't prohibit multiple elements.
WSDL allows two values for the use attribute that controls parameter, and return value, formatting:
Encoded: Data is formatted according to a scheme is described in Section 5 of the SOAP 1.1 specification. SOAP encoding uses a subset of the XML Schema for binding between XML documents and the data they represent. SOAP encoding also employs references for elements that appear multiple times in a document. Specified use="encoded". Literal: Data is formatted literally according to XML Schema definitions specified in, or imported into, the WSDL document. Specified use="literal".
Instead of handcrafting a WSDL document, a developer that creates a Web service for ASP.NET can specify these SOAP formats by applying attributes to either individual Web service methods or entire Web service classes. If a developer does not specify these attributes, the default SOAP formats are used. If you are developing a Web service based on an existing WSDL document, you can run the Wsdl.exe tool with the /server option to generate an abstract Web service class that has the appropriate attribute values automatically set. Without the /server option, Wsdl.exe produces a client proxy class that sets the relevant SOAP formatting attributes to the appropriate values to communicate with the Web service described by the input WSDL document. A client proxy class uses most of the same attributes that can be specified on the server. Normally, a developer does not need to manually add or edit these attributes in the client proxy class because normally the client is generated by Wsdl.exe to ensure that it complies with the service contract specified by the WSDL document.
The following table outlines the formatting choices supported by Web services and clients created using ASP.NET and the .NET Framework, along with the attributes that accomplish each specific combination. The attributes with a Service suffix can be applied to a class that implements a Web service (not a client proxy class) to set the default formatting style for Web service methods within the class. The attributes with a Method suffix can be applied either to a Web service method or to a method in a client proxy class that calls a Web service method. The details of each combination are covered in the following paragraphs.
Parame ter formatt ing (use) SOAP Body formatting (style) for RPC-based SOAP messages according to SOAP 1.1 Section 7s
for
Literal based on an XSD schema for each parame ter Encode d SOAP 1.1 Section 5 encodi ng rules
Note:
The actual attribute names use the Attribute suffix. In the source code, the names can be abbreviated, as shown in the preceding table.
Document style can be explicitly specified by applying the SoapDocumentMethodAttribute attribute to a Web service method or client proxy method, or by applying the SoapDocumentServiceAttribute attribute to a Web service class. RPC style can be explicitly specified by applying the SoapRpcMethodAttribute attribute to a Web service method or client proxy method, or by applying the SoapRpcServiceAttribute attribute to a Web service class. For a service, a method-level attribute overrides a class-level attribute. These same attributes play a role in determining parameter and return value formatting, as described later in this topic. They also play a role in determining whether a "wrapper" element is automatically generated at runtime to contain the parameters or return value. For more information, see How to: Control Whether Web Service Method Parameters Are Enclosed in an Extra Element. For more information about how to apply these attributes, see How to: Control the Overall SOAP Body Formatting for a Web Service Method.
With the ParameterStyle property set to SoapParameterStyle.Bare, the developer is able to specify a message that has multiple partsliterally multiple XML elements that appear as children of the SOAP Body element. Technically, multiple elements do not constitute an XML document because a document must have a single root. Therefore, the recommended practice in the Web services community is to use a single message part with document-style services. Each Web service method must use not its intended signature but a signature where an object mapping to an XML document is the single parameter and another object mapping to an XML document is the return value. A developer must write the code to extract or package the true parameters or return values. Therefore, normally it is sufficient for a developer to set the ParameterStyle property to SoapParameterStyle.Wrapped and let the Web services infrastructure place parameters and return values into XML documents. For more information about how to set the ParameterStyle property, see How to: Control Whether Web Service Method Parameters Are Enclosed in an Extra Element.
Customizing Serialization
SOAP
Messages
with
XML
Besides specifying style, use, and whether to insert a wrapper element, you can directly customize the XML in a SOAP message with XML serialization. By default, the .NET Framework's Web services infrastructure automatically serializes public fields and properties into XML messages. The System.Xml.Serialization namespace includes numerous attributes for manipulating XML. The following code example shows how some of these attributes can be applied directly to Web service method parameters or return values.
C# VB
[SoapDocumentMethod( "http://www.contoso.com/DocumentBareLiteral", Use=SoapBindingUse.Literal, ParameterStyle=SoapParameterStyle.Bare)] [return: XmlElement(Namespace="http://www.contoso.com", IsNullable=true)] public string DocumentBareLiteral( [XmlElement(Namespace="http://www.contoso.com", IsNullable=true)]
Some commonly used attributes are listed as follows, their names appear without the Attribute suffix, which can be omitted:
XmlElement: Specifies that a public field or property be serialized as an XML element. This is the default attribute for serializing non-array public fields and properties. When the XmlElement attribute is applied to public fields and properties of an array type attribute, the array is serialized with other members, without a special parent element. XmlAttribute: Specifies that a public field or property be serialized as an XML attribute of the element that represents the containing type. XmlArray: Specifies that a public field of an array type be serialized with a special parent element. This is the default attribute for serializing public fields and properties of an array type. XmlArrayItem: Used in combination with the XmlArray attribute to control the array elements. XmlIgnore: Specifies that a public field or property not be serialized.
The preceding attributes, except for XmlIgnore, can also be used to specify an element or attribute name besides the default, which is the member name for non-array members. They can also be used to specify a namespace for a particular element. Usually, a Web service does not mix namespaces and a namespace is required to be specified only at the class level, using an attribute like WebService or WebServiceBinding. For more information, see , see System.Xml.Serialization.
Note:
For RPC or encoded Web services, using RPC style with SOAP encoding, the use of XML serialization is restricted. P Also, SOAP 1.1 Section 5 encoding, combined with document or RPC style, prohibits the binding of data to XML attrib
Note:
If an abstract service class or client proxy class is generated from a WSDL document, the correct System.Xml.Seria that are defined under the WSDL types element, whether they appear inline or are imported.
Note:
Using Nullable types in a Web service results in WSDL that contains the "nillable=true" setting for the type. However, when N not reflected in the resulting WSDL in the following cases: 1) When RPC-based SOAP messages are used, and 2) When Docum
As you can see, the .NET Framework serializes and deserializes XML during phases on both the Web service computer and the Web service client computer. A SOAP extension can be injected into the infrastructure to inspect or modify the SOAP messages before and after each of these serialize and deserialize phases. For instance, an encryption SOAP extension might encrypt the XML portion of the SOAP message after the .NET Framework serializes the client's arguments, and then decrypt the SOAP message on the Web server before the .NET Framework deserializes the SOAP message. These phases, where a SOAP extension might inspect or modify the SOAP message, are defined in the SoapMessageStage enumeration. In this case, the SOAP extension is encrypting in the AfterSerialize stage and decrypting in the BeforeDeserialize stage. Typically, when a SOAP extension modifies the contents of a SOAP message, the modifications must be done on both the client and the server. That is, if a SOAP extension were to run on the client and encrypt the SOAP message, a corresponding SOAP extension must decrypt the SOAP message on the server. If the SOAP message is not decrypted, then the ASP.NET infrastructure cannot deserialize the SOAP message into an object. Of course, a SOAP extension that does not modify the SOAP message, such as a SOAP extension that simply logs the SOAP messages, can run on only the client or server. In this case, the recipient receives the same SOAP message it would have if a SOAP extension were not running and the ASP.NET infrastructure can deserialize the SOAP message. Also, if the SOAP extension does not modify the SOAP in a way that makes deserialization impossible, the SOAP extension does not need to run on both the client and server.
ChainStream, a virtual method GetInitializer, an abstract method with two signatures Initialize, an abstract method ProcessMessage, an abstract method
How to implement these methods is explained in the step-by-step topic Walkthrough: Altering the SOAP Message Using SOAP Extensions. The ChainStream method is passed a Stream object and returns a Stream object. As the SOAP extension executes during each SoapMessageStage and modifies the SOAP message, a SOAP extension should read from theStream passed into ChainStream and write to the Stream returned from ChainStream. Therefore, it is important within the ChainStream method to assign both Stream references to member variables. The class deriving from SoapExtension uses the GetInitializer and Initialize methods to initialize internal data, based on the Web service or Web service method it is applied to. For instance, a SOAP extension that logs the SOAP message sent to and from a Web service method might initialize the name of a file to save the logging information (based on the name of the Web service or the Web service method the SOAP extension is running with). At what point the Web services infrastructure calls the GetInitializer method and what parameters are passed to the method depend on how the SOAP extension is configured, as follows:
If the SOAP extension is configured using an attribute, GetInitializer is called by the Web services infrastructure the first time a Web service method is accessed. If the SOAP extension is configured in a configuration file, GetInitializer is called by the Web services infrastructure only the first time the entire Web service is accessed.
The Web services infrastructure caches the object that the GetInitializer method returns. Then each time the SOAP extension runs with that Web service or Web service method, the infrastructure passes the initializer object to the Initialize method. Actual extended processing beyond the standard SOAP processing is performed by the ProcessMessage method. Each time the Web services infrastructure calls ProcessMessage, it passes (as an argument) an instance of a class derived from SoapMessage that contains information about the SOAP message at that particular stage. If the SOAP extension is running with a Web service, then a SoapServerMessage object is passed in. If the SOAP extension is running with a Web service client, then a SoapClientMessage object is passed in.
4. 5. 6. 7. 8. 9.
4. 5. 6. 7. 8. 9.
10. The Web service method executes its code, eventually setting the return value and any out parameters. 11. The ProcessMessage method is invoked with SoapMessageStage set to BeforeSerialize. 12. ASP.NET on the Web server serializes the return value and out parameters into XML. 13. The ProcessMessage method is invoked with SoapMessageStage set to AfterSerialize. 14. ASP.NET sends the SOAP response message over the network back to the Web service client.
<configuration> <system.web> <webServices> <soapExtensionTypes> <add type="Contoso.MySoapExtension, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0"/> </soapExtensionTypes> </webServices> </system.web> </configuration> Second, you can create a custom attribute that is applied to a Web service method. To create the custom attribute, create a class that derives from SoapExtensionAttribute. For details about creating a custom attribute, seeHow to: Implement a SOAP Extension. For more information about creating custom attributes, see Creating Custom Attributes.
Note:
When implementing a SOAP extension, there is a possibility that a Denial of Service (DOS) attack could be attempted if your extension uses an XmlTextReader to read the data stream. One way of
preventing such an attack is to ensure that the ProhibitDtd property is set to true.
Highest priority group: SOAP extensions configured using a configuration file with a group setting of 0. Medium priority group: SOAP extensions configured using an attribute. Lowest priority group: SOAP extensions configured using a configuration file with a group setting of 1.
The following code example is a configuration file that specifies that the Logger.LoggerExtension SOAP extension runs within the relative priority group 0 and has a priority of 1.
<configuration> <system.web> <webServices> <soapExtensionTypes> <add type="Logger.LoggerExtension,logger" priority="1" group="0" /> </soapExtensionTypes> </webServices> </system.web> </configuration>
How to: Control the Overall SOAP Body Formatting for a Web Service Method
For overall SOAP body formatting, or style, the Web Services Description Language (WSDL) provides two choices: RPC and document. The .NET Framework controls these choices in code using attributes.
[SoapDocumentMethod("http://www.contoso.com/DocumentWrappedLiteral", RequestNamespace="http://www.contoso.com", ResponseNamespace="http://www.contoso.com", Use=SoapBindingUse.Literal)] public string DocumentWrappedLiteral(Address MyAddress, bool useZipPlus4) {
VB
<SoapDocumentMethod("http://www.contoso.com/DocumentWrappedLiteral", _ RequestNamespace:="http://www.contoso.com", _ ResponseNamespace:="http://www.contoso.com", _ Use:=SoapBindingUse.Literal)> _ Public Function DocumentWrappedLiteral(ByVal MyAddress As Address, _ ByVal useZipPlus4 As Boolean)As String With the Document formatting style, an XSD schema is defined within the service description that defines both the SOAP request and SOAP response. The following is an excerpt from the service description for the SOAP request for the DocumentWrappedLiteral Web service method. Because the first parameter to the DocumentWrappedLiteral Web service method is a class, and the Literal parameter formatting style was specified, an XSD schema is created for the address type. <s:element name="DocumentWrappedLiteral"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="MyAddress" nillable="true" type="s0:Address" /> <s:element minOccurs="1" maxOccurs="1" name="useZipPlus4" type="s:boolean" /> </s:sequence> </s:complexType> </s:element> <s:complexType name="Address"> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="Street" nillable="true" type="s:string" /> <s:element minOccurs="1" maxOccurs="1" name="City" nillable="true" type="s:string" /> <s:element minOccurs="1" maxOccurs="1" name="Zip" nillable="true" type="s:string" />
</s:sequence> </s:complexType> With the XSD schema that is defined in the service description, the XML portion of the SOAP request to the DocumentWrappedLiteral Service method follows. Note that the XML elements beneath the Bodyelement in the SOAP request match the elements defined in the XSD schema. <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <DocumentWrappedLiteral xmlns="http://www.contoso.com"> <MyAddress> <Street>string</Street> <City>string</City> <Zip>string</Zip> </MyAddress> <useZipPlus4>boolean</useZipPlus4> </DocumentWrappedLiteral> </soap:Body> </soap:Envelope>
VB
<SoapRpcMethodAttribute("http://www.contoso.com/Rpc", _ RequestNamespace:="http://www.contoso.com", _ ResponseNamespace:="http://www.contoso.com")> _ Public Function Rpc(ByVal address As Address, _ ByVal useZipPlus4 As Boolean) As Address An XSD schema is not strictly defined in the service description for either the SOAP request or SOAP response to the Rpc method in the previous example, but rather just the parts that comprise them. Therefore, look at the SOAP request for the Rpc method, noting that the parameters are encapsulated inside one element and they are encoded using the Encoded parameter formatting. <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.contoso.com" xmlns:tnsTypes="http://www.contoso.com/encodedTypes"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <tns:Rpc> <address href="#1" /> <useZipPlus4>boolean</useZipPlus4> </tns:Rpc> <tnsTypes:Address id="1"> <Street id="2">string</Street> <City id="3">string</City> <Zip id="4">string</Zip> </tnsTypes:Address> </soap:Body> </soap:Envelope>
Note:
If an XML Web services sample has been developed using Visual Studio, a tilde ('~') can appear in a directive attribut this usage, see ASP.NET Web Site Paths
In This Section
Term Definition
Defines XML Web service specific (.asmx file) attributes used by the ASP.NET parser and compiler.
Attributes
Term Definition
Name
Note: The assembly name does not include a file name extension.
Src The path to a source file to dynamically compile and link against.
Note: You cannot include a Name and a Src attribute in the same @ Assembly directive. If you want to than one directive on the page.
Remarks
The compiler references the assembly at compile time, allowing early binding. Once compilation of the XML Web service is complete, the assembly is dyamically loaded into the application domain when it changes, allowing late binding. Assemblies that reside in your Web application's \bin directory are automatically linked to XML Web services in that application. Such assemblies do not require the @ Assembly directive.
Note:
The path to the assembly or source file in an @ Assembly directive must be a relative path to the Web applic service.
Example
The following code fragment uses two @ Assembly directives, the first to link to MyAssembly, a user-defined assembly, the second to MySource.vb, a Visual Basic source file located in the src folder beneath the directory of the Web application hosting the XML Web service. <%@ Assembly Name="MyAssembly" %> <%@ Assembly Src="src/MySource.vb" %>
Attributes
Term Definition
Class
Specifies the class implementing the XML Web service that is automatically compiled the first time the XML Web service is accessed after changes. This value can be any valid class name residing in either the same file as the WebService directive or within a separate file. If the class resides in a separate file, it must be placed in the \Bin directory underneath the Web application where the XML Web service resides. This attribute is required for the XML Web service to compile.
CodeBehind
Specifies the source file implementing the XML Web service, when the class implementing the XML Web service does not reside in the same file and has not been compiled into an assembly and placed in the \Bin directory.
Debug
Indicates whether the XML Web service should be compiled with debug symbols. true if the XML Web service should be compiled with debug symbols; otherwise, false.
Language
Specifies the language used when compiling all inline code within the XML Web service file (.asmx). The values can represent any .NET-supported language, including C#, VB, and JS, which refer to C#, Visual Basic .NET, and JScript .NET, respectively.
Introduction
The transaction support for XML Web services created using ASP.NET is based on the same distributed transaction model found in the COM+ Services. This model is based on declaring attributes to decide whether an object participates in a transaction, rather than writing specific code to commit / roll back a transaction. Once an XML Web service method is marked to participate in a transaction, it will automatically execute within the scope of a transaction. You can control an object's transactional behavior by setting a transaction attribute value on XML Web service method. The attribute value, in turn, determines the transactional behavior of the instantiated object. Thus, based on the declared attribute value, an object will automatically participate in an existing or ongoing transaction, be the root of a new transaction, or never participate in a transaction at all. In an XML Web service created using ASP.NET, you can declare the web methods transactional behavior by setting theTransactionOption property of the WebMethod attribute applied to an XML Web service method. If an exception is thrown while the XML Web service method is executing, the transaction is automatically aborted; conversely, if no exception occurs, the transaction is automatically committed. Lets look at the TransactionOption enumeration: Disabled: Ignores any transaction in the current context. NotSupported: Creates the component in a context with no governing transaction. Required: Shares a transaction if one exists, and creates a new transaction if necessary. RequiresNew: Creates the component with a new transaction, regardless of the state of the current context. Supported: Shares a transaction, if one exists.
2.
3.
4.
Declare an XML Web service method, setting the TransactionOption property of the WebMethod attribute toTransactionOption.RequiresNew.
Collapse | Copy Code
The following code example shows an XML Web service that exposes a single XML Web service method, calledDBOperations. This XML Web service method performs a database operation that is scoped within a transaction. If the database operation does throw an exception, the transaction is automatically stopped; otherwise, the transaction is automatically committed.
Collapse | Copy Code
<%@ WebService Language="C#" Class=" DBOperations " %> <%@ Assembly name="System.EnterpriseServices" %> using using using using using System; System.Data; System.Data.SqlClient; System.Web.Services; System.EnterpriseServices;
public class DBOperations : WebService { [ WebMethod(TransactionOption=TransactionOption.RequiresNew)] public int DeleteAuthor(string lastName) { String delCmdSql = "DELETE FROM authors WHERE au_lname='" + lastName + "'" ; String exceptionCausingCmdSQL = "DELETE FROM NonExistingTable WHERE au_lname='" + lastName + "'" ; SqlConnection myCon = new SqlConnection("user id=sa;database=pubs;server=myserver"); SqlCommand delCmd = new SqlCommand(delCmdSQL,myCon); SqlCommand exceptionCausingCmd = new SqlCommand(exceptionCausingCmdSQL,myCon); // This command should execute properly. delCmd.Connection.Open(); delCmd.ExecuteNonQuery(); // This command results in an exception, so the first command is // automatically rolled back. int cmdResult = exceptionCausingCmd.ExecuteNonQuery(); myCon.Close(); return cmdResult; } }
Server1. WService2 Service2 = new Server1. WService2 (); Server2.WService3 Service3 = new Server2. WService3 (); Service2.WMethod2(); Service3.WMethod3(); }
[WebMethod(TransactionOption.Required)] public void WMethod2 () { //Code to update a row in a table } [WebMethod(TransactionOption.Required)] public void WMethod3 () { //Code to update a row in another table }
Develop a client application named myApp that consumes Wmethod1 of WService1. Run myApp. While WMethod1 is calling WMethod3, close myApp. What is the most likely result? What do you expect? A roll back of the updates made by WMethod2 and WMethod3? No, the Answer is Wmethod1 continues processing, and whatever updates that are made by the WMethod2 andWMethod3 persists, because transactions do not flow across XML Web service methods. XML Web service methods can only participate in a transaction as the root of a new transaction. XML Web service methods that call other XML Web service methods participate in different transactions, as transactions do not flow across XML Web service methods.