Fix System.UnsupportedException using WCF on Windows Phone 7

Could anyone communicate using WCF on a Windows Phone Series 7 emulator?

I have been trying for the past two days, and it just happens to me. I can get a regular Silverlight control to work in both Silverlight 3 and Silverlight 4, but not in the phone version. Here are two versions I tried:

Version 1 - Using Async Pattern

BasicHttpBinding basicHttpBinding = new BasicHttpBinding(); EndpointAddress endpointAddress = new EndpointAddress("http://localhost/wcf/Authentication.svc"); Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress); AsyncCallback callback = (result) => { Action<string> write = (str) => { this.Dispatcher.BeginInvoke(delegate { //Display something }); }; try { Wcf.IAuthentication auth = result.AsyncState as Wcf.IAuthentication; Wcf.AuthenticationResponse response = auth.EndLogin(result); write(response.Success.ToString()); } catch (Exception ex) { write(ex.Message); System.Diagnostics.Debug.WriteLine(ex.Message); } }; auth1.BeginLogin("user0", "test0", callback, auth1); 

This version is broken into this line:

 Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress); 

Throw System.NotSupportedException . The exception is not very descriptive, and the stop table is also not very useful:

 
     at System.ServiceModel.DiagnosticUtility.ExceptionUtility.BuildMessage (Exception x) 
     at System.ServiceModel.DiagnosticUtility.ExceptionUtility.LogException (Exception x) 
     at System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError (Exception e) 
     at System.ServiceModel.ChannelFactory`1.CreateChannel (EndpointAddress address) 
     at WindowsPhoneApplication2.MainPage.DoLogin () 
     .... 
 

Version 2 - WCF Call Block

Here is a version that does not use the async template.

 [System.ServiceModel.ServiceContract] public interface IAuthentication { [System.ServiceModel.OperationContract] AuthenticationResponse Login(string user, string password); } public class WcfClientBase<TChannel> : System.ServiceModel.ClientBase<TChannel> where TChannel : class { public WcfClientBase(string name, bool streaming) : base(GetBinding(streaming), GetEndpoint(name)) { ClientCredentials.UserName.UserName = WcfConfig.UserName; ClientCredentials.UserName.Password = WcfConfig.Password; } public WcfClientBase(string name) : this(name, false) {} private static System.ServiceModel.Channels.Binding GetBinding(bool streaming) { System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding(); binding.MaxReceivedMessageSize = 1073741824; if(streaming) { //binding.TransferMode = System.ServiceModel.TransferMode.Streamed; } /*if(XXXURLXXX.StartsWith("https")) { binding.Security.Mode = BasicHttpSecurityMode.Transport; binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; }*/ return binding; } private static System.ServiceModel.EndpointAddress GetEndpoint(string name) { return new System.ServiceModel.EndpointAddress(WcfConfig.Endpoint + name + ".svc"); } protected override TChannel CreateChannel() { throw new System.NotImplementedException(); } } auth.Login("test0", "password0"); 

This version crashes in the System.ServiceModel.ClientBase<TChannel> constructor. The call stack is slightly different:

 
     at System.Reflection.MethodInfo.get_ReturnParameter () 
     at System.ServiceModel.Description.ServiceReflector.HasNoDisposableParameters (MethodInfo methodInfo) 
     at System.ServiceModel.Description.TypeLoader.CreateOperationDescription (ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, ContractReflectionInfo reflectionInfo, ContractDescription declaringContract) 
     at System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions (ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction) 
     at System.ServiceModel.Description.TypeLoader.CreateContractDescription (ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo & reflectionInfo, Object serviceImplementation) 
     at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper (Type contractType, Type serviceType, Object serviceImplementation) 
     at System.ServiceModel.Description.TypeLoader.LoadContractDescription (Type contractType) 
     at System.ServiceModel.ChannelFactory 1.CreateDescription() at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address) at System.ServiceModel.ChannelFactory 1.CreateDescription() at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address) at System.ServiceModel.ChannelFactory  1.CreateDescription() at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address) at System.ServiceModel.ChannelFactory 1..ctor (Binding binding, EndpointAddress remoteAddress) 
     at System.ServiceModel.ClientBase 1..ctor(Binding binding, EndpointAddress remoteAddress) at Wcf.WcfClientBase 1..ctor(Binding binding, EndpointAddress remoteAddress) at Wcf.WcfClientBase  1..ctor(Binding binding, EndpointAddress remoteAddress) at Wcf.WcfClientBase 1..ctor (String name, Boolean streaming) 
     at Wcf.WcfClientBase`1..ctor (String name) 
     at Wcf.AuthenticationClient..ctor () 
     at WindowsPhoneApplication2.MainPage.DoLogin () 
     ... 
 
sub>

Any ideas?

+4
source share
4 answers

As Scottmarlow pointed out, an automated service message just works. I set myself the task of figuring out why the hell did he work, and the manual version doesn’t.

I found the culprit and he is ChannelFactory . For some reason, new ChannelFactory<T>().CreateChannel() just throws an exception. The only solution I found was to provide my own channel implementation. It includes:

  • Redefine the customer base. (Optional).
  • Override ClientBase.CreateChannel. (Optional).
  • ChannelBase subclass with specific implementation of your WCF interface

ClientBase now provides an instance of the factory thru ChannelFactory channel ChannelFactory . If you just call CreateChannel off, you will get the same exception. You need to create an instance of the channel, which you define in step 3, within the CreateChannel .

This is the basic framework for how everything looks together.

 [DataContractAttribute] public partial class AuthenticationResponse { [DataMemberAttribute] public bool Success { get; set; } [System.ServiceModel.ServiceContract] public interface IAuthentication { [System.ServiceModel.OperationContract(AsyncPattern = true)] IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object state); AuthenticationResponse EndLogin(IAsyncResult result); } public class AuthenticationClient : ClientBase<IAuthentication>, IAuthentication { public AuthenticationClient(System.ServiceModel.Channels.Binding b, EndpointAddress ea):base(b,ea) { } public IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object asyncState) { return base.Channel.BeginLogin(user, password, callback, asyncState); } public AuthenticationResponse EndLogin(IAsyncResult result) { return Channel.EndLogin(result: result); } protected override IAuthentication CreateChannel() { return new AuthenticationChannel(this); } private class AuthenticationChannel : ChannelBase<IAuthentication>, IAuthentication { public AuthenticationChannel(System.ServiceModel.ClientBase<IAuthentication> client) : base(client) { } public System.IAsyncResult BeginLogin(string user, string password, System.AsyncCallback callback, object asyncState) { object[] _args = new object[2]; _args[0] = user; _args[1] = password; System.IAsyncResult _result = base.BeginInvoke("Login", _args, callback, asyncState); return _result; } public AuthenticationResponse EndLogin(System.IAsyncResult result) { object[] _args = new object[0]; AuthenticationResponse _result = ((AuthenticationResponse)(base.EndInvoke("Login", _args, result))); return _result; } } } 

TL; DR; If you want to use your own WCF code for WP7, you need to create your own channel class and not rely on ChannelFactory .

+7
source

Creating a dynamic proxy using ChannelFactory.CreateChannel () is not supported on Windows Phone. This is described here - http://msdn.microsoft.com/en-us/library/ff426930(VS.96).aspx

Using the Add Service Link service in an async template would be the correct way.

+1
source

I did not have any problems, but I went to the link "add a link to the service ...", which I had to do through the "VS2010 Express for Windows Phone". b / c VS2010 RC does not yet support this feature for WP7. The Express version comes with a WP7 Developer installation.

0
source

Source: https://habr.com/ru/post/1304537/


All Articles