WCF - How to hold on to the Channel/Proxy between Begin and End call
I'm attempting to use the ChannelFactory to call an asynchronous service.
The bit I'm unsure of is how to best hold on to the reference to the channel - between the call to BeginSave and then EndSave (which is in the callback method).
I'm currently doing this by assigning it to an instance variable, but this doesn't seem ideal. I only want the channel to exist for the lifetime of the call (which I think is best practice i.e. Open, use it, close it). I also want to make sure I'm closing the correct channel, there could be situations where there's more than one in existence.
Any examples on how best to do this would be great.
Here's my code:
public partial class MyForm : Form
{
ICompanyService m_Channel;
public MyForm()
{
InitializeComponent();
// ChannelProvider is a class I've created which returns a channel created by the ChannelFactory
ChannelProvider<ICompanyService> channelProvider = new ChannelProvider<ICompanyService>();
m_Channel = channelProvider.GetChannel();
}
private void OnSaveButtonClickAsync(object sender, EventArgs e)
{
Company company = new Company();
company.BranchId = "A1";
company.CompanyName = "A1 LTD";
开发者_开发百科m_Channel.BeginSave(
company,
new AsyncCallback(OnSaveCallback),
null);
StatusLabel.Text = "Saving...";
}
private void OnSaveCallback(IAsyncResult ar)
{
int result = m_Channel.EndSave(ar);
Invoke(
new MethodInvoker(delegate()
{
StatusLabel.Text = result.ToString();
}));
}
}
Many thanks.
sorry about the delay in getting back to you on this. One of the problems I think you have is that you are not instantiating your proxy correctly. Not sure what you channelprovider does but creating you own channel is pretty straight forward and might not need a wrapper.
I tried a simple test using the old calculator service sample and found I had no difficulties with keeping the channel open.
First I created two fields...
private ChannelFactory<ICalculator> m_Factory;
private ICalculator m_Proxy;
Then instantiated the factory in the constructor using the client config in the config file.
m_Factory = new ChannelFactory<ICalculator>("calc");
Then when invoking the service I create my proxy and execute the async method. Once the call is returned I convert the proxy into a ICommunicationObject which gives me the state of my channel. You should see that the proxy you invoked is still open. You should then be able to close it.
void OnBegin(object sender, EventArgs e)
{
m_Proxy = m_Factory.CreateChannel();
m_Proxy.BeginAdd(2, 3, OnCompletion, null);
// Do other stuff...
}
void OnCompletion(IAsyncResult result)
{
int sum = m_Proxy.EndAdd(result);
result.AsyncWaitHandle.Close();
ICommunicationObject channel = (ICommunicationObject)m_Proxy;
if (channel.State == CommunicationState.Opened)
channel.Close();
}
Hope this helps.
I found the answer to this in Juval Lowy's WCF book. Using my original example, this can be rewritten as follows:
public partial class MyForm : Form {
public MyForm()
{
InitializeComponent();
}
private void OnSaveButtonClickAsync(object sender, EventArgs e)
{
Company company = new Company();
company.BranchId = "A1";
company.CompanyName = "A1 LTD";
// ChannelProvider is a class I've created which returns a channel created by the ChannelFactory
ChannelProvider<ICompanyService> channelProvider = new ChannelProvider<ICompanyService>();
channel = channelProvider.GetChannel();
channel.BeginSave(
company,
new AsyncCallback(OnSaveCallback),
channel);
StatusLabel.Text = "Saving...";
}
private void OnSaveCallback(IAsyncResult ar)
{
int result = m_Channel.EndSave(ar);
IContextChannel contextChannel = (IContextChannel)ar.AsyncState;
contextChannel.Close();
Invoke(
new MethodInvoker(delegate()
{
StatusLabel.Text = result.ToString();
}));
}
}
精彩评论