A metadata exchange (MEX) endpoint is a special
endpoint added to your service that will expose your WSDL and supporting
schemas required to call your service. MEX conforms to the
WS-MetadataExchange standard. Once a MEX endpoint has been added to your
service, consumers can use the Add Service Reference feature of Visual
Studio 2008 to automatically create the proxy object required to call
your service.
1. Publishing MEX Metadata
Publishing metadata is easy through the BizTalk WCF Service Publishing Wizard. On the WCF Service Type screen, there is a check box for enabling metadata endpoints. When
you select this option, the wizard adds some information to the
generated Web. config file. The following is an entire file, with the
additional information highlighted in bold:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviorConfiguration">
<serviceDebug httpHelpPageEnabled="true"
httpsHelpPageEnabled="false"
includeExceptionDetailInFaults="false" />
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Microsoft.BizTalk.Adapter.Wcf.Runtime.
BizTalkServiceInstance"
behaviorConfiguration="ServiceBehaviorConfiguration">
<endpoint name="HttpMexEndpoint" address="mex"
binding="mexHttpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
There are three additional elements in this file:
A serviceMetadata tag that allows HTTP GET access to your WSDL. This is the common way developers will access your metadata.
A behaviorConfiguration tag in the service
element that attaches the behavior to the service. This tag triggers
the ability to use HTTP GET access to the specified service.
A new endpoint name="HttpMexEndpoint"
tag that provides standard WS-MetadataExchange access to the WSDL.
Notice the MEX endpoint must conform to standard address, binding, and
contracts (ABCs) of WCF, but the contract implemented is IMetadataExchange and not your custom service.
2. Customizing the SOAP Address Location
Adding the default MEX output
is easy to do and works just fine. But sometimes it is necessary modify
the default output. This need to modify is quite common in scenarios
where your service is located behind a network load balancer such as
Windows Network Load Balancing because the autogenerated WSDL includes
the computer name, as shown in Figure 1.
In Figure 1,
the computer name is bts2009rc. A server-specific name like that is
fine if we're running on one server, but when running in a web farm,
each server would render a different name. When the consumer uses the
Add Service Reference feature of Visual Studio 2008, the service would
default to the computer name that rendered the MEX and not the virtual
server name of the web farm.
Even though the default
endpoint address would be tied to the computer name, the default can be
easily overwritten in the application's configuration file. But
nevertheless, it's not good practice to expose your server names to an
outside consumer, especially if your service is public-facing. Exposing
your server names publicly provides environment configuration details
that should be kept away from possible intruders.
WCF will automatically use the
IIS metabase server bindings of the web site to dynamically render the
address of the service. Therefore, in order to modify the default
behavior, the metabase needs to be updated to include the DNS name you'd
like to use. To do this, run the following at the command prompt:
cscript //nologo %systemdrive%\inetpub\adminscripts\adsutil.vbs set
W3SVC/1/ServerBindings ":80:www.myserverfarm.com"
Alternatively, the serviceMetadata element of a WCF endpoint behavior can be modified to use an external WSDL file. Point the externalMetadataLocation
attribute to an external file containing your service's WSDL. This
allows you to have complete control of your WSDL but does require you to
keep it in sync with the functionality of your service.
|
|
Once completed, run IISRESET, or recycle the application pool to allow the change to be in effect, as shown in Figure 2.
3. Customizing MEX with a WCF Behavior
Adding content to the MEX output is easy thanks to WCF's highly extensible architecture.
Most organizations
don't customize the output, but they should. Public-facing services
should add copyright information, and all services should add some level
of summary help to their endpoints.
To customize the MEX output,
you'll need to create a class that inherits from
BehaviorExtensionElement and implements the IWsdlExportExtension and
IEndpointBehavior interfaces. This work sounds complex, but it's not
that bad. The following is a sample class that implements all these
objects and interfaces and exposes a property called CopyrightText allowing for the text to be configurable in the application's configuration file:
public class WSDLDocumentor : BehaviorExtensionElement,
IWsdlExportExtension,
IEndpointBehavior
{
public WSDLDocumentor() { }
public WSDLDocumentor(string CopyrightText)
{
this.CopyrightText = CopyrightText;
}
#region IWsdlExportExtension Members
public void ExportContract(WsdlExporter exporter,
WsdlContractConversionContext context)
{}
public void ExportEndpoint(WsdlExporter exporter,
WsdlEndpointConversionContext context)
{
// Must set documentation to empty string or XmlDocument
// will be null.
context.WsdlPort.Documentation = string.Empty;
XmlDocument summary =
context.WsdlPort.DocumentationElement.OwnerDocument;
XmlElement copyright = summary.CreateElement("Copyright");
copyright.InnerText = CopyrightText;
context.WsdlPort.DocumentationElement.AppendChild(copyright);
}
#endregion
[ConfigurationProperty("copyrightText", DefaultValue = "",
IsRequired = true)]
public string CopyrightText
{
get { return (string)base["copyrightText"]; }
set { base["copyrightText"] = value; }
}
private ConfigurationPropertyCollection configurationProperties;
protected override ConfigurationPropertyCollection Properties
{
get
{
if (configurationProperties == null)
{
configurationProperties =
new ConfigurationPropertyCollection();
configurationProperties.Add(
new ConfigurationProperty("copyrightText",
typeof(string), string.Empty,
ConfigurationPropertyOptions.IsRequired));
}
return configurationProperties;
}
}
public override System.Type BehaviorType
{
get { return typeof(WSDLDocumentor); }
}
protected override object CreateBehavior()
{
return new WSDLDocumentor(CopyrightText);
}
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{}
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{}
public void Validate(ServiceEndpoint endpoint)
{}
#endregion
}
After compiling this class, the
next step is to add content to your Web.config file to hook in your
custom behavior. For example, notice the bold lines in the following
configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="WSDLCopyright"
type="ProBizTalk.WSDLExtension.WSDLDocumentor,
ProBizTalk.WSDLExtension, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<bindings>
<basicHttpBinding>
<binding name="SayHelloBindingConfig">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="CopyrightBehavior">
<WSDLCopyright
copyrightText="Copyright Pro BizTalk 2009!" />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="CertService.SayHello">
<endpoint address=""
behaviorConfiguration="CopyrightBehavior"
binding="basicHttpBinding"
bindingConfiguration="SayHelloBindingConfig"
contract="CertService.ISayHello" />
</service>
</services>
</system.serviceModel>
</configuration>
You can also use the WCF Configuration Editor as part of the Windows SDK to add the additional configuration settings.
|
|
Be sure to reference the
custom behavior DLL in your solution and build! When viewing your WSDL,
you should notice text similar to the bold code in the following
example:
<wsdl:service name="SayHello">
<wsdl:port name="BasicHttpBinding_ISayHello"
binding="tns:BasicHttpBinding_ISayHello">
<wsdl:documentation>
<Copyright>Copyright Pro BizTalk 2009!</Copyright>
</wsdl:documentation>
<soap:address location="http://bts2009rc/SayHello" />
</wsdl:port>
</wsdl:service>