Escolar Documentos
Profissional Documentos
Cultura Documentos
Disclaimer
This document is for informational purposes only and is subject to change without notice. This document and its
contents, including the viewpoints, dates and functional content expressed herein are believed to be accurate as of its
date of publication. However, Epicor Software Corporation makes no guarantee, representations or warranties with
regard to the enclosed information and specifically disclaims any applicable implied warranties, such as fitness for a
particular purpose, merchantability, satisfactory quality or reasonable skill and care. As each user of Epicor software is
likely to be unique in their requirements in the use of such software and their business processes, users of this document
are always advised to discuss the content of this document with their Epicor account manager. All information contained
herein is subject to change without notice and changes to this document since printing and other important information
about the software product are made or published in release notes, and you are urged to obtain the current release
notes for the software product. We welcome user comments and reserve the right to revise this publication and/or
make improvements or changes to the products or programs described in this publication at any time, without notice.
The usage of any Epicor software shall be pursuant to an Epicor end user license agreement and the performance of
any consulting services by Epicor personnel shall be pursuant to Epicor's standard services terms and conditions. Usage
of the solution(s) described in this document with other Epicor software or third party products may require the purchase
of licenses for such other products. Where any software is expressed to be compliant with local laws or requirements
in this document, such compliance is not a warranty and is based solely on Epicor's current understanding of such laws
and requirements. All laws and requirements are subject to varying interpretations as well as to change and accordingly
Epicor cannot guarantee that the software will be compliant and up to date with such changes. All statements of
platform and product compatibility in this document shall be considered individually in relation to the products referred
to in the relevant statement, i.e., where any Epicor software is stated to be compatible with one product and also
stated to be compatible with another product, it should not be interpreted that such Epicor software is compatible
with both of the products running at the same time on the same platform or environment. Additionally platform or
product compatibility may require the application of Epicor or third-party updates, patches and/or service packs and
Epicor has no responsibility for compatibility issues which may be caused by updates, patches and/or service packs
released by third parties after the date of publication of this document. Epicor is a registered trademark and/or
trademark of Epicor Software Corporation in the United States, certain other countries and/or the EU. All other
trademarks mentioned are the property of their respective owners. Copyright Epicor Software Corporation 2014.
All rights reserved. No part of this publication may be reproduced in any form without the prior written consent of
Epicor Software Corporation.
10.0.700
Revision: July 03, 2014 12:16 p.m.
Total pages: 28
sys.ditaval
Contents
Contents
Introduction............................................................................................................................4
Audience.........................................................................................................................................................4
Prerequisites....................................................................................................................................................4
Conventions....................................................................................................................................................4
Overview.................................................................................................................................5
When to Use HTTP Transport...........................................................................................................................5
When to Use the TCP Transport.......................................................................................................................5
HTTP Transport.......................................................................................................................6
WCF Services Example.....................................................................................................................................6
Create the Visual Studio Project................................................................................................................6
Add the Web Service References...............................................................................................................7
Add Helper Classes...................................................................................................................................8
Add Functionality to the Program Class...................................................................................................11
Code the Main Method..........................................................................................................................14
Setting Up SSL......................................................................................................................20
Create Site Binding........................................................................................................................................20
Connect the Application Server......................................................................................................................24
Introduction
Introduction
Welcome to the Epicor WCF-Services Developer Guide. This document describes how to consume the Epicor
WCF-Services, how to configure the web services for different scenarios, and other information developers may
find useful when working with Epicor Web Services.
This guide is written for the .NET 4 platform.
Audience
This guide is intended for developers responsible for integrating with Epicor ERP using web services. By leveraging
web services, developers can make Epicor data available for use in third party applications, custom storefront
applications, and other purposes. These web services also can move Epicor data into Java or other programming
environments.
Prerequisites
This document assumes you have a working knowledge of C#, Visual Studio 2012, .NET 4.0, and Internet
Information Services (IIS). You should also understand the basic concepts behind web services and WCF.
This guide assumes you have already installed your Epicor application server, so application server installation
instructions are not included in this document. This document also assumes you have a configured Epicor client
application on your local development machine. You will need access to the client assemblies to complete some
coding projects.
Conventions
This guide uses the following conventions.
When this document refers to Internet Information Services (IIS), it refers to the server where you installed
the Epicor application server.
Code samples appear in the follow font style:
static void Main(string[] args)
{
string myString = "Test";
Overview
Overview
The Epicor WCF services support two transport mechanisms: net.tcp and http/ https.
Each of these mechanism requires you follow a different approach when you use them. You also need to properly
configure the application servers Web.Config file.
HTTP Transport
HTTP Transport
In WCF, you specify how to transfer data across a network between endpoints through a binding, and each
binding is made up of a sequence of binding elements.
For HTTP Transport, this document explores BasicHttpBinding and WSHttpBinding.
BasicHttpBinding - Used when you communicate with ASMX-based web services, web clients, and other
services that conform to the WS-I Basic Profile 1.1 (Web Services Interoperability Organization, 2004).
WSHttpBinding - Supports the SOAP 1.2 and WS-Addressing specifications.
By default BasicHttpBinding sends data in plain text, while WSHttpBinding sends it in an encrypted and secured
manner.
HTTP Transport
5. Click OK.
The reference is added to your project.
6. Repeat steps 1-5 again. This time add a reference to the AbcCode service. The address for this service is
like http://localhost/ERP100500/Erp/BO/AbcCode.svc, and you use a namespace value of
Epicor.AbcCodeSvc.
HTTP Transport
HTTP Transport
OnWriteHeaderContents method is called when the header contents are serialized. You write the
contents of the header through this code block:
protected override void OnWriteHeaderContents(System.Xml.XmlDictionaryWri
ter writer, MessageVersion messageVersion)
{
writer.WriteElementString("SessionID", @"http://schemas.datacontract
.org/2004/07/Epicor.Hosting", SessionId.ToString());
writer.WriteElementString("UserID", @"http://schemas.datacontract.or
g/2004/07/Epicor.Hosting", EpicorUserId);
}
public override string Name
{
get { return "SessionInfo"; }
}
public override string Namespace
{
get { return "urn:epic:headers:SessionInfo"; }
}
c. To complete this class, add two properties that store the users Epicor session Id and Epicor user Id:
public Guid SessionId { get; set; }
public string EpicorUserId { get; set; }
HTTP Transport
_sessionId = SessionId;
_epicorUserId = EpicorUserId;
}
Tip You may notice that Visual Studio displays errors that refer to code in the ApplyClientBehavior
method. You can ignore these messages, as they will stop once you implement the
CustomMessageInspector class.
d. Provide implementations for the four methods defined by the interface.
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParamet
erCollection bindingParameters){ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime c
lientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new CustomMessageInspector
(_sessionId, _epicorUserId));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, Endpoi
ntDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
10. Now implement the CustomMessageInspector class. This class adds the SessionInfo header to the
outgoing request headers.
a. Specify the CustomMessageInspector class implements the IClientMessageInspector interface. This
interface defines a message inspector object that can be added to the MessageInspectors collection
to view or modify messages.
class CustomMessageInspector : IClientMessageInspector
b. Add two private class level variables that hold the Epicor session Id and user Id.
class CustomMessageInspector : IClientMessageInspector
{
private Guid _sessionID;
private string _epicorUserId;
c. Add a constructor method for the class that uses for parameters a Guid and a string. Assign their values
to the two class level variables you added.
public CustomMessageInspector(Guid SessionId, string EpicorUserId)
{
_sessionID = SessionId;
_epicorUserId = EpicorUserId;
}
d. Enter the two methods required for the IClientMessageInspector interface. In this example, only add
code to the BeforeSendRequest method, as this method is where you place the SessionInfo header
information.
public void AfterReceiveReply(ref Message reply, object correlationState)
{ }
public object BeforeSendRequest(ref Message request, System.ServiceModel.
IClientChannel channel)
{
10
HTTP Transport
At this point your helper classes are complete, but the project does not actually function. However you can run
a test build of the project to make sure you dont have build errors. If you do, review these steps again to correct
these errors.
System.Net;
System.Reflection;
System.ServiceModel;
System.ServiceModel.Channels;
AbcCodeServiceClient.Epicor.AbcCodeSvc;
AbcCodeServiceClient.Epicor.SessionModSvc;
b. Now enter the GetWsHttpBinding method. This method can be added immediately after the Main
method.
private static WSHttpBinding GetWsHttpBinding()
{
var binding = new WSHttpBinding();
const int maxBindingSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = maxBindingSize;
binding.ReaderQuotas.MaxDepth = maxBindingSize;
binding.ReaderQuotas.MaxStringContentLength = maxBindingSize;
binding.ReaderQuotas.MaxArrayLength = maxBindingSize;
binding.ReaderQuotas.MaxBytesPerRead = maxBindingSize;
binding.ReaderQuotas.MaxNameTableCharCount = maxBindingSize;
11
HTTP Transport
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialTyp
e.UserName;
return binding;
}
c. Name the second method GetBasicHttpBinding; this method creates a new, properly configured
instance of the BasicHttpBinding class.
Notice this method is similar to the first method. Unfortunately these two bindings inherit from different
classes and the ReaderQuotas property is defined on each base class instead of common base class
from which they both inherit. Add the following method directly below the GetWsHttpBinding method.
public static BasicHttpBinding GetBasicHttpBinding()
{
var binding = new BasicHttpBinding();
const int maxBindingSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = maxBindingSize;
binding.ReaderQuotas.MaxDepth = maxBindingSize;
binding.ReaderQuotas.MaxStringContentLength = maxBindingSize;
binding.ReaderQuotas.MaxArrayLength = maxBindingSize;
binding.ReaderQuotas.MaxBytesPerRead = maxBindingSize;
binding.ReaderQuotas.MaxNameTableCharCount = maxBindingSize;
binding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCr
edential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCred
entialType.UserName;
return binding;
}
Notice this code first creates a new instance of the binding. It then sets the maximum values for the
message size and reader quotas. The reader quotas element defines the constraints on the complexity
of the SOAP messages processed by endpoints configured through this binding. With the Epicor
application, you can retrieve large record sets.
The code next specifies the security mode the binding will use:
For the BasicHttpBinding, set it to TransportwithMessageCredential. This mode indicates you
use https and that the service is configured with a certificate. SOAP message security provides the
client authentication.
For the WSHttpBinding, set the security mode to Message as the WSHttpBinding encrypts its
messages by default.
For both bindings, set the client credential type to UserName to indicate you want to include a UserName
token in the header.
3. Now add the last helper method GetClient. This method creates an instance of the client classes. Add
the following method directly after the GetBasicHttpBinding method.
private static TClient GetClient<TClient, TInterface>(
string url,
string username,
string password,
EndpointBindingType bindingType)
where TClient : ClientBase<TInterface>
where TInterface : class
{
12
HTTP Transport
13
HTTP Transport
You can resolve this error in two ways. One way is to change the service URL so it uses the fully qualified machine
name. You can also specify a DnsEndpointIdenity object to the EndpointAddress you created. To do this,
replace the line:
var endpointAddress = new EndpointAddress(url);
With this line:
DnsEndpointIdentity endpointIdentity = new DnsEndpointIdentity("L303415.america
s.epicor.net");
var endpointAddress = new EndpointAddress(new Uri(url), endpointIdentity);
You will also need to add a reference to the System.IdentityModel assembly.
14
HTTP Transport
5. Now add instances of the two service client classes created by Visual Studio; these classes were created
when you added the service references in Step 2. Before creating each instance, set the Path property of
the UriBuilder to the path of the service.
In this example code, the Epicor 10 appserver name is ERP100500; replace this value with your appserver
name.
builder.Path = "ERP100500/Ice/Lib/SessionMod.svc";
SessionModSvcContractClient sessionModClient = GetClient<SessionModSvcContr
actClient, SessionModSvcContract>(
builder.Uri.ToString(),
epicorUserID,
epiorUserPassword,
bindingType);
builder.Path = "ERP100500/Erp/BO/AbcCode.svc";
ABCCodeSvcContractClient abcCodeClient = GetClient<ABCCodeSvcContractClient
, ABCCodeSvcContract>(
builder.Uri.ToString(),
epiorUserPassword,
epicorUserID,
bindingType);
6. Now use the services. First call the SessionModSvc Login method to establish a session in the appserver.
This returns a Guid that identifies the session. Then create an instance of the HookServiceBehavior class
for each client instance, passing it to the Guid you receive. This adds the SessionInfo header to each
subsequent call.
Guid sessionId = Guid.Empty;
sessionId = sessionModClient.Login();
sessionModClient.Endpoint.EndpointBehaviors.Add(new HookServiceBehavior(ses
sionId, epicorUserID));
abcCodeClient.Endpoint.EndpointBehaviors.Add(new HookServiceBehavior(sessio
nId, epicorUserID));
7. Make calls to the AbcCodeSvc service. First create an instance of an empty ABCCodeTableset to pass into
the service. Then call the GetNewABCCode method to create a new ABCCode record.
This call returns a new row in the tableset with default values, but it does not save the row to the database.
When you call a GetNew methods on the Epicor services, the row should return with the RowMod field
set to A. The code uses this to select a new row from the ABCCode table in the tableset.
var ts = new ABCCodeTableset();
abcCodeClient.GetNewABCCode(ref ts);
var newRow = ts.ABCCode.Where(n => n.RowMod.Equals("A", StringComparison.In
variantCultureIgnoreCase)).FirstOrDefault();
if (newRow != null)
{
}
8. You can now set the required fields and call the Update method on the service to save the record.
In this example, the code sets the ABCCode field for the new row to a G value. However for your code,
use a value that does not exist. This code goes between the curly braces after the if (newRow != null)
statement you added in the previous step.
newRow.ABCCode = "G";
newRow.CountFreq = 30;
newRow.StockValPcnt = 100;
15
HTTP Transport
abcCodeClient.Update(ref ts);
9. Since you saved the record, you next fetch it from the server. This example demonstrates your record was
saved by the previous code. Replace the G in the call to GetByID with the code you entered in the previous
step.
ts = null;
ts = abcCodeClient.GetByID("G");
if (ts != null && ts.ABCCode.Any())
{
}
10. Next update some values on the record and save it back to the server again. This code goes inside the curly
braces that appear after the if(ts != null && ts.ABCCode.Any()) code added in the previous step.
This code example demonstrates two important concepts:
First, server business logic often requires both the before and updated versions of the row be sent.
This requires you make a copy of the row and then add it to the table before making changes.
Second, when you update an existing record, set the RowMod field in the row to a U value. If you
do not do this, your changes are not saved. After saving the change, you null out the tableset and call
GetByID again to demonstrate the record was updated.
ABCCodeRow backupRow = new ABCCodeRow();
var fields = backupRow.GetType().GetProperties(BindingFlags.Instance | Bind
ingFlags.Public);
foreach(var field in fields)
{
if (field.PropertyType == typeof(System.Runtime.Serialization.Extensio
nDataObject))
{
continue;
}
var fieldValue = field.GetValue(ts.ABCCode[0]);
field.SetValue(backupRow, fieldValue);
}
ts.ABCCode.Add(backupRow);
ts.ABCCode[0].CountFreq = 45;
ts.ABCCode[0].RowMod = "U";
abcCodeClient.Update(ref ts);
ts = null;
ts = abcCodeClient.GetByID("G");
if (ts != null && ts.ABCCode.Any())
{
Console.WriteLine("CountFreq = {0}", ts.ABCCode[0].CountFreq);
}
11. To finish the AbcCodeSvc service, delete the record. Place the following code immediately after the call to
Console.WriteLine and inside the curly braces that surround it.
To delete a record, set the RowMod field to a D value and call the Update method. Again you try to call
the GetByID method to retrieve the record. This time no record should exist, so a record not found error
should get thrown by the application server.
The following code demonstrates wrapping the service call in a try/catch block. You should always code
defensively and have code that can handle exceptions that may occur when calling the application server.
Other possible values for the ExceptionKindValue are ServerException, BLException,
16
HTTP Transport
17
HTTP Transport
builder.Uri.ToString(),
epicorUserID,
epiorUserPassword,
bindingType);
builder.Path = "ERP100500/Erp/BO/AbcCode.svc";
ABCCodeSvcContractClient abcCodeClient = GetClient<ABCCodeSvcContractClien
t, ABCCodeSvcContract>(
builder.Uri.ToString(),
epicorUserID,
epiorUserPassword,
bindingType);
Guid sessionId = Guid.Empty;
sessionId = sessionModClient.Login();
sessionModClient.Endpoint.EndpointBehaviors.Add(new HookServiceBehavior(se
ssionId, epicorUserID));
abcCodeClient.Endpoint.EndpointBehaviors.Add(new HookServiceBehavior(sessi
onId, epicorUserID));
var ts = new ABCCodeTableset();
abcCodeClient.GetNewABCCode(ref ts);
var newRow = ts.ABCCode.Where(n => n.RowMod.Equals("A", StringComparison.I
nvariantCultureIgnoreCase)).FirstOrDefault();
if (newRow != null)
{
newRow.ABCCode = "G";
newRow.CountFreq = 30;
newRow.StockValPcnt = 100;
abcCodeClient.Update(ref ts);
ts = null;
ts = abcCodeClient.GetByID("G");
if (ts != null && ts.ABCCode.Any())
{
ABCCodeRow backupRow = new ABCCodeRow();
var fields = backupRow.GetType().GetProperties(BindingFlags.Inst
ance | BindingFlags.Public);
foreach(var field in fields)
{
if (field.PropertyType == typeof(System.Runtime.Serializati
on.ExtensionDataObject))
{
continue;
}
var fieldValue = field.GetValue(ts.ABCCode[0]);
field.SetValue(backupRow, fieldValue);
}
ts.ABCCode.Add(backupRow);
ts.ABCCode[0].CountFreq = 45;
ts.ABCCode[0].RowMod = "U";
abcCodeClient.Update(ref ts);
ts = null;
ts = abcCodeClient.GetByID("G");
if (ts != null && ts.ABCCode.Any())
{
Console.WriteLine("CountFreq = {0}", ts.ABCCode[0].CountFreq);
18
HTTP Transport
ts.ABCCode[0].RowMod = "D";
abcCodeClient.Update(ref ts);
try
{
ts = abcCodeClient.GetByID("G");
}
catch (FaultException<Epicor.AbcCodeSvc.EpicorFaultDetail> ex)
{
if (ex.Detail.ExceptionKindValue.Equals("RecordNotFound", S
tringComparison.InvariantCultureIgnoreCase))
{
Console.WriteLine("Record deleted.");
}
else
{
Console.WriteLine(ex.Message);
}
}
}
}
}
if (sessionId != Guid.Empty)
{
sessionModClient.Logout();
}
Console.ReadLine();
}
19
Setting Up SSL
Setting Up SSL
You have two options for setting up SSL in Internet Information Services (IIS):
Obtain an SSL certificate from a known certificate authority (CA) such as VeriSign or GeoTrust.
Create a self-signed certificate through the IIS Management console.
The following steps outline how to configure IIS to use a self-signed certificate.
3. Now from the Actions panel, click the "Create Self-Signed Certificate" option:
20
Setting Up SSL
4. In the Create Self-Signed Certificate dialog box, enter a name for the certificate such as Epicor-Dev.
5. Click OK.
The certificate is created.
6. In the Server Certificates panel, right-click your new certificate; from the context menu, select the View
option.
7. Now in the certificate dialog, select the Details tab.
8. Highlight the Subject property. Write down this value, as you will need it later.
21
Setting Up SSL
22
Setting Up SSL
b. Internet Explorer (IE) 7 and above will display an error page. Click the Continue to this website (not
recommended) link.
Tip This error occurs because the self-signed certificate was issued by your computer, not by a
trusted Certificate Authority (CA). Internet Explorer 7 and above will trust the certificate if you add
it to the list of Trusted Root Certification Authorities in the certificates store on the local
computer or in Group Policy for the domain.
23
Setting Up SSL
24
BasicHTTPBinding Explanation
Since BasicHttpBinding communicates in plain text, make sure it uses the SSL protocol.
You do this by specifying transport security; this ensures the communication is encrypted. You also need to
provide a username/password token to specify a security mode of TransportWithMessageCredential. By
25
setting the message client credential type to UserName, the client must authenticate the server using a
UserName credential.
The reader quotas element of the binding defines the constraints on the complexity of the SOAP messages
processed by the configured binding endpoints. Because you can retrieve large records through the Epicor
application, it is recommended you set these values to their maximum.
WSHTTPBinding Explanation
If you use WSHttpBinding, specify the message is encrypted by default. You can then use http to communicate
with the server.
Do this by indicating the security mode is "message", as security is provided using SOAP message security. By
default, the SOAP body is Encrypted and Signed. This requires that an SSL certification is specified in the
system.serviceModel/behaviors/serviceBehaviors/behavior/serviceCredentials element in your web.config file
(review the Setting Up SSL section for more information). You specify the client credential type is a username
and you also specify the same reader quotas as in the BasicHttpBinding.
26
Index
Index
B
basichttpbinding 25
C
conventions 4
ssl set up 20
ssl set up, connect application server 24
ssl set up, site binding 20
main method 14
main method, full code example 17
V
visual studio project, create 6
P
prerequisites 4
27