TechNet
Products
IT Resources
Downloads
Training
Support
Products
Windows
Windows Server
System Center
Internet Explorer
Office
Office 365
Exchange Server
SQL Server
SharePoint Products
Lync
See all products »
Resources
Curah! curation service
Evaluation Center
Learning Resources
Microsoft Tech Companion App
Microsoft Technical Communities
Microsoft Virtual Academy
Script Center
Server and Tools Blogs
TechNet Blogs
TechNet Flash Newsletter
TechNet Gallery
TechNet Library
TechNet Magazine
TechNet Subscriptions
TechNet Video
TechNet Wiki
Windows Sysinternals
Virtual Labs
Solutions
Networking
Cloud and Datacenter
Security
Virtualization
Updates
Service Packs
Security Bulletins
Microsoft Update
Trials
Windows Server 2012 R2
System Center 2012 R2
Microsoft SQL Server 2012 SP1
Windows 8.1 Enterprise
See all trials »
Related Sites
Microsoft Download Center
TechNet Evaluation Center
Drivers
Windows Sysinternals
TechNet Gallery
Training
Training Catalog
Class Locator
Microsoft Virtual Academy
Free Windows Server 2012 courses
Free Windows 8 courses
SQL Server training
e-Learning overview
Certifications
Certification overview
MCSA: Windows 8
Windows Server Certification (MCSE)
Private Cloud Certification (MCSE)
SQL Server Certification (MCSE)
Other resources
TechNet Events
Second shot for certification
Born To Learn blog
Find technical communities in your area
Support options
For small and midsize businesses
For enterprises
For developers
For IT professionals
From partners
For technical support
Support offerings
For home users
More support
Microsoft Premier Online
Microsoft Fix It Center
TechNet Forums
MSDN Forums
Security Bulletins & Advisories
International support solutions
Log a support ticket
Not an IT pro?
Microsoft Customer Support
Microsoft Community Forums
Sign in
GD Bloggers
This is the blog site for Microsoft Global Delivery Communities focused in sharing the technical knowledge about devices, apps and cloud.
Visitor Globe
Large Visitor Globe
Search Blogs
Translate this page
Powered by
Microsoft® Translator
Tags
.NET
.NET Framework
Asp.Net
Biztalk
Configuration Manager
Exchange 2010
Hyper-V
Office 365
Operations Manager 2007 R2
Orchestrator 2012
SharePoint
SharePoint 2010
SharePoint 2010 troubleshooting
SharePoint 2013
SharePoint Foundation
SharePoint Troubleshooting
SQL Server
System Center 2012 Configuration Manager
Visual Studio
Windows 2008
Windows 7
Windows 8
Windows Azure
Windows Server 2012
Windows Server 8
Archive
Archives
December 2014
(1)
September 2014
(1)
June 2014
(5)
May 2014
(5)
April 2014
(3)
March 2014
(5)
February 2014
(3)
January 2014
(2)
December 2013
(7)
November 2013
(1)
October 2013
(2)
September 2013
(4)
August 2013
(2)
July 2013
(8)
June 2013
(10)
May 2013
(8)
April 2013
(6)
March 2013
(5)
February 2013
(12)
January 2013
(6)
December 2012
(4)
November 2012
(5)
October 2012
(5)
September 2012
(7)
August 2012
(3)
July 2012
(2)
June 2012
(3)
May 2012
(50)
April 2012
(10)
March 2012
(26)
February 2012
(8)
January 2012
(8)
December 2011
(12)
November 2011
(13)
October 2011
(7)
September 2011
(15)
August 2011
(12)
July 2011
(1)
June 2011
(6)
May 2011
(14)
April 2011
(5)
March 2011
(10)
February 2011
(11)
January 2011
(26)
December 2010
(38)
November 2010
(3)
Options
Home
About
Email Blog Author
Share this
RSS for posts
Atom
RSS for comments
Calling a WCF dynamically using a BizUnit Test Step
TechNet Blogs
»
GD Bloggers
»
Calling a WCF dynamically using a BizUnit Test Step
Calling a WCF dynamically using a BizUnit Test Step
Mohamed M Malek
17 Mar 2014 8:29 PM
Comments
0
Likes
Introduction
Using BizUnit to test complex testing cases is a common practice that we all have been using for a while now. This very useful library of testing steps provides ease in writing testing cases maintaining them and executing them. One common challenge commonly faced is how to call web services or more commonly how to call WCF services with a test step? There has been an out of the box test step to call SOAP 1.1 web services or WCF services based on BasicHttpBinding. Also there has been another custom one (
here
) to call a WCF with a common strongly typed contract. Of course there is always the good old HTTP step to invoke everything yourself and complicate your life.
In this post I will show you a custom test step that I have written to call a WCF dynamically without knowing anything about its contract. I am basing my code below on the out of the box Web service testing case already in BizUnit 4.0.
Solution
So like I said I wanted to call any WCF service with any binding and any contract without limitations. Also I wanted the flexibility to configure the service as I want using the app.config file.
So I have extracted the out of the box Web testing case and started to look into how to customize that test case. So here is what I did. I started with adding couple of properties for my testing case as below:
Property
Description
DataLoaderBase
RequestBody
This is the standard request body loader of the Web service call test step.
string
ServiceUrl
This is the URL of the WCF service you want to call.
string
Username
This is the username of the user to be added to the client credentials if the security mode is set to username. Else you should not specify this value.
string
Password
This is the password of the user to be added to the client credentials if the security mode is set to username. Else you should not specify this value.
string
BindingTypeName
This is the full type name of the binding required to be used when calling the WCF service.
MessageVersion
MsgVersion
This is the request message version to be used when calling the WCF service.
string
BindingConfigurationName
This is the name of the binding configuration in the app.config file.
Then I validated my test step as per the below method:
if
(
string
.IsNullOrEmpty(ServiceUrl))
{
throw
new
StepValidationException
(
"ServiceUrl may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(Action))
{
throw
new
StepValidationException
(
"Action may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(BindingTypeName))
{
throw
new
StepValidationException
(
"Binding type name may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(BindingConfigurationName))
{
throw
new
StepValidationException
(
"Binding configuration name may not be null or empty"
,
this
);
}
RequestBody.Validate(context);
And then I started working on the Execute method. First thing I wanted is to create the binding and I used the reflection to do this and I used the binding configuration in the configuration file to customize the binding as I want.
Type
bindingType =
Type
.GetType(BindingTypeName);
Binding
binding = (
Binding
)
Activator
.CreateInstance(bindingType, BindingConfigurationName);
Then once I have the binding I created the address as below:
var
epa =
new
EndpointAddress
(
new
Uri
(serviceUrl));
I also created a dummy WCF service contract so that it would be a generic contract for any WCF service as below:
///
<summary>
///
A dummy WCF interface that will be manipulated by the CallWebMethod above
///
</summary>
[
ServiceContract
]
interface
genericContract
{
[
OperationContract
(Action =
"*"
, ReplyAction =
"*"
)]
Message
Invoke(
Message
msg);
}
Then I created the ChannelFactory using the EndpointAddress and the Binding created above as below:
cf =
new
ChannelFactory
<
genericContract
>(binding, epa);
One final note is that I used the Message version property to control which message version my WCF is using when I am creating the request message as below:
request =
Message
.CreateMessage(MsgVersion, action, r);
The remaining code is standard with no changes. Then I started to call my service as below:
var
testCase =
new
TestCase
();
var
wcftststep =
new
WcfGenericRequestResponseStep
();
wcftststep.ServiceUrl =
"http://localhost:16987/Service1.svc"
;
wcftststep.Action =
"http://tempuri.org/IService1/GetData"
;
wcftststep.BindingConfigurationName =
"WSHttpBinding_IService1"
;
wcftststep.BindingTypeName =
typeof
(System.ServiceModel.
WSHttpBinding
).AssemblyQualifiedName;
wcftststep.FailOnError =
true
;
wcftststep.RunConcurrently =
false
;
wcftststep.MsgVersion = System.ServiceModel.Channels.
MessageVersion
.Soap12WSAddressing10;
wcftststep.RequestBody =
new
FileDataLoader
()
{
FilePath =
@"SampleInput.xml"
};
var
xmlvalstep =
new
XmlValidationStep
();
xmlvalstep.XmlSchemas.Add(
new
SchemaDefinition
()
{
XmlSchemaPath =
@"OutputSchema.xsd"
,
XmlSchemaNameSpace =
@"http://tempuri.org/"
});
xmlvalstep.XPathValidations.Add(
new
BizUnit.TestSteps.Common.
XPathDefinition
()
{
XPath =
"/*[local-name()='GetDataResponse' and namespace-uri()='http://tempuri.org/']/*[local-name()='GetDataResult' and namespace-uri()='http://tempuri.org/']"
,
Value =
"You entered: 0"
});
wcftststep.SubSteps.Add(xmlvalstep);
testCase.ExecutionSteps.Add(wcftststep);
var
bu =
new
BizUnit.
BizUnit
(testCase);
bu.RunTest();
The complete code for the WcfGenericRequestResponseStep is listed below:
using
BizUnit;
using
BizUnit.TestSteps.Common;
using
BizUnit.TestSteps.Soap;
using
BizUnit.Xaml;
using
System;
using
System.Collections.Generic;
using
System.Collections.ObjectModel;
using
System.IO;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Channels;
using
System.Text;
using
System.Threading.Tasks;
using
System.Xml;
namespace
BizUnitTester
{
public
class
WcfGenericRequestResponseStep
:
TestStepBase
{
private
Stream
_request;
private
Stream
_response;
private
Collection
<
SoapHeader
> _soapHeaders =
new
Collection
<
SoapHeader
>();
public
DataLoaderBase
RequestBody {
get
;
set
; }
public
string
ServiceUrl {
get
;
set
; }
public
string
Action {
get
;
set
; }
public
string
Username {
get
;
set
; }
public
string
Password {
get
;
set
; }
public
string
BindingTypeName {
get
;
set
; }
public
MessageVersion
MsgVersion {
get
;
set
; }
public
string
BindingConfigurationName {
get
;
set
; }
public
WcfGenericRequestResponseStep()
{
SubSteps =
new
Collection
<
SubStepBase
>();
}
public
Collection
<
SoapHeader
> SoapHeaders
{
set
{
_soapHeaders =
value
;
}
get
{
return
_soapHeaders;
}
}
public
override
void
Execute(
Context
context)
{
_request = RequestBody.Load(context);
context.LogXmlData(
"Request"
, _request,
true
);
_response = CallWebMethod(
_request,
ServiceUrl,
Action,
Username,
Password,
context);
Stream
responseForPostProcessing = _response;
foreach
(
var
subStep
in
SubSteps)
{
responseForPostProcessing = subStep.Execute(responseForPostProcessing, context);
}
}
public
override
void
Validate(
Context
context)
{
if
(
string
.IsNullOrEmpty(ServiceUrl))
{
throw
new
StepValidationException
(
"ServiceUrl may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(Action))
{
throw
new
StepValidationException
(
"Action may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(BindingTypeName))
{
throw
new
StepValidationException
(
"Binding type name may not be null or empty"
,
this
);
}
if
(
string
.IsNullOrEmpty(BindingConfigurationName))
{
throw
new
StepValidationException
(
"Binding configuration name may not be null or empty"
,
this
);
}
RequestBody.Validate(context);
}
private
Stream
CallWebMethod(
Stream
requestData,
string
serviceUrl,
string
action,
string
username,
string
password,
Context
ctx )
{
try
{
Stream
responseData;
Type
bindingType =
Type
.GetType(BindingTypeName);
Binding
binding = (
Binding
)
Activator
.CreateInstance(bindingType, BindingConfigurationName);
var
epa =
new
EndpointAddress
(
new
Uri
(serviceUrl));
ChannelFactory
<
genericContract
> cf =
null
;
genericContract
channel;
Message
request;
Message
response;
string
responseString;
try
{
cf =
new
ChannelFactory
<
genericContract
>(binding, epa);
if
(!
string
.IsNullOrWhiteSpace(username) && !
string
.IsNullOrWhiteSpace(password))
{
cf.Credentials.UserName.UserName = username;
cf.Credentials.UserName.Password = password;
}
cf.Open();
channel = cf.CreateChannel();
using
(
new
OperationContextScope
((
IContextChannel
)channel))
{
XmlReader
r =
new
XmlTextReader
(requestData);
request =
Message
.CreateMessage(MsgVersion, action, r);
foreach
(
var
header
in
_soapHeaders)
{
MessageHeader
messageHeader =
MessageHeader
.CreateHeader(header.HeaderName, header.HeaderNameSpace, header.HeaderInstance);
OperationContext
.Current.OutgoingMessageHeaders.Add(messageHeader);
}
response = channel.Invoke(request);
string
responseStr = response.GetReaderAtBodyContents().ReadOuterXml();
ctx.LogXmlData(
"Response"
, responseStr);
responseData =
StreamHelper
.LoadMemoryStream(responseStr);
}
request.Close();
response.Close();
cf.Close();
}
catch
(
CommunicationException
ce)
{
ctx.LogException(ce);
if
(cf !=
null
)
{
cf.Abort();
}
throw
;
}
catch
(
TimeoutException
te)
{
ctx.LogException(te);
if
(cf !=
null
)
{
cf.Abort();
}
throw
;
}
catch
(
Exception
e)
{
ctx.LogException(e);
if
(cf !=
null
)
{
cf.Abort();
}
throw
;
}
return
responseData;
}
catch
(
Exception
ex)
{
ctx.LogException(ex);
throw
;
}
}
///
<summary>
///
A dummy WCF interface that will be manipulated by the CallWebMethod above
///
</summary>
[
ServiceContract
]
interface
genericContract
{
[
OperationContract
(Action =
"*"
, ReplyAction =
"*"
)]
Message
Invoke(
Message
msg);
}
}
}
0 Comments
Comments
Your comment has been posted.
Close
Thank you, your comment requires moderation so it may take a while to appear.
Close
Leave a Comment
Name
Comment
Post