How to re-write WCF client to use ChannelFactory instead of service reference
I have a WCF service created using the web service software factory. All my incoming requests and returned responses are implemented as message contracts. I had been accessing the service by adding a service reference in VS which wor开发者_Python百科ked fine. However I've now been told that this isn't the standard company way and that I need to call the service using an in-house WCF proxy helper class based on the System.ServiceModel.ChannelFactory.
I've never used the ChannelFactory before and I'm struggling to figure out the best way to re-write the client access. The service contract is generated by the service factory and I need to provide the service interface to the proxy helper class. Here's part of the service contract - there's about 25 operations in total on the service:
namespace CAEWCFService.ServiceContracts
{
/// <summary>
/// Service Contract Class - CAEServiceContract
/// </summary>
[WCF::ServiceContract(Namespace = "urn:CAEServiceServiceContracts", Name = "CAEServiceContract", SessionMode = WCF::SessionMode.Allowed, ProtectionLevel = ProtectionLevel.None )]
public partial interface ICAEServiceContract
{
[WCF::OperationContract(IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = "GetAllIncomes", ProtectionLevel = ProtectionLevel.None)]
CAEService.MessageContracts.GetAllIncomesReponse GetIncomeRecords(CAEService.MessageContracts.GetAllIncomesRequest request);
[WCF::OperationContract(IsTerminating = false, IsInitiating = true, IsOneWay = false, AsyncPattern = false, Action = "urn:CAEServiceServiceContracts.CAEServiceContract.GetSecurityRecords", ProtectionLevel = ProtectionLevel.None)]
CAEService.MessageContracts.GetAllSecuritiesResponse GetSecurityRecords(CAEService.MessageContracts.GetAllSecuritiesRequest request);
//... the rest
}
}
And here's the call from the client side calling the GetIncomeRecords operation:
CAEServiceContractClient client = new CAEServiceContractClient();
IncomeSearchItem item = new IncomeSearchItem()
{
aCode = aCode.Text,
bCode = bCode.Text,
sCode = sCode.Text,
secDesc = tbSecurityName.Text,
status = statusValue != 0 ? statusValue : 0,
fromDate = fromDate,
toDate = toDate,
IncomeID = 0,
userBank = userBank,
userId = userId,
currentRate = currentSourceVal != 0 ? currentSourceVal : 0,
dateConfirmed = ddDate.SelectedValue,
pageIndex = pageIdx,
pageSize = recordsPerPage
};
GetAllIncomesReponse response = new GetAllIncomesReponse();
try
{
response = client.GetIncomeRecords(item);
totalRecords = response.TotalRecords;
incomelist.DataSource = response.IncomeItemColl;
incomelist.DataBind();
//.. the rest
}
Here's some sample code from another project showing how to use the proxy helper. The problem with my service is that it expects and returns message contracts whereas the sample one passes in primitive types and returns primitives or datasets:
public static class ServiceHelper
{
/// <summary>
/// Services the verification.
/// </summary>
/// <param name="user">The user.</param>
/// <returns></returns>
public static string ServiceVerification(string user)
{
return WCFProxyHelper<IFCAServices>.Use(client =>
client.ServiceVerification(user));
}
}
So what's the quickest / easiest way to do this? How do I make the ChannelFactory aware of my IncomeSearchItem and several other objects that I need to pass to the service? Can / should I use svcutil to generate all the objects and use that in the ChannelFactory?
Are you saying that the "Company Way" is to use the service helper, and that it internally creates a proxy based on ChannelFactory - or, do you want to create your own proxy class the long way. Would this work for you? An extension method on ServiceHelper would let you stay using the company way, but would not require the ServiceHelper to be changed to know about your request/response messages or anything they contain.
using CAEService;
using CAEService.MessageContracts;
public static class ServiceHelperExtensions
{
public static GetAllIncomesReponse GetIncomeRecords(this ServiceHelper, GetAllIncomesRequest request)
{
return WCFProxyHelper<ICAEServiceContract>.Use(client =>
client.GetAllIncomes(request));
}
}
Then in client code, you would replace this:
response = client.GetIncomeRecords(item);
with this:
response = ServiceHelper.GetIncomeRecords(item);
I think you will also have to use the SVCUTIL.exe command to generate a proxy class, and then edit the result stripping out the proxy and leaving only the request/response classes and their supporting types. Alternatively, if you have already done "Add Service Reference" in VS, you can click the "Show All Files" option in solution explorer and drill into the service reference. One of those files contains the generated service proxy and its supporting types, all in one file.
精彩评论