Visual Studio Hacks [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Visual Studio Hacks [Electronic resources] - نسخه متنی

Andrew Lockhart

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Hack 99. Generate Web Services Code

If you're a fan of
contract-driven development, you can take control of the WSDL
chicken-egg situation.

The . NET Framework makes it extremely easy to
create and deploy Web Services; on top of that, Visual Studio makes
it even easier still. You can add an .asmx file
to your project, add a couple of methods, then build your solution,
and you have just written a Web Service. This process is deceptively
simple though, since a lot of things are going on in the background,
including the generation of a WSDL on the server side and a client
proxy on the client side. Visual Studio quietly handles all of this
for you, which is not always a good thing, since Visual Studio
assumes an XML-based RPC view of Web Services.

There is an idea in Web Services development called
contract-first or contract-driven
development. The basic idea is that, instead of letting Visual Studio
generate a WSDL file for you, you should write this WSDL file by hand
using a WSDL, XML, or text editor.


WSDL stands for Web Services Description Language. It is an XML
format used to describe a Web Service's interface by
defining its operations and message exchange patterns. The actual
messages are defined using a schema definition language like XSD.

Why would you want to write something by hand that Visual Studio will
usually generate for you? Letting Visual Studio generate your WSDL is
kind of like picking up a car on the lot and then letting the dealer
take care of the contract for you. Sure, you get the carbut
who knows what you are committed to. By writing your WSDL first, you
have complete control over how your Web Service will be seen to the
outside world, including its interface and data structures. This is
really just a continuation of the idea of contract-driven development
that has been around for yearsthe idea of first creating a
contract that your object will implement and that your clients will
consume.

Writing the WSDL to your Web Services can be a task in and of itself.
There are not really any great tools out there to help you along, and
the format takes a little bit of getting used to. And after you have
created your WSDL file, you then also need to create the client-side
proxy and the server-side Web Service code. This is where the
WSContractFirst add-in comes into play.

The
WSContractFirst
add-in was written by Christian Weyer in an effort to make
contract-first development easier. Using this add-in, you can
generate the code for client-side proxies and server-side Web
Services based on a WSDL file right inside of Visual Studio.

First, you will need to download and install the add-in from
http://www.thinktecture.com/resources/software/wscontractfirst/defaultl.


13.9.1. Generate Server-Side Interface


To demonstrate this tool, I am
going to start with a very simple WSDL file. This WSDL file defines a
simple service called UserValidation that includes
a single method, ValidateUser. This method accepts
an integer as its single parameter and returns a Boolean value,
specifying whether this is a valid user or not. Here is the WSDL file
I have created for this simple service:

<?xml version="1.0" encoding="utf-8"?>
<definitions
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:uv="http://namespaces.infozerk.com/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://namespaces.infozerk.com/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema elementFormDefault="qualified"
targetNamespace="http://namespaces.infozerk.com/">
<xsd:element name="ValidateUser">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1"
name="userID" type="xsd:int" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ValidateUserResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1"
name="ValidateUserResult" type="xsd:boolean" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="ValidateUserSoapIn">
<part name="parameters" element="uv:ValidateUser" />
</message>
<message name="ValidateUserSoapOut">
<part name="parameters" element="uv:ValidateUserResponse" />
</message>
<portType name="UserValidationSoap">
<operation name="ValidateUser">
<input message="uv:ValidateUserSoapIn" />
<output message="uv:ValidateUserSoapOut" />
</operation>
</portType>
<binding name="UserValidationSoap" type="uv:UserValidationSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="ValidateUser">
<soap:operation
soapAction="http:/namespaces.infozerk.com/ValidateUser"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="UserValidation">
<port name="UserValidationSoap" binding="uv:UserValidationSoap">
<soap:address
location="http://localhost/TestServices/UserValidation.asmx" />
</port>
</service>
</definitions>

After creating and saving this WSDL file, you then need to add it to
your project. Once it is in your project, you then simply need to
right-click on the WSDL file and you will see the option shown in
Figure 13-21.


Figure 13-21. ContractFirst menu


You could alternatively open the tool from the Tools menu and simply
point the tool to your WSDL file (including a URL); it does not have
to be a part of your project.

After choosing Generate Web Service Code, you will see the dialog
shown in Figure 13-22.


Figure 13-22. Code Generation Options

You can configure a number of things from this dialog. In this
example, I have chosen to generate a Service-Side Interface. I have
also renamed the file to better match the name of my service. After
you click Generate, the add-in will create two different files for
you. In this example, the first is named
UserValidation.cs and is an abstract class
defining the interface for the Web Service. The code for this file
can be seen here:

//------------------------------------------------------------
// <autogenerated code>
// This code was generated by a tool.
// Changes to this file may cause incorrect
// behavior and will be lost if
// the code is regenerated.
// </autogenerated code>
//------------------------------------------------------------
//
// This source code was auto-generated
// by WsContractFirst, Version=0.3.1.4244
namespace TestServices
{
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks></remarks>
[System.Web.Services.WebServiceBindingAttribute(
Name="UserValidationSoap",
Namespace="http://namespaces.infozerk.com/")]
public abstract class UserValidation : System.Web.Services.WebService
{
/// <remarks/>
[System.Web.Services.WebMethodAttribute( )]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"http:/namespaces.infozerk.com/ValidateUser",
RequestNamespace="http://namespaces.infozerk.com/",
ResponseNamespace="http://namespaces.infozerk.com/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public abstract bool ValidateUser(int userID);
}
}

ContractFirst then also generates an .asmx file
(including the corresponding .cs or
.vb file) that inherits from this abstract
class. This file can be seen here:

//------------------------------------------------------------
// <autogenerated code>
// This code was generated by a tool.
// Changes to this file may cause incorrect
// behavior and will be lost if
// the code is regenerated.
// </autogenerated code>
//------------------------------------------------------------
//
// This source code was auto-generated
// by WsContractFirst, Version=0.3.1.4244
namespace TestServices
{
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks/>
[System.Web.Services.WebServiceBindingAttribute(
Name="UserValidationSoap",
Namespace="http://namespaces.infozerk.com/")]
[System.Web.Services.WebServiceAttribute(
Namespace="http://namespaces.infozerk.com/")]
public class UserValidationImpl : UserValidation
{
/// <remarks/>
[System.Web.Services.WebMethodAttribute( )]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("
http:/namespaces.infozerk.com/ValidateUser",
RequestNamespace="http://namespaces.infozerk.com/",
ResponseNamespace="http://namespaces.infozerk.com/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public override bool ValidateUser(int userID)
{
return new bool( );
}
}
}

Notice that the tool simply adds a stub return into the
methodin this example, it will return a new
bool value. From here, your job would be to
implement this Web Service by writing the contents of this method,
doing the actual work of determining whether this is a valid
user.


13.9.2. Generate Client-Side Proxies


The
other way that Visual Studio makes working with
Web Services easy is the ability to add a web reference to a Web
Service. After adding a web reference, you can then access that Web
Service just as if it were a local class in your project, due to
Visual Studio generating a client-side proxy for you. This proxy is
simply a class that sits between your code and the actual Web
Service. The ContractFirst add-in can generate client-side proxies as
well, including some advanced options for code generation.

For this example, I will use the same WSDL file used for the
server-side example. After right-clicking on the WSDL file and
choosing Generate Web Service Code, you will now need to choose
Client-Side Proxy and specify a name of the proxy, as shown in Figure 13-23.


Figure 13-23. Client proxy creation

After you click Generate, the following code will be added to your
project as UserValidationProxy.cs:

//------------------------------------------------------------
// <autogenerated code>
// This code was generated by a tool.
// Changes to this file may cause incorrect
// behavior and will be lost if
// the code is regenerated.
// </autogenerated code>
//------------------------------------------------------------
//
// This source code was auto-generated
// by WsContractFirst, Version=0.3.1.4244
namespace TestServices
{
using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;
/// <remarks></remarks>
[System.Diagnostics.DebuggerStepThroughAttribute( )]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(
Name="UserValidationSoap",
Namespace="http://namespaces.infozerk.com/")]
public class UserValidation :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
/// <remarks/>
public UserValidation( )
{
this.Url = "http://localhost/TestServices/UserValidation.asmx";
}
/// <remark></remarks>
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("
http:/namespaces.infozerk.com/ValidateUser",
RequestNamespace="http://namespaces.infozerk.com/",
ResponseNamespace="http://namespaces.infozerk.com/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public bool ValidateUser(int userID)
{
object[ ] results =
this.Invoke("ValidateUser", new object[ ] {userID});
return ((bool)(results[0]));
}
/// <remarks/>
public System.IAsyncResult BeginValidateUser(
int userID,
System.AsyncCallback callback,
object asyncState)
{
return this.BeginInvoke("ValidateUser", new object[ ] {
userID}, callback, asyncState);
}
/// <remarks/>
public bool EndValidateUser(System.IAsyncResult asyncResult)
{
object[ ] results = this.EndInvoke(asyncResult);
return ((bool)(results[0]));
}
}
}

You will then be able to use this class from your project to
interface with the UserValidation Web Service.


13.9.3. ContractFirst Options


The ContractFirst add-in
also contains a number of options and
properties that can be used to customize the code that is generated
by the tool. These options are shown in Table 13-1.

Table 13-1. ContractFirst add-in options

Name


Description


Public properties


If checked, the add-in will use public properties instead of using
public fields.


Serializable classes


If checked, the add-in will create serializable data classes.


Collection


If checked, the add-in will generate collections to use instead of
arrays.


Endpoint URL configuration


If checked, endpoint configuration in the
.config file will be enabled.


Access to SOAP messages


If checked, read-only access to the SOAP messages will be added.


Validate messages


If checked, the add-in will enable XSD-based validation on the
incoming SOAP messages.

The ContractFirst add-in is a great tool if you have subscribed to
the idea of contract-first Web Service development. There are also
plans in the future to add a wizard that would help you create WSDL
files starting with an XSD file so you don't have to
worry about all the clumsy WSDL details. Instead, ContractFirst will
present you with a simple but powerful abstraction of it. Look for a
lot more from this tool in the future.


/ 172